From e45fbfc61d33c470ebea12966aa13a4ee2ac344d Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Sun, 5 Jun 2016 09:09:07 -0400 Subject: [PATCH 001/413] Modified dwaftvet plugin to work with latest DFHack Initial commit of the dwarfvet plugin Signed-off-by: Michael Casadevall --- library/include/modules/Buildings.h | 2 + library/modules/Buildings.cpp | 14 + plugins/CMakeLists.txt | 1 + plugins/dwarfvet.cpp | 835 ++++++++++++++++++++++++++++ 4 files changed, 852 insertions(+) create mode 100644 plugins/dwarfvet.cpp diff --git a/library/include/modules/Buildings.h b/library/include/modules/Buildings.h index 1d939665f..de78acda6 100644 --- a/library/include/modules/Buildings.h +++ b/library/include/modules/Buildings.h @@ -292,6 +292,8 @@ DFHACK_EXPORT bool isActivityZone(df::building * building); DFHACK_EXPORT bool isPenPasture(df::building * building); DFHACK_EXPORT bool isPitPond(df::building * building); DFHACK_EXPORT bool isActive(df::building * building); +DFHACK_EXPORT bool isHospital(df::building * building); +DFHACK_EXPORT bool isAnimalTraining(df::building * building); DFHACK_EXPORT df::building* findPenPitAt(df::coord coord); } diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index a6589bac1..b1a22e2cc 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -1263,6 +1263,20 @@ bool Buildings::isActive(df::building * building) return ((df::building_civzonest*) building)->zone_flags.bits.active != 0; } +bool Buildings::isHospital(df::building * building) + { + if (!isActivityZone(building)) + return false; + return ((df::building_civzonest*) building)->zone_flags.bits.hospital != 0; + } + + bool Buildings::isAnimalTraining(df::building * building) + { + if (!isActivityZone(building)) + return false; + return ((df::building_civzonest*) building)->zone_flags.bits.animal_training != 0; + } + // returns building of pen/pit at cursor position (NULL if nothing found) df::building* Buildings::findPenPitAt(df::coord coord) { diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index cc0de019f..fbf33f459 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -93,6 +93,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(dig dig.cpp) DFHACK_PLUGIN(digFlood digFlood.cpp) add_subdirectory(diggingInvaders) + DFHACK_PLUGIN(dwarfvet dwarfvet.cpp) DFHACK_PLUGIN(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(embark-tools embark-tools.cpp) DFHACK_PLUGIN(eventful eventful.cpp LINK_LIBRARIES lua) diff --git a/plugins/dwarfvet.cpp b/plugins/dwarfvet.cpp new file mode 100644 index 000000000..44b3684e0 --- /dev/null +++ b/plugins/dwarfvet.cpp @@ -0,0 +1,835 @@ +/** + * Copyright (c) 2015, Michael Casadevall + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + **/ + +#include "Console.h" +#include "Core.h" +#include "DataDefs.h" +#include "Export.h" +#include "PluginManager.h" +#include "modules/EventManager.h" +#include "modules/Units.h" +#include "modules/Buildings.h" +#include "modules/Maps.h" +#include "modules/Job.h" + +#include "df/animal_training_level.h" +#include "df/building_type.h" +#include "df/caste_raw.h" +#include "df/caste_raw_flags.h" +#include "df/creature_raw.h" +#include "df/job.h" +#include "df/general_ref_unit_workerst.h" +#include "df/profession.h" +#include "df/ui.h" +#include "df/unit.h" +#include "df/unit_health_info.h" +#include "df/unit_health_flags.h" +#include "df/world.h" + +#include +#include + +using namespace DFHack; +using namespace DFHack::Units; +using namespace DFHack::Buildings; + +using namespace std; + +DFHACK_PLUGIN("dwarfvet"); +DFHACK_PLUGIN_IS_ENABLED(dwarfvet_enabled); + +REQUIRE_GLOBAL(ui); +REQUIRE_GLOBAL(world); + +static vector tracked_units; +static int32_t howOften = 100; + +struct hospital_spot { + int32_t x; + int32_t y; + int32_t z; +}; + +class Patient { + public: + // Constructor/Deconstrctor + Patient(int32_t id, int spot_index, int32_t x, int32_t y, int32_t z); + int32_t getID() { return this->id; }; + int32_t getSpotIndex() { return this->spot_index; }; + int32_t returnX() { return this->spot_in_hospital.x; }; + int32_t returnY() { return this->spot_in_hospital.y; }; + int32_t returnZ() { return this->spot_in_hospital.z; }; + + private: + struct hospital_spot spot_in_hospital; + int id; + int spot_index; +}; + +Patient::Patient(int32_t id, int32_t spot_index, int32_t x, int32_t y, int32_t z){ + this->id = id; + this->spot_in_hospital.x = x; + this->spot_in_hospital.y = y; + this->spot_in_hospital.z = z; +} + +class AnimalHospital { + + public: + // Constructor + AnimalHospital(df::building *, color_ostream &out); + ~AnimalHospital(); + int32_t getID() { return id; } + bool acceptPatient(int32_t id, color_ostream&); + void processPatients(color_ostream &out); + void dischargePatient(Patient * patient, color_ostream &out); + void calculateHospital(bool force, color_ostream &out); + void reportUsage(color_ostream &out); + + // GC + bool to_be_deleted; + + private: + int spots_open; + int32_t id; + int32_t x1; + int32_t x2; + int32_t y1; + int32_t y2; + int32_t z; + int height; + int length; + + // Doing an actual array in C++ is *annoying*, bloody copy constructors */ + vector spots_in_use; + vector building_in_hospital_notification; /* If present, we already notified about this */ + vector accepted_patients; +}; + +AnimalHospital::AnimalHospital(df::building * building, color_ostream &out) { + // Copy in what we need to know + id = building->id; + x1 = building->x1; + x2 = building->x2; + y1 = building->y1; + y2 = building->y2; + z = building->z; + + // Determine how many spots we have for animals + this->length = x2-x1; + this->height = y2-y1; + + // And calculate the hospital! + this->calculateHospital(true, out); +} + +AnimalHospital::~AnimalHospital() { + // Go through and delete all the patients + for (vector::iterator accepted_patient = this->accepted_patients.begin(); accepted_patient != this->accepted_patients.end(); accepted_patient++) { + delete (*accepted_patient); + } +} + +bool AnimalHospital::acceptPatient(int32_t id, color_ostream &out) { + // This function determines if we can accept a patient, and if we will. + this->calculateHospital(true, out); + + // First, do we have room? + if (!spots_open) return false; + + // Yup, let's find the next open spot, + // and give it to our patient + int spot_cur = 0; // fuck the STL for requiring a second counter to make this usable + for (vector::iterator spot = this->spots_in_use.begin(); spot != this->spots_in_use.end(); spot++) { + if (*spot == false) { + *spot = true; + break; + } + spot_cur++; + } + + spots_open--; + + // Convert the spot into x/y/z cords. + int offset_y = spot_cur/length; + int offset_x = spot_cur%length; + + // Create the patient! + Patient * patient = new Patient(id, + spot_cur, + this->x1+offset_x, + this->y1+offset_y, + this->z + ); + + accepted_patients.push_back(patient); + return true; +} + +// Before any use of the hospital, we need to make calculate open spots +// and such. This can change (i.e. stuff built in hospital) and +// such so it should be called on each function. +void AnimalHospital::reportUsage(color_ostream &out) { + // Debugging tool to see parts of the hospital in use + int length_cursor = this->length; + + for (vector::iterator spot = this->spots_in_use.begin(); spot != this->spots_in_use.end(); spot++) { + if (*spot) out.print("t"); + if (!(*spot)) out.print("f"); + length_cursor--; + if (length_cursor < 0) { + out.print("\n"); + length_cursor = this->length; + } + } + out.print("\n"); + +} + +void AnimalHospital::calculateHospital(bool force, color_ostream &out) { + // Only calculate out the hospital if we actually have a patient in it + // (acceptPatient will forcibly rerun this to make sure everything OK + + // Should reduce FPS impact of each calculation tick when the hospitals + // are not in use + //if (!force || (spots_open == length*height)) { + // Hospital is idle, don't recalculate + // return; + //} + + // Calculate out the total area of the hospital + // This can change if a hospital has been resized + this->spots_open = length*height; + this->spots_in_use.assign(this->spots_open, false); + + // The spots_in_use maps one to one with a spot + // starting at the upper-left hand corner, then + // across, then down. i.e. + // + // given hospital zone: + // + // UU + // uU + // + // where U is in use, and u isn't, the array + // would be t,t,f,t + + // Walk the building array and see what stuff is in the hospital, + // then walk the patient array and remark those spots as used. + + // If a patient is in an invalid spot, reassign it + for (size_t b =0 ; b < world->buildings.all.size(); b++) { + df::building* building = world->buildings.all[b]; + + // Check that we're not comparing ourselves; + if (building->id == this->id) { + continue; + } + + // Check if the building is on our z level, if it isn't + // then it can't overlap the hospital (until Toady implements + // multi-z buildings + if (building->z != this->z) { + continue; + } + + // DF defines activity zones multiple times in the building structure + // If axises agree with each other, we're looking at a reflection of + // ourselves + if (building->x1 == this->x1 && + building->x2 == this->x2 && + building->y1 == this->y1 && + building->y2 == this->y2) { + continue; + } + + // Check for X/Y overlap + // I can't believe I had to look this up -_-; + // http://stackoverflow.com/questions/306316/determine-if-two-rectangles-overlap-each-other + if ((this->x1 > building->x2 || + building->x1 > this->x2 || + this->y1 > building->y2 || + building->y1 > this->y2)) { + continue; + } + + // Crap, building overlaps, we need to figure out where it is in the hospital + // NOTE: under some conditions, this generates a false warning. Not a lot I can do about it + + // Mark spots used by that building as used; FIXME: handle special logic for traction benches and such + int building_offset_x = building->x1 - this->x1; + int building_offset_y = building->y1 - this->y1; + int building_length = building->x2 - building->x1 + 1; + int building_height = building->y2 - building->y1 + 1; + + // Cap the used calculation to only include the part in the hospital + if (this->x1 > building->x1) { + building_offset_x -= (this->x1 - building->x1); + } + + if (this->y1 > building->y1) { + building_offset_y -= (building->y1 - this->y1); + } + + if ((this->x2 < building->x2) && building_offset_x) { + building_length -= (this->x2 - building->x2) + 1; + } + + if ((this->y2 < building->y2) && building_offset_y) { + building_height = (building->y2 - this->y2) + 1; + } + + // Quick explination, if a building is north or east of the activity zone, + // we get a negative offset, we'll just skip those lines below. If its + // south or west, we make the building length/height lower to compinsate. + + /* if we have a negative x offset, we correct that */ + if (building_offset_x < 0) { + building_height += building_offset_x; + building_offset_x = 0; + } + + /* Handle negative y offset */ + if (building_offset_y < 0) { + building_length += building_offset_y; + building_offset_y = 0; + }; + + /* Advance the pointer to first row we need to mark */ + int spot_cur = 0; + if (building_offset_y) { + spot_cur = (length+1) * building_offset_y; + } + + spot_cur += building_offset_x; + /* Start marking! */ + for (int i = 0; i != building_height; i++) { + for (int j = 0; j != building_length; j++) { + spots_in_use[spot_cur+j] = true; + } + + // Wind the cursor to the start of the next row + spot_cur += length+1; + } + + // *phew*, done. Now repeat the process for the next building! + } + +} + +// Self explanatory +void AnimalHospital::dischargePatient(Patient * patient, color_ostream &out) { + int32_t id = patient->getID(); + + // Remove them from the hospital + + // We can safely iterate here because once we delete the unit + // we no longer use the iterator + for (vector::iterator accepted_patient = this->accepted_patients.begin(); accepted_patient != this->accepted_patients.end(); accepted_patient++) { + if ( (*accepted_patient)->getID() == id) { + out.print("Discharging unit %d from hospital %d\n", id, this->id); + // Reclaim their spot + spots_in_use[(*accepted_patient)->getSpotIndex()] = false; + this->spots_open++; + delete (*accepted_patient); + this->accepted_patients.erase(accepted_patient); + break; + } + } + + // And the master list + for (vector::iterator it = tracked_units.begin(); it != tracked_units.end(); it++) { + if ((*it) == id) { + tracked_units.erase(it); + break; + } + } + + return; +} + +void AnimalHospital::processPatients(color_ostream &out) { + // Where the magic happens + for (vector::iterator patient = this->accepted_patients.begin(); patient != this->accepted_patients.end(); patient++) { + int id = (*patient)->getID(); + df::unit * real_unit; + // Appears the health bits can get freed/realloced too -_-;, Find the unit from the main + // index and check it there. + auto units = world->units.all; + + for ( size_t a = 0; a < units.size(); a++ ) { + real_unit = units[a]; + if (real_unit->id == id) { + break; + } + } + + // Check to make sure the unit hasn't expired before assigning a job, or if they've been healed + if (real_unit->flags1.bits.dead || !real_unit->health->flags.bits.needs_healthcare) { + // discharge the patient from the hospital + this->dischargePatient(*patient, out); + return; + } + + // Give the unit a job if they don't have any + if (!real_unit->job.current_job) { + // Create REST struct + df::job * job = new df::job; + DFHack::Job::linkIntoWorld(job); + + job->pos.x = (*patient)->returnX(); + job->pos.y = (*patient)->returnY(); + job->pos.z = (*patient)->returnZ(); + job->flags.bits.special = 1; + job->job_type = df::enums::job_type::Rest; + df::general_ref *ref = df::allocate(); + ref->setID(real_unit->id); + job->general_refs.push_back(ref); + real_unit->job.current_job = job; + job->wait_timer = 1600; + out.print("Telling intelligent unit %d to report to the hospital!\n", real_unit->id); + } + } +} + + +static vector animal_hospital_zones; + +void delete_animal_hospital_vector(color_ostream &out) { + out.print("Clearing all animal hospitals\n"); + for (vector::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) { + delete (*animal_hospital); + } + animal_hospital_zones.clear(); +} + +command_result dwarfvet(color_ostream &out, std::vector & parameters); + +DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +{ + commands.push_back(PluginCommand( + "dwarfvet", + "Allows animals to be cared for in animal hospitals (activity zones that are animal training + hospital combined).", + dwarfvet, + false, //allow non-interactive use + "dwarfvet enable\n" + " enables animals to use animal hospitals (requires dwarf with Animal Caretaker labor enabled)\n" + "dwarfvet report\n" + " displays all zones dwarfvet considers animal hospitals and their current location on the map\n" + )); + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown ( color_ostream &out ) +{ + return CR_OK; +} + +bool isActiveAnimalHospital(df::building * building) { + if (Buildings::isHospital(building) && Buildings::isAnimalTraining(building) && Buildings::isActive(building)) { + return true; + } + + return false; +} + +bool compareAnimalHospitalZones(df::building * hospital1, df::building * hospital2) { + // We compare hospitals by checking if positions are identical, not by ID + // since activity zones can easily be changed in size + + if ( hospital1->x1 == hospital2->x1 && + hospital1->x2 == hospital2->x2 && + hospital1->y1 == hospital2->y1 && + hospital1->y2 == hospital2->y2 && + hospital1->z == hospital1->z) { + return true; + } + + return false; +} + +void tickHandler(color_ostream& out, void* data) { + if ( !dwarfvet_enabled ) + return; + CoreSuspender suspend; + int32_t own_race_id = df::global::ui->race_id; + int32_t own_civ_id = df::global::ui->civ_id; + auto units = world->units.all; + + /** + * Generate a list of animal hospitals on the map + * + * Since activity zones can change any instant given user interaction + * we need to be constantly on the lookout for changed zones, and update + * our cached list on the fly if necessary. + **/ + + vector hospitals_on_map; + + // Because C++ iterators suck, we're going to build a temporary vector with the AHZ, and then + // copy it for my own bloody sanity (and compilance with the STL spec) + vector ahz_scratch; + + // Holding area for things to be added to the scratch + vector to_be_added; + + + // Walk the building tree, and generate a list of animal hospitals on the map + for (size_t b =0 ; b < world->buildings.all.size(); b++) { + df::building* building = world->buildings.all[b]; + if (isActiveAnimalHospital(building)) { + hospitals_on_map.push_back(building); + } + } + + int count_of_hospitals = hospitals_on_map.size(); + int hospitals_cached = animal_hospital_zones.size(); + //out.print ("count_of_Hospitals: %d, hospitals_cached: %d\n", count_of_hospitals, hospitals_cached); + // It's possible our hospital cache is empty, if so, simply copy it, and jump to the main logic + if (!hospitals_cached && count_of_hospitals) { + out.print("Populating hospital cache:\n"); + for (vector::iterator current_hospital = hospitals_on_map.begin(); current_hospital != hospitals_on_map.end(); current_hospital++) { + AnimalHospital * hospital = new AnimalHospital(*current_hospital, out); + out.print(" Found animal hospital %d at x1: %d, y1: %d from valid hospital list\n", + hospital->getID(), + (*current_hospital)->x1, + (*current_hospital)->y1, + (*current_hospital)->z + ); + animal_hospital_zones.push_back(hospital); + } + + goto processUnits; + } + + if (!count_of_hospitals && !hospitals_cached) { + // No hospitals found, delete any cache, and return + delete_animal_hospital_vector(out); + out.print("No hospitals found, plugin sleeping ...\n"); + goto cleanup; + } + + // Now walk our list of known hospitals, do a bit of checking, then compare + // TODO: this doesn't handle zone resizes at all + + for (vector::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) { + // If a zone is changed at all, DF seems to reallocate it. + // + // Each AnimalHospital has a "to_be_deleted" bool. We're going to set that to true, and clear it if we can't + // find a matching hospital. This limits the number of times we need to walk through the AHZ list to twice, and + // lets us cleanly report it later + // + // Surviving hospitals will be copied to scratch which will become the new AHZ vector + + (*animal_hospital)->to_be_deleted = true; + for (vector::iterator current_hospital = hospitals_on_map.begin(); current_hospital != hospitals_on_map.end(); current_hospital++) { + + /* Keep the hospital if its still valid */ + if ((*animal_hospital)->getID() == (*current_hospital)->id) { + ahz_scratch.push_back(*animal_hospital); + (*animal_hospital)->to_be_deleted = false; + break; + } + + } + } + + // Report what we're deleting by checking the to_be_deleted bool. + // + // Whatsever left is added to the pending add list + for (vector::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) { + if ((*animal_hospital)->to_be_deleted) { + out.print("Hospital #%d removed\n", (*animal_hospital)->getID()); + delete *animal_hospital; + } + } + + /* Now we need to walk the scratch and add anything that is a hospital and wasn't in the vector */ + + for (vector::iterator current_hospital = hospitals_on_map.begin(); current_hospital != hospitals_on_map.end(); current_hospital++) { + bool new_hospital = true; + + for (vector::iterator animal_hospital = ahz_scratch.begin(); animal_hospital != ahz_scratch.end(); animal_hospital++) { + if ((*animal_hospital)->getID() == (*current_hospital)->id) { + // Next if we're already here + new_hospital = false; + break; + } + } + + // Add it if its new + if (new_hospital == true) to_be_added.push_back(*current_hospital); + } + + /* Now add it to the scratch AHZ */ + for (vector::iterator current_hospital = to_be_added.begin(); current_hospital != to_be_added.end(); current_hospital++) { + // Add it to the vector + out.print("Adding new hospital #id at x1 %d y1: %d z: %d\n", + (*current_hospital)->id, + (*current_hospital)->x1, + (*current_hospital)->y1, + (*current_hospital)->z + ); + AnimalHospital * hospital = new AnimalHospital(*current_hospital, out); + ahz_scratch.push_back(hospital); + } + + /* Copy the scratch to the AHZ */ + animal_hospital_zones = ahz_scratch; + + // We always recheck the cache instead of counts because someone might have removed then added a hospital +/* if (hospitals_cached != count_of_hospitals) { + out.print("Hospitals on the map changed, rebuilding cache\n"); + + for (vector::iterator current_hospital = hospitals_on_map.begin(); current_hospital != hospitals_on_map.end(); current_hospital++) { + bool add_hospital = true; + + for (vector::iterator map_hospital = animal_hospital_zones.begin(); map_hospital != animal_hospital_zones.end(); map_hospital++) { + if (compareAnimalHospitalZones(*map_hospital, *current_hospital)) { + // Same hospital, we're good + add_hospital = false; + break; + } + } + + // Add it to the list + if (add_hospital) { + out.print("Adding zone at x1: %d, y1: %d to valid hospital list\n", (*current_hospital)->x1, (*current_hospital)->y1); + animal_hospital_zones.push_back(*current_hospital); + } + } + } +*/ +processUnits: + /* Code borrowed from petcapRemover.cpp */ + for ( size_t a = 0; a < units.size(); a++ ) { + df::unit* unit = units[a]; + + /* As hilarious as it would be, lets not treat FB :) */ + if ( unit->flags1.bits.dead || unit->flags1.bits.active_invader || unit->flags2.bits.underworld || unit->flags2.bits.visitor_uninvited || unit->flags2.bits.visitor ) { + continue; + } + + if ( !Units::isTamable(unit)) { + continue; + } + + /** + * So, for a unit to be elligable for the hospital, all the following must be true + * + * 1. It must be a member of our civilization + * 2. It must be tame (semi-wild counts for this) + * 2.1 If its not a dwarf, AND untame clear its civ out so traps work + * 3. It must have a health struct (which is generated by combat) + * 4. health->needs_healthcare must be set to true + * 5. If health->requires_recovery is set, the creature can't move under its own power + * and a Recover Wounded or Pen/Pasture job MUST be created by hand - TODO + * 6. An open spot in the "Animal Hospital" (activity zone with hospital+animal training set) + * must be available + * + * I apologize if this excessively verbose, but the healthcare system is stupidly conplex + * and there's tons of edgecases to watch out for, and I want someone else to ACTUALLY + * beside me able to understand what's going on + */ + + // 1. Make sure its our own civ + if (!Units::isOwnCiv(unit)) { + continue; + } + + // 2. Check for tameness + if (unit->training_level == df::animal_training_level::WildUntamed) { + // We don't IMMEDIATELY continue here, if the unit is + // part of our civ, it indiciates it WAS tamed, and reverted + // from SemiWild. Clear its civ flag so it looses TRAPAVOID + // + // Unfortunately, dwarves (or whatever is CIV_SELECTABLE) + // also have a default taming level of WildUntamed so + // check for this case + // + // Furthermore, it MIGHT be a werebeast, so check THAT too + // and exclude those as well. + // + // Finally, this breaks makeown. I might need to write a patch + // to set the tameness of "makeowned" units so dwarfvet can notice + // it + + if (unit->race == own_race_id || unit->enemy.normal_race == own_race_id) { + continue; + } else { + unit->civ_id = -1; + out.print ("Clearing civ on unit: %d", unit->id); + } + } + + // 3. Check for health struct + if (!unit->health) { + // Unit has not been injured ever; health struct MIA + continue; + } + + // 4. Check the healthcare flags + if (unit->health->flags.bits.needs_healthcare) { + /** + * So, for dwarves to care for a unit it must be resting in + * in a hospital zone. Since non-dwarves never take jobs + * this why animal healthcare doesn't work for animals despite + * animal caretaker being coded in DF itself + * + * How a unit gets there is dependent on several factors. If + * a unit can move under its own power, it will take the rest + * job, with a position of a bed in the hospital, then move + * into that bed and fall asleep. This triggers a doctor to + * treat the unit. + * + * If a unit *can't* move, it will set needs_recovery, which + * creates a "Recover Wounded" job in the job list, and then + * create the "Rest" job as listed above. Another dwarf with + * the right labors will go recover the unit, then the above + * logic kicks off. + * + * The necessary flags seem to be properly set for all units + * on the map, so in theory, we just need to make the jobs and + * we're in business, but from a realism POV, I don't think + * non-sentient animals would be smart enough to go to the + * hospital on their own, so instead, we're going to do the following + * + * If a unit CAN_THINK, and can move let it act like a dwarf, + * it will try and find an open spot in the hospital, and if so, + * go there to be treated. In vanilla, the only tamable animal + * with CAN_THINK are Gremlins, so this is actually an edge case + * but its the easiest to code. + * + * TODO: figure out exact logic for non-thinking critters. + */ + + // Now we need to find if this unit can be accepted at a hospital + bool awareOfUnit = false; + for (vector::iterator it = tracked_units.begin(); it != tracked_units.end(); it++) { + if ((*it) == unit->id) { + awareOfUnit = true; + } + } + // New unit for dwarfvet to be aware of! + if (!awareOfUnit) { + // The master list handles all patients which are accepted + // Check if this is a unit we're already aware of + + bool patient_accepted = false; + for (vector::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end();) { + if ((*animal_hospital)->acceptPatient(unit->id, out)) { + out.print("Accepted patient %d at hospital %d\n", unit->id, (*animal_hospital)->getID()); + patient_accepted = true; + tracked_units.push_back(unit->id); + break; + } + + + } + } + } + } + + // The final step, process all patients! + for (vector::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) { + (*animal_hospital)->calculateHospital(true, out); + (*animal_hospital)->processPatients(out); + } + +cleanup: + EventManager::unregisterAll(plugin_self); + EventManager::EventHandler handle(tickHandler, howOften); + EventManager::registerTick(handle, howOften, plugin_self); +} + +command_result dwarfvet (color_ostream &out, std::vector & parameters) +{ + CoreSuspender suspend; + + for ( size_t a = 0; a < parameters.size(); a++ ) { + if ( parameters[a] == "enable" ) { + out.print("dwarfvet enabled!\n"); + dwarfvet_enabled = true; + } + if ( parameters[a] == "disable") { + out.print("dwarvet disabled!\n"); + dwarfvet_enabled = false; + } + if ( parameters[a] == "report") { + out.print("Current animal hospitals are:\n"); + for (size_t b =0 ; b < world->buildings.all.size(); b++) { + df::building* building = world->buildings.all[b]; + if (isActiveAnimalHospital(building)) { + out.print(" at x1: %d, x2%: %d, y1: %d, y2: %d, z: %d\n", building->x1, building->x2, building->y1, building->y2, building->z); + } + } + return CR_OK; + } + if ( parameters[a] == "report-usage") { + out.print("Current animal hospitals are:\n"); + for (vector::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) { + (*animal_hospital)->calculateHospital(true, out); + (*animal_hospital)->reportUsage(out); + } + return CR_OK; + } + } + + if ( !dwarfvet_enabled ) { + return CR_OK; + } + + EventManager::unregisterAll(plugin_self); + EventManager::EventHandler handle(tickHandler, howOften); + EventManager::registerTick(handle, howOften, plugin_self); + + return CR_OK; +} + +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + if (enable && !dwarfvet_enabled) { + dwarfvet_enabled = true; + } + else if (!enable && dwarfvet_enabled) { + delete_animal_hospital_vector(out); + dwarfvet_enabled = false; + } + + return CR_OK; +} + +DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) +{ + switch (event) + { + case DFHack::SC_MAP_LOADED: + break; + case DFHack::SC_MAP_UNLOADED: + delete_animal_hospital_vector(out); + dwarfvet_enabled = false; + break; + default: + break; + } + return CR_OK; +} \ No newline at end of file From fead8a80ff5d18743a1f11a8a710e23a62098abc Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Sun, 5 Jun 2016 11:05:28 -0400 Subject: [PATCH 002/413] Fix tabs to spaces Signed-off-by: Michael Casadevall --- plugins/dwarfvet.cpp | 84 ++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/plugins/dwarfvet.cpp b/plugins/dwarfvet.cpp index 44b3684e0..920e13d34 100644 --- a/plugins/dwarfvet.cpp +++ b/plugins/dwarfvet.cpp @@ -175,7 +175,7 @@ bool AnimalHospital::acceptPatient(int32_t id, color_ostream &out) { // Create the patient! Patient * patient = new Patient(id, - spot_cur, + spot_cur, this->x1+offset_x, this->y1+offset_y, this->z @@ -342,8 +342,8 @@ void AnimalHospital::dischargePatient(Patient * patient, color_ostream &out) { // Remove them from the hospital - // We can safely iterate here because once we delete the unit - // we no longer use the iterator + // We can safely iterate here because once we delete the unit + // we no longer use the iterator for (vector::iterator accepted_patient = this->accepted_patients.begin(); accepted_patient != this->accepted_patients.end(); accepted_patient++) { if ( (*accepted_patient)->getID() == id) { out.print("Discharging unit %d from hospital %d\n", id, this->id); @@ -485,12 +485,12 @@ void tickHandler(color_ostream& out, void* data) { vector hospitals_on_map; - // Because C++ iterators suck, we're going to build a temporary vector with the AHZ, and then - // copy it for my own bloody sanity (and compilance with the STL spec) - vector ahz_scratch; + // Because C++ iterators suck, we're going to build a temporary vector with the AHZ, and then + // copy it for my own bloody sanity (and compilance with the STL spec) + vector ahz_scratch; - // Holding area for things to be added to the scratch - vector to_be_added; + // Holding area for things to be added to the scratch + vector to_be_added; // Walk the building tree, and generate a list of animal hospitals on the map @@ -531,70 +531,70 @@ void tickHandler(color_ostream& out, void* data) { // Now walk our list of known hospitals, do a bit of checking, then compare // TODO: this doesn't handle zone resizes at all - for (vector::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) { + for (vector::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) { // If a zone is changed at all, DF seems to reallocate it. // // Each AnimalHospital has a "to_be_deleted" bool. We're going to set that to true, and clear it if we can't // find a matching hospital. This limits the number of times we need to walk through the AHZ list to twice, and - // lets us cleanly report it later - // - // Surviving hospitals will be copied to scratch which will become the new AHZ vector + // lets us cleanly report it later + // + // Surviving hospitals will be copied to scratch which will become the new AHZ vector (*animal_hospital)->to_be_deleted = true; for (vector::iterator current_hospital = hospitals_on_map.begin(); current_hospital != hospitals_on_map.end(); current_hospital++) { - /* Keep the hospital if its still valid */ + /* Keep the hospital if its still valid */ if ((*animal_hospital)->getID() == (*current_hospital)->id) { - ahz_scratch.push_back(*animal_hospital); + ahz_scratch.push_back(*animal_hospital); (*animal_hospital)->to_be_deleted = false; - break; - } + break; + } } } // Report what we're deleting by checking the to_be_deleted bool. - // - // Whatsever left is added to the pending add list + // + // Whatsever left is added to the pending add list for (vector::iterator animal_hospital = animal_hospital_zones.begin(); animal_hospital != animal_hospital_zones.end(); animal_hospital++) { if ((*animal_hospital)->to_be_deleted) { out.print("Hospital #%d removed\n", (*animal_hospital)->getID()); delete *animal_hospital; - } + } } /* Now we need to walk the scratch and add anything that is a hospital and wasn't in the vector */ for (vector::iterator current_hospital = hospitals_on_map.begin(); current_hospital != hospitals_on_map.end(); current_hospital++) { - bool new_hospital = true; - - for (vector::iterator animal_hospital = ahz_scratch.begin(); animal_hospital != ahz_scratch.end(); animal_hospital++) { - if ((*animal_hospital)->getID() == (*current_hospital)->id) { - // Next if we're already here - new_hospital = false; - break; - } - } - - // Add it if its new - if (new_hospital == true) to_be_added.push_back(*current_hospital); - } - - /* Now add it to the scratch AHZ */ - for (vector::iterator current_hospital = to_be_added.begin(); current_hospital != to_be_added.end(); current_hospital++) { - // Add it to the vector + bool new_hospital = true; + + for (vector::iterator animal_hospital = ahz_scratch.begin(); animal_hospital != ahz_scratch.end(); animal_hospital++) { + if ((*animal_hospital)->getID() == (*current_hospital)->id) { + // Next if we're already here + new_hospital = false; + break; + } + } + + // Add it if its new + if (new_hospital == true) to_be_added.push_back(*current_hospital); + } + + /* Now add it to the scratch AHZ */ + for (vector::iterator current_hospital = to_be_added.begin(); current_hospital != to_be_added.end(); current_hospital++) { + // Add it to the vector out.print("Adding new hospital #id at x1 %d y1: %d z: %d\n", (*current_hospital)->id, (*current_hospital)->x1, (*current_hospital)->y1, (*current_hospital)->z - ); - AnimalHospital * hospital = new AnimalHospital(*current_hospital, out); + ); + AnimalHospital * hospital = new AnimalHospital(*current_hospital, out); ahz_scratch.push_back(hospital); - } + } - /* Copy the scratch to the AHZ */ - animal_hospital_zones = ahz_scratch; + /* Copy the scratch to the AHZ */ + animal_hospital_zones = ahz_scratch; // We always recheck the cache instead of counts because someone might have removed then added a hospital /* if (hospitals_cached != count_of_hospitals) { @@ -808,7 +808,7 @@ command_result dwarfvet (color_ostream &out, std::vector & paramet DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { if (enable && !dwarfvet_enabled) { - dwarfvet_enabled = true; + dwarfvet_enabled = true; } else if (!enable && dwarfvet_enabled) { delete_animal_hospital_vector(out); From e99187dc866c346c8451fde7809c9a0c5c86a3a5 Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Sun, 5 Jun 2016 11:45:58 -0400 Subject: [PATCH 003/413] Add documentation for dwarfvet Signed-off-by: Michael Casadevall --- docs/Plugins.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 75d2d988d..34bbef32e 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -1109,6 +1109,27 @@ Example: This will confiscate rotten and dropped food, garbage on the floors and any worn items with 'X' damage and above. +.. _dwarfvet: + +dwarfvet +============ +Enables Animal Caretaker functionality + +Always annoyed your dragons become useless after a minor injury? Well, with +dwarfvet, your animals become first rate members of your fort. It can also +be used to train medical skills. + +Animals need to be treated in an animal hospital, which is simply a hospital +that is also an animal training zone. The console will print out a list on game +load, and whenever one is added or removed. Dwarfs must have the Animal Caretaker +labor to treat animals. Normal medical skills are used (and no experience is given +to the Animal Caretaker skill). + +Options: + +:enable: Enables Animal Caretakers to treat and manage animals +:disable: Turns off the plguin +:report: Reports all zones that the game considers animal hospitals .. _dwarfmonitor: From 0dc62a5c9c071008069e091d2f93bb4cc222573a Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Wed, 8 Jun 2016 04:07:50 -0400 Subject: [PATCH 004/413] Add to NEWS.rst and authors Signed-off-by: Michael Casadevall --- NEWS.rst | 1 + docs/Authors.rst | 1 + 2 files changed, 2 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 7571ec45a..025aabfbc 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -40,6 +40,7 @@ Lua New Features ------------ - `gui/gm-editor` it's now possible to insert default types to containers. For primitive types leave the type entry empty, for references use ``*``. +- `dwarfvet` enables animal caretaking. Fixes ----- diff --git a/docs/Authors.rst b/docs/Authors.rst index c4462a987..cb6d0db7f 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -57,6 +57,7 @@ Meneth32 Meph Michon van Dooren MaienM miffedmap miffedmap +Michael Casadevall NCommander Mike Stewart thewonderidiot Mikko Juola Noeda Adeon MithrilTuxedo MithrilTuxedo From 628c8ee5bf4c59f00c41b9aa70c7c91828711d78 Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Wed, 8 Jun 2016 06:10:18 -0400 Subject: [PATCH 005/413] Fix ordering in Authors.rst Signed-off-by: Michael Casadevall --- docs/Authors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Authors.rst b/docs/Authors.rst index cb6d0db7f..bc1c1c7cb 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -55,9 +55,9 @@ Max maxthyme Max^TM melkor217 melkor217 Meneth32 Meph +Michael Casadevall NCommander Michon van Dooren MaienM miffedmap miffedmap -Michael Casadevall NCommander Mike Stewart thewonderidiot Mikko Juola Noeda Adeon MithrilTuxedo MithrilTuxedo From 39c96c474a827cb01ffc7a2ba8b450be8aa14565 Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Tue, 14 Jun 2016 16:13:26 -0400 Subject: [PATCH 006/413] Fix ordering, news, and indentation Signed-off-by: Michael Casadevall --- NEWS.rst | 5 ++++- docs/Plugins.rst | 44 +++++++++++++++++++++--------------------- plugins/CMakeLists.txt | 2 +- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 025aabfbc..1b1b594b5 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -37,10 +37,13 @@ Lua --- - Label widgets can now easily register handlers for mouse clicks +New Plugins +----------- +- `dwarfvet` enables animal caretaking. + New Features ------------ - `gui/gm-editor` it's now possible to insert default types to containers. For primitive types leave the type entry empty, for references use ``*``. -- `dwarfvet` enables animal caretaking. Fixes ----- diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 34bbef32e..f352d97fe 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -1109,28 +1109,6 @@ Example: This will confiscate rotten and dropped food, garbage on the floors and any worn items with 'X' damage and above. -.. _dwarfvet: - -dwarfvet -============ -Enables Animal Caretaker functionality - -Always annoyed your dragons become useless after a minor injury? Well, with -dwarfvet, your animals become first rate members of your fort. It can also -be used to train medical skills. - -Animals need to be treated in an animal hospital, which is simply a hospital -that is also an animal training zone. The console will print out a list on game -load, and whenever one is added or removed. Dwarfs must have the Animal Caretaker -labor to treat animals. Normal medical skills are used (and no experience is given -to the Animal Caretaker skill). - -Options: - -:enable: Enables Animal Caretakers to treat and manage animals -:disable: Turns off the plguin -:report: Reports all zones that the game considers animal hospitals - .. _dwarfmonitor: dwarfmonitor @@ -1208,6 +1186,28 @@ Some widgets support additional options: displayed as ``-1`` when the cursor is outside of the DF window; otherwise, nothing will be displayed. +.. _dwarfvet: + +dwarfvet +============ +Enables Animal Caretaker functionality + +Always annoyed your dragons become useless after a minor injury? Well, with +dwarfvet, your animals become first rate members of your fort. It can also +be used to train medical skills. + +Animals need to be treated in an animal hospital, which is simply a hospital +that is also an animal training zone. The console will print out a list on game +load, and whenever one is added or removed. Dwarfs must have the Animal Caretaker +labor to treat animals. Normal medical skills are used (and no experience is given +to the Animal Caretaker skill). + +Options: + +:enable: Enables Animal Caretakers to treat and manage animals +:disable: Turns off the plguin +:report: Reports all zones that the game considers animal hospitals + .. _workNow: workNow diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index fbf33f459..79d2f0092 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -93,7 +93,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(dig dig.cpp) DFHACK_PLUGIN(digFlood digFlood.cpp) add_subdirectory(diggingInvaders) - DFHACK_PLUGIN(dwarfvet dwarfvet.cpp) + DFHACK_PLUGIN(dwarfvet dwarfvet.cpp) DFHACK_PLUGIN(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(embark-tools embark-tools.cpp) DFHACK_PLUGIN(eventful eventful.cpp LINK_LIBRARIES lua) From 2072dcc38d9cadf747006223f12018ef16056221 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 27 Jun 2016 12:04:51 -0500 Subject: [PATCH 007/413] Rename autolabor2 to labormanager and bring up to date with current --- plugins/devel/CMakeLists.txt | 2 +- .../{autolabor2.cpp => labormanager.cpp} | 487 +++++++++++++----- 2 files changed, 354 insertions(+), 135 deletions(-) rename plugins/devel/{autolabor2.cpp => labormanager.cpp} (86%) diff --git a/plugins/devel/CMakeLists.txt b/plugins/devel/CMakeLists.txt index 1f3ff6f75..a1e5b7f14 100644 --- a/plugins/devel/CMakeLists.txt +++ b/plugins/devel/CMakeLists.txt @@ -3,13 +3,13 @@ DFHACK_PLUGIN(vectors vectors.cpp) endif() ADD_DEFINITIONS(-DDEV_PLUGIN) -#DFHACK_PLUGIN(autolabor2 autolabor2.cpp) DFHACK_PLUGIN(buildprobe buildprobe.cpp) DFHACK_PLUGIN(color-dfhack-text color-dfhack-text.cpp) DFHACK_PLUGIN(counters counters.cpp) DFHACK_PLUGIN(dumpmats dumpmats.cpp) DFHACK_PLUGIN(eventExample eventExample.cpp) DFHACK_PLUGIN(frozen frozen.cpp) +DFHACK_PLUGIN(labormanager labormanager.cpp) DFHACK_PLUGIN(kittens kittens.cpp) DFHACK_PLUGIN(memview memview.cpp) DFHACK_PLUGIN(nestboxes nestboxes.cpp) diff --git a/plugins/devel/autolabor2.cpp b/plugins/devel/labormanager.cpp similarity index 86% rename from plugins/devel/autolabor2.cpp rename to plugins/devel/labormanager.cpp index 4897832d4..12e4e8ca1 100644 --- a/plugins/devel/autolabor2.cpp +++ b/plugins/devel/labormanager.cpp @@ -1,5 +1,5 @@ /* -* Autolabor 2.0 module for dfhack +* Labor manager (formerly Autolabor 2) module for dfhack * * */ @@ -77,7 +77,7 @@ using df::global::world; #define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0])) -DFHACK_PLUGIN_IS_ENABLED(enable_autolabor); +DFHACK_PLUGIN_IS_ENABLED(enable_labormanager); static bool print_debug = 0; @@ -94,11 +94,11 @@ enum ConfigFlags { // Here go all the command declarations... // mostly to allow having the mandatory stuff on top of the file and commands on the bottom -command_result autolabor (color_ostream &out, std::vector & parameters); +command_result labormanager (color_ostream &out, std::vector & parameters); // A plugin must be able to return its name and version. -// The name string provided must correspond to the filename - autolabor2.plug.so or autolabor2.plug.dll in this case -DFHACK_PLUGIN("autolabor2"); +// The name string provided must correspond to the filename - labormanager.plug.so or labormanager.plug.dll in this case +DFHACK_PLUGIN("labormanager"); static void generate_labor_to_skill_map(); @@ -486,9 +486,20 @@ static const struct labor_default default_labor_infos[] = { /* PRESSING */ {200, 0, TOOL_NONE}, /* BEEKEEPING */ {200, 0, TOOL_NONE}, /* WAX_WORKING */ {200, 0, TOOL_NONE}, - /* PUSH_HAUL_VEHICLES */ {200, 0, TOOL_NONE} + /* PUSH_HAUL_VEHICLES */ {200, 0, TOOL_NONE}, + /* HAUL_TRADE */ {200, 0, TOOL_NONE}, + /* PULL_LEVER */ {200, 0, TOOL_NONE}, + /* REMOVE_CONSTRUCTION */ {200, 0, TOOL_NONE}, + /* HAUL_WATER */ {200, 0, TOOL_NONE}, + /* GELD */ {200, 0, TOOL_NONE}, + /* BUILD_ROAD */ {200, 0, TOOL_NONE}, + /* BUILD_CONSTRUCTION */ {200, 0, TOOL_NONE}, + /* PAPERMAKING */ {200, 0, TOOL_NONE}, + /* BOOKBINDING */ {200, 0, TOOL_NONE} }; +void debug (char* fmt, ...); + struct dwarf_info_t { df::unit* dwarf; @@ -506,12 +517,19 @@ struct dwarf_info_t df::unit_labor using_labor; dwarf_info_t(df::unit* dw) : dwarf(dw), clear_all(false), - state(OTHER), high_skill(0), has_children(false), armed(false) + state(OTHER), high_skill(0), has_children(false), armed(false), using_labor(df::unit_labor::NONE) { for (int e = TOOL_NONE; e < TOOLS_MAX; e++) has_tool[e] = false; } + ~dwarf_info_t() + { + if (print_debug) + debug("LABORMANAGER: destroying dwarf %p\n", (void*) this); + } + + void set_labor(df::unit_labor labor) { if (labor >= 0 && labor <= ENUM_LAST_ITEM(unit_labor)) @@ -554,10 +572,10 @@ static df::unit_labor hauling_labor_map[] = df::unit_labor::HAUL_ITEM, /* INSTRUMENT */ df::unit_labor::HAUL_ITEM, /* TOY */ df::unit_labor::HAUL_FURNITURE, /* WINDOW */ - df::unit_labor::HAUL_ANIMAL, /* CAGE */ + df::unit_labor::HAUL_ANIMALS, /* CAGE */ df::unit_labor::HAUL_ITEM, /* BARREL */ df::unit_labor::HAUL_ITEM, /* BUCKET */ - df::unit_labor::HAUL_ANIMAL, /* ANIMALTRAP */ + df::unit_labor::HAUL_ANIMALS, /* ANIMALTRAP */ df::unit_labor::HAUL_FURNITURE, /* TABLE */ df::unit_labor::HAUL_FURNITURE, /* COFFIN */ df::unit_labor::HAUL_FURNITURE, /* STATUE */ @@ -850,7 +868,7 @@ private: return df::unit_labor::SIEGECRAFT; } - debug ("AUTOLABOR: Cannot deduce labor for construct building job of type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for construct building job of type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); return df::unit_labor::NONE; @@ -944,7 +962,7 @@ private: return df::unit_labor::SIEGECRAFT; } - debug ("AUTOLABOR: Cannot deduce labor for destroy building job of type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for destroy building job of type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); return df::unit_labor::NONE; @@ -979,13 +997,13 @@ private: return df::unit_labor::BONE_CARVE; else { - debug ("AUTOLABOR: Cannot deduce labor for make crafts job (not bone)\n"); + debug ("LABORMANAGER: Cannot deduce labor for make crafts job (not bone)\n"); return df::unit_labor::NONE; } case df::item_type::WOOD: return df::unit_labor::WOOD_CRAFT; default: - debug ("AUTOLABOR: Cannot deduce labor for make crafts job, item type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for make crafts job, item type %s\n", ENUM_KEY_STR(item_type, jobitem).c_str()); return df::unit_labor::NONE; } @@ -1002,7 +1020,7 @@ private: case df::workshop_type::MetalsmithsForge: return metaltype; default: - debug ("AUTOLABOR: Cannot deduce labor for make job, workshop type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for make job, workshop type %s\n", ENUM_KEY_STR(workshop_type, type).c_str()); return df::unit_labor::NONE; } @@ -1016,13 +1034,13 @@ private: case df::furnace_type::GlassFurnace: return df::unit_labor::GLASSMAKER; default: - debug ("AUTOLABOR: Cannot deduce labor for make job, furnace type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for make job, furnace type %s\n", ENUM_KEY_STR(furnace_type, type).c_str()); return df::unit_labor::NONE; } } - debug ("AUTOLABOR: Cannot deduce labor for make job, building type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for make job, building type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); return df::unit_labor::NONE; @@ -1147,8 +1165,6 @@ public: job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInBag] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInHospital] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInChest] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInCabinet] = jlf_hauling; job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling; job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling; @@ -1219,7 +1235,6 @@ public: job_to_labor_table[df::job_type::MilkCreature] = jlf_const(df::unit_labor::MILK); job_to_labor_table[df::job_type::MakeCheese] = jlf_const(df::unit_labor::MAKE_CHEESE); job_to_labor_table[df::job_type::ProcessPlants] = jlf_const(df::unit_labor::PROCESS_PLANT); - job_to_labor_table[df::job_type::ProcessPlantsBag] = jlf_const(df::unit_labor::PROCESS_PLANT); job_to_labor_table[df::job_type::ProcessPlantsVial] = jlf_const(df::unit_labor::PROCESS_PLANT); job_to_labor_table[df::job_type::ProcessPlantsBarrel] = jlf_const(df::unit_labor::PROCESS_PLANT); job_to_labor_table[df::job_type::PrepareMeal] = jlf_const(df::unit_labor::COOK); @@ -1256,7 +1271,6 @@ public: job_to_labor_table[df::job_type::CastSpell] = jlf_no_labor; job_to_labor_table[df::job_type::LinkBuildingToTrigger] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::PullLever] = jlf_no_labor; - job_to_labor_table[df::job_type::BrewDrink] = jlf_const(df::unit_labor::BREWER) ; job_to_labor_table[df::job_type::ExtractFromPlants] = jlf_const(df::unit_labor::HERBALIST) ; job_to_labor_table[df::job_type::ExtractFromRawFish] = jlf_const(df::unit_labor::DISSECT_FISH) ; job_to_labor_table[df::job_type::ExtractFromLandAnimal] = jlf_const(df::unit_labor::DISSECT_VERMIN) ; @@ -1334,9 +1348,9 @@ public: job_to_labor_table[df::job_type::ExecuteCriminal] = jlf_no_labor; job_to_labor_table[df::job_type::TrainAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN); job_to_labor_table[df::job_type::CarveTrack] = jlf_const(df::unit_labor::DETAIL); - job_to_labor_table[df::job_type::PushTrackVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE); - job_to_labor_table[df::job_type::PlaceTrackVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE); - job_to_labor_table[df::job_type::StoreItemInVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE); + job_to_labor_table[df::job_type::PushTrackVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES); + job_to_labor_table[df::job_type::PlaceTrackVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES); + job_to_labor_table[df::job_type::StoreItemInVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES); job_to_labor_table[df::job_type::GeldAnimal] = jlf_const(df::unit_labor::GELD); job_to_labor_table[df::job_type::MakeFigurine] = jlf_make_object; job_to_labor_table[df::job_type::MakeAmulet] = jlf_make_object; @@ -1365,7 +1379,14 @@ public: df::unit_labor labor; - labor = job_to_labor_table[j->job_type]->get_labor(j); + if (job_to_labor_table.count(j->job_type) == 0) + { + debug("LABORMANAGER: job has no job to labor table entry: %s\n", ENUM_KEY_STR(job_type, j->job_type).c_str()); + labor = df::unit_labor::NONE; + } else { + + labor = job_to_labor_table[j->job_type]->get_labor(j); + } return labor; } @@ -1375,6 +1396,8 @@ public: static JobLaborMapper* labor_mapper = 0; +static bool initialized = false; + static bool isOptionEnabled(unsigned flag) { return config.isValid() && (config.ival(0) & flag) != 0; @@ -1393,8 +1416,9 @@ static void setOptionEnabled(ConfigFlags flag, bool on) static void cleanup_state() { - enable_autolabor = false; + enable_labormanager = false; labor_infos.clear(); + initialized = false; } static void reset_labor(df::unit_labor labor) @@ -1405,25 +1429,25 @@ static void reset_labor(df::unit_labor labor) static void init_state() { - config = World::GetPersistentData("autolabor/2.0/config"); + config = World::GetPersistentData("labormanager/2.0/config"); if (config.isValid() && config.ival(0) == -1) config.ival(0) = 0; - enable_autolabor = isOptionEnabled(CF_ENABLED); + enable_labormanager = isOptionEnabled(CF_ENABLED); - if (!enable_autolabor) + if (!enable_labormanager) return; // Load labors from save labor_infos.resize(ARRAY_COUNT(default_labor_infos)); std::vector items; - World::GetPersistentData(&items, "autolabor/2.0/labors/", true); + World::GetPersistentData(&items, "labormanager/2.0/labors/", true); for (auto p = items.begin(); p != items.end(); p++) { string key = p->key(); - df::unit_labor labor = (df::unit_labor) atoi(key.substr(strlen("autolabor/2.0/labors/")).c_str()); + df::unit_labor labor = (df::unit_labor) atoi(key.substr(strlen("labormanager/2.0/labors/")).c_str()); if (labor >= 0 && labor <= labor_infos.size()) { labor_infos[labor].config = *p; @@ -1437,7 +1461,7 @@ static void init_state() continue; std::stringstream name; - name << "autolabor/2.0/labors/" << i; + name << "labormanager/2.0/labors/" << i; labor_infos[i].config = World::AddPersistentData(name.str()); labor_infos[i].mark_assigned(); @@ -1445,6 +1469,8 @@ static void init_state() reset_labor((df::unit_labor) i); } + initialized = true; + } static df::job_skill labor_to_skill[ENUM_LAST_ITEM(unit_labor) + 1]; @@ -1477,12 +1503,12 @@ static void enable_plugin(color_ostream &out) { if (!config.isValid()) { - config = World::AddPersistentData("autolabor/2.0/config"); + config = World::AddPersistentData("labormanager/2.0/config"); config.ival(0) = 0; } setOptionEnabled(CF_ENABLED, true); - enable_autolabor = true; + enable_labormanager = true; out << "Enabling the plugin." << endl; cleanup_state(); @@ -1497,32 +1523,32 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector \n" + " labormanager max \n" " Set max number of dwarves assigned to a labor.\n" - " autolabor2 max none\n" + " labormanager max none\n" " Unrestrict the number of dwarves assigned to a labor.\n" - " autolabor2 priority \n" + " labormanager priority \n" " Change the assignment priority of a labor (default is 100)\n" - " autolabor2 reset \n" + " labormanager reset \n" " Return a labor to the default handling.\n" - " autolabor2 reset-all\n" + " labormanager reset-all\n" " Return all labors to the default handling.\n" - " autolabor2 list\n" + " labormanager list\n" " List current status of all labors.\n" - " autolabor2 status\n" + " labormanager status\n" " Show basic status information.\n" "Function:\n" - " When enabled, autolabor periodically checks your dwarves and enables or\n" + " When enabled, labormanager periodically checks your dwarves and enables or\n" " disables labors. Generally, each dwarf will be assigned exactly one labor.\n" - " Warning: autolabor will override any manual changes you make to labors\n" - " while it is enabled. Do not try to run both autolabor and autolabor2 at\n" - " the same time." + " Warning: labormanager will override any manual changes you make to labors\n" + " while it is enabled. Do not try to run both labormanager and labormanager at\n" + " the same time.\n" )); generate_labor_to_skill_map(); @@ -1594,14 +1620,21 @@ private: int need_food_water; + int priority_food; + std::map labor_needed; std::map labor_outside; std::vector dwarf_info; std::list available_dwarfs; + std::list busy_dwarfs; private: void scan_buildings() { + has_butchers = false; + has_fishery = false; + trader_requested = false; + for (auto b = world->buildings.all.begin(); b != world->buildings.all.end(); b++) { df::building *build = *b; @@ -1658,16 +1691,14 @@ private: if (dig != df::enums::tile_dig_designation::No) { df::tiletype tt = bl->tiletype[x][y]; + df::tiletype_material ttm = ENUM_ATTR(tiletype, material, tt); df::tiletype_shape tts = ENUM_ATTR(tiletype, shape, tt); - switch (tts) - { - case df::enums::tiletype_shape::TREE: - tree_count++; break; - case df::enums::tiletype_shape::SHRUB: - plant_count++; break; - default: - dig_count++; break; - } + if (ttm == df::enums::tiletype_material::TREE) + tree_count++; + else if (tts == df::enums::tiletype_shape::SHRUB) + plant_count++; + else + dig_count++; } if (bl->designation[x][y].bits.smooth != 0) detail_count++; @@ -1684,13 +1715,15 @@ private: for (int e = TOOL_NONE; e < TOOLS_MAX; e++) tool_count[e] = 0; + priority_food = 0; + df::item_flags bad_flags; bad_flags.whole = 0; #define F(x) bad_flags.bits.x = true; F(dump); F(forbid); F(garbage_collect); F(hostile); F(on_fire); F(rotten); F(trader); - F(in_building); F(construction); F(artifact); + F(in_building); F(construction); #undef F auto& v = world->items.all; @@ -1704,6 +1737,11 @@ private: if (item->flags.whole & bad_flags.whole) continue; + df::item_type t = item->getType(); + + if (item->materialRots() && t != df::item_type::CORPSEPIECE && t != df::item_type::CORPSE && item->getRotTimer() > 1) + priority_food++; + if (!item->isWeapon()) continue; @@ -1869,14 +1907,20 @@ private: { state = CHILD; } + else if (ENUM_ATTR(profession, military, dwarf->dwarf->profession)) state = MILITARY; + + else if (dwarf->dwarf->burrows.size() > 0) + state = OTHER; // dwarfs assigned to burrows are treated as if permanently busy + else if (dwarf->dwarf->job.current_job == NULL) { - if (is_on_break) + if (is_on_break || dwarf->dwarf->flags1.bits.chained || dwarf->dwarf->flags1.bits.caged) + { state = OTHER; - else if (dwarf->dwarf->burrows.size() > 0) - state = OTHER; // dwarfs assigned to burrows are treated as if permanently busy + dwarf->clear_all = true; + } else if (dwarf->dwarf->status2.limbs_grasp_count == 0) { state = OTHER; // dwarfs unable to grasp are incapable of nearly all labors @@ -1902,18 +1946,23 @@ private: if (state == BUSY) { df::unit_labor labor = labor_mapper->find_job_labor(dwarf->dwarf->job.current_job); + + dwarf->using_labor = labor; + if (labor != df::unit_labor::NONE) { - dwarf->using_labor = labor; + labor_infos[labor].busy_dwarfs++; - if (!dwarf->dwarf->status.labors[labor] && print_debug) + if (!dwarf->dwarf->status.labors[labor]) { - out.print("AUTOLABOR: dwarf %s (id %d) is doing job %s(%d) but is not enabled for labor %s(%d).\n", + out.print("LABORMANAGER: dwarf %s (id %d) is doing job %s(%d) but is not enabled for labor %s(%d).\n", dwarf->dwarf->name.first_name.c_str(), dwarf->dwarf->id, ENUM_KEY_STR(job_type, job).c_str(), job, ENUM_KEY_STR(unit_labor, labor).c_str(), labor); } } } + if (state == OTHER) + dwarf->clear_all = true; } dwarf->state = state; @@ -1925,8 +1974,6 @@ private: if (dwarf->dwarf->status.labors[l]) if (state == IDLE) labor_infos[l].idle_dwarfs++; - else if (state == BUSY) - labor_infos[l].busy_dwarfs++; } @@ -2022,19 +2069,69 @@ private: dwarf->clear_labor(labor); } + } else { + if (state == IDLE) + available_dwarfs.push_back(dwarf); + + if (state == BUSY) + busy_dwarfs.push_back(dwarf); } - else if (state == IDLE || state == BUSY) - available_dwarfs.push_back(dwarf); + } + + } + } + void release_dwarf_list() + { + while (!dwarf_info.empty()) { + auto d = dwarf_info.begin(); + delete *d; + dwarf_info.erase(d); + } + available_dwarfs.clear(); + busy_dwarfs.clear(); + } + + int score_labor (dwarf_info_t* d, df::unit_labor labor) + { + int skill_level = 0; + int xp = 0; + + if (labor != df::unit_labor::NONE) + { + df::job_skill skill = labor_to_skill[labor]; + if (skill != df::job_skill::NONE) + { + skill_level = Units::getEffectiveSkill(d->dwarf, skill); + xp = Units::getExperience(d->dwarf, skill, false); } + } + int score = skill_level * 1000 - (d->high_skill - skill_level) * 2000 + (xp / (skill_level + 5) * 10); + + if (labor != df::unit_labor::NONE) + { + if (d->dwarf->status.labors[labor]) + if (labor == df::unit_labor::OPERATE_PUMP) + score += 50000; + else + score += 1000; + if (default_labor_infos[labor].tool != TOOL_NONE && + d->has_tool[default_labor_infos[labor].tool]) + score += 5000; + if (d->has_children && labor_outside[labor]) + score -= 15000; + if (d->armed && labor_outside[labor]) + score += 5000; } + + return score; } public: void process() { - dwarf_info.clear(); + release_dwarf_list(); dig_count = tree_count = plant_count = detail_count = 0; cnt_recover_wounded = cnt_diagnosis = cnt_immobilize = cnt_dressing = cnt_cleaning = cnt_surgery = cnt_suture = @@ -2106,13 +2203,27 @@ public: labor_needed[df::unit_labor::HAUL_FOOD] += world->stockpile.num_jobs[6]; labor_needed[df::unit_labor::HAUL_REFUSE] += world->stockpile.num_jobs[7]; labor_needed[df::unit_labor::HAUL_FURNITURE] += world->stockpile.num_jobs[8]; - labor_needed[df::unit_labor::HAUL_ANIMAL] += world->stockpile.num_jobs[9]; + labor_needed[df::unit_labor::HAUL_ANIMALS] += world->stockpile.num_jobs[9]; + + labor_needed[df::unit_labor::HAUL_STONE] += (world->stockpile.num_jobs[1] >= world->stockpile.num_haulers[1]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_WOOD] += (world->stockpile.num_jobs[2] >= world->stockpile.num_haulers[2]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_ITEM] += (world->stockpile.num_jobs[3] >= world->stockpile.num_haulers[3]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_BODY] += (world->stockpile.num_jobs[5] >= world->stockpile.num_haulers[5]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_FOOD] += (world->stockpile.num_jobs[6] >= world->stockpile.num_haulers[6]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_REFUSE] += (world->stockpile.num_jobs[7] >= world->stockpile.num_haulers[7]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_FURNITURE] += (world->stockpile.num_jobs[8] >= world->stockpile.num_haulers[8]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_ANIMALS] += (world->stockpile.num_jobs[9] >= world->stockpile.num_haulers[9]) ? 1 : 0; + + int binjobs = world->stockpile.num_jobs[4] + ((world->stockpile.num_jobs[4] >= world->stockpile.num_haulers[4]) ? 1 : 0); + + labor_needed[df::unit_labor::HAUL_ITEM] += binjobs; + labor_needed[df::unit_labor::HAUL_FOOD] += priority_food; // add entries for vehicle hauling for (auto v = world->vehicles.all.begin(); v != world->vehicles.all.end(); v++) if ((*v)->route_id != -1) - labor_needed[df::unit_labor::PUSH_HAUL_VEHICLE]++; + labor_needed[df::unit_labor::HANDLE_VEHICLES]++; // add fishing & hunting @@ -2131,33 +2242,101 @@ public: // note: this doesn't test to see if the trainer is actually needed, and thus will overallocate trainers. bleah. } + /* move idle dwarfs ready to be assigned to busy list */ + for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); ) + { + bool busy = false; + + FOR_ENUM_ITEMS(unit_labor, l) + { + if (l == df::unit_labor::NONE) + continue; + + + if (labor_needed[l] > 0 && (*d)->dwarf->status.labors[l]) + { + busy = true; + labor_needed[l] = max(labor_needed[l]-1, 0); + } + } + + if (busy) + { + busy_dwarfs.push_back(*d); + d = available_dwarfs.erase(d); + } else { + d++; + } + } + /* adjust for over/under */ FOR_ENUM_ITEMS(unit_labor, l) { if (l == df::unit_labor::NONE) continue; - if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMAL) - continue; - if (labor_infos[l].idle_dwarfs > 0 && labor_needed[l] > labor_infos[l].busy_dwarfs) + if (labor_infos[l].idle_dwarfs > 0) + labor_needed[l] = 0; + else + labor_needed[l] = std::max(labor_needed[l] - labor_infos[l].busy_dwarfs, 0); + } + + /* assign food haulers for rotting food items */ + + if (priority_food > 0 && labor_infos[df::unit_labor::HAUL_FOOD].idle_dwarfs > 0) + priority_food = 1; + + if (print_debug) + out.print ("priority food count = %d\n", priority_food); + + while (!available_dwarfs.empty() && priority_food > 0) + { + std::list::iterator bestdwarf = available_dwarfs.begin(); + + int best_score = INT_MIN; + + for (std::list::iterator k = available_dwarfs.begin(); k != available_dwarfs.end(); k++) { - int clawback = labor_infos[l].busy_dwarfs; - if (clawback == 0 && labor_needed[l] > 0) - clawback = 1; + dwarf_info_t* d = (*k); + int score = score_labor(d, df::unit_labor::HAUL_FOOD); + + if (score > best_score) + { + bestdwarf = k; + best_score = score; + } + } + + if (best_score > INT_MIN) + { if (print_debug) - out.print("reducing labor %s to %d (%d needed, %d busy, %d idle)\n", ENUM_KEY_STR(unit_labor, l).c_str(), - clawback, - labor_needed[l], labor_infos[l].busy_dwarfs, labor_infos[l].idle_dwarfs); - labor_needed[l] = clawback; + out.print("LABORMANAGER: assign \"%s\" labor %s score=%d (priority food)\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(unit_labor, df::unit_labor::HAUL_FOOD).c_str(), best_score); + + FOR_ENUM_ITEMS(unit_labor, l) + { + if (l == df::unit_labor::NONE) + continue; + + if (l == df::unit_labor::HAUL_FOOD) + (*bestdwarf)->set_labor(l); + else + (*bestdwarf)->clear_labor(l); + } + + available_dwarfs.erase(bestdwarf); + priority_food--; } + else + break; + } if (print_debug) { for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) { - out.print ("labor_needed [%s] = %d, outside = %d, idle = %d\n", ENUM_KEY_STR(unit_labor, i->first).c_str(), i->second, - labor_outside[i->first], labor_infos[i->first].idle_dwarfs); + out.print ("labor_needed [%s] = %d, busy = %d, outside = %d, idle = %d\n", ENUM_KEY_STR(unit_labor, i->first).c_str(), i->second, + labor_infos[i->first].busy_dwarfs, labor_outside[i->first], labor_infos[i->first].idle_dwarfs); } } @@ -2173,6 +2352,8 @@ public: { int priority = labor_infos[l].priority(); priority += labor_infos[l].time_since_last_assigned()/12; + for (int n = 0; n < labor_infos[l].busy_dwarfs; n++) + priority /= 2; pq.push(make_pair(priority, l)); } } @@ -2212,7 +2393,7 @@ public: (1 << df::unit_labor::HAUL_REFUSE) | (1 << df::unit_labor::HAUL_ITEM) | (1 << df::unit_labor::HAUL_FURNITURE) | - (1 << df::unit_labor::HAUL_ANIMAL); + (1 << df::unit_labor::HAUL_ANIMALS); while (!available_dwarfs.empty()) { @@ -2227,36 +2408,11 @@ public: continue; df::unit_labor labor = j->first; - df::job_skill skill = labor_to_skill[labor]; for (std::list::iterator k = available_dwarfs.begin(); k != available_dwarfs.end(); k++) { dwarf_info_t* d = (*k); - int skill_level = 0; - int xp = 0; - if (skill != df::job_skill::NONE) - { - skill_level = Units::getEffectiveSkill(d->dwarf, skill); - xp = Units::getExperience(d->dwarf, skill, false); - } - int score = skill_level * 1000 - (d->high_skill - skill_level) * 2000 + (xp / (skill_level + 5) * 10); - if (d->dwarf->status.labors[labor]) - if (labor == df::unit_labor::OPERATE_PUMP) - score += 50000; - else - score += 1000; - if (default_labor_infos[labor].tool != TOOL_NONE && - d->has_tool[default_labor_infos[labor].tool]) - score += 5000; - if (d->has_children && labor_outside[labor]) - score -= 15000; - if (d->armed && labor_outside[labor]) - score += 5000; - if (d->state == BUSY) - if (d->using_labor == labor) - score += 7500; - else - score -= 7500; + int score = score_labor(d, labor); if (score > best_score) { bestdwarf = k; @@ -2289,11 +2445,15 @@ public: (*bestdwarf)->clear_labor(l); } - if (best_labor >= df::unit_labor::HAUL_STONE && best_labor <= df::unit_labor::HAUL_ANIMAL) + if (best_labor == df::unit_labor::HAUL_FOOD && priority_food > 0) + priority_food--; + + if (best_labor >= df::unit_labor::HAUL_STONE && best_labor <= df::unit_labor::HAUL_ANIMALS) canary &= ~(1 << best_labor); if (best_labor != df::unit_labor::NONE) { + busy_dwarfs.push_back(*bestdwarf); labor_infos[best_labor].active_dwarfs++; to_assign[best_labor]--; } @@ -2301,17 +2461,71 @@ public: available_dwarfs.erase(bestdwarf); } - if (canary != 0) + for (auto d = busy_dwarfs.begin(); d != busy_dwarfs.end(); d++) { - dwarf_info_t* d = dwarf_info.front(); + int current_score = score_labor (*d, (*d)->using_labor); + FOR_ENUM_ITEMS (unit_labor, l) { - if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMAL && - canary & (1 << l)) - d->set_labor(l); + if (l == df::unit_labor::NONE) + continue; + if (l == (*d)->using_labor) + continue; + if (labor_needed[l] <= 0) + continue; + + int score = score_labor (*d, l); + score += labor_infos[l].time_since_last_assigned()/12; + if (l == df::unit_labor::HAUL_FOOD && priority_food > 0) + score += 1000000; + + if (score > current_score) + { + tools_enum t = default_labor_infos[l].tool; + if (t == TOOL_NONE || (*d)->has_tool[t]) + { + (*d)->set_labor (l); + if (print_debug) + out.print("assign \"%s\" extra labor %s score=%d current %s score=%d\n", + (*d)->dwarf->name.first_name.c_str(), + ENUM_KEY_STR(unit_labor, l).c_str(), score, + ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score); + } + } + else + (*d)->clear_labor (l); + } + } + + + if (canary != 0) + { + dwarf_info_t* d = 0; + + for (auto di = busy_dwarfs.begin(); di != busy_dwarfs.end(); di++) + if (!(*di)->clear_all) + { + d = *di; + break; + } + + if (d) + { + + FOR_ENUM_ITEMS (unit_labor, l) + { + if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && + canary & (1 << l)) + d->set_labor(l); + } + if (print_debug) + out.print ("Setting %s as the hauling canary\n", d->dwarf->name.first_name.c_str()); + } + else + { + if (print_debug) + out.print ("No dwarf available to set as the hauling canary!\n"); } - if (print_debug) - out.print ("Setting %s as the hauling canary\n", d->dwarf->name.first_name.c_str()); } /* set reequip on any dwarfs who are carrying tools needed by others */ @@ -2320,6 +2534,9 @@ public: { FOR_ENUM_ITEMS (unit_labor, l) { + if (l == df::unit_labor::NONE) + continue; + tools_enum t = default_labor_infos[l].tool; if (t != TOOL_NONE && tool_count[t] < 0 && (*d)->has_tool[t] && !(*d)->dwarf->status.labors[l]) { @@ -2329,6 +2546,8 @@ public: } } + release_dwarf_list(); + *df::global::process_jobs = true; print_debug = 0; @@ -2359,7 +2578,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) { static int step_count = 0; // check run conditions - if(!world || !world->map.block_index || !enable_autolabor) + if(!initialized || !world || !world->map.block_index || !enable_labormanager) { // give up if we shouldn't be running' return CR_OK; @@ -2406,26 +2625,26 @@ df::unit_labor lookup_labor_by_name (std::string& name) DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable ) { if (!Core::getInstance().isWorldLoaded()) { - out.printerr("World is not loaded: please load a game first.\n"); + out.printerr("World is not loaded: please load a fort first.\n"); return CR_FAILURE; } - if (enable && !enable_autolabor) + if (enable && !enable_labormanager) { enable_plugin(out); } - else if(!enable && enable_autolabor) + else if(!enable && enable_labormanager) { - enable_autolabor = false; + enable_labormanager = false; setOptionEnabled(CF_ENABLED, false); - out << "Autolabor is disabled." << endl; + out << "LaborManager is disabled." << endl; } return CR_OK; } -command_result autolabor (color_ostream &out, std::vector & parameters) +command_result labormanager (color_ostream &out, std::vector & parameters) { CoreSuspender suspend; @@ -2443,7 +2662,7 @@ command_result autolabor (color_ostream &out, std::vector & parame else if (parameters.size() == 3 && (parameters[0] == "max" || parameters[0] == "priority")) { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2474,7 +2693,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 2 && parameters[0] == "reset") { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2493,7 +2712,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 1 && (parameters[0] == "allow-fishing" || parameters[0] == "forbid-fishing")) { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2504,7 +2723,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 1 && (parameters[0] == "allow-hunting" || parameters[0] == "forbid-hunting")) { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2515,7 +2734,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 1 && parameters[0] == "reset-all") { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2530,7 +2749,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 1 && parameters[0] == "list" || parameters[0] == "status") { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2563,7 +2782,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 1 && parameters[0] == "debug") { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2576,8 +2795,8 @@ command_result autolabor (color_ostream &out, std::vector & parame else { out.print("Automatically assigns labors to dwarves.\n" - "Activate with 'autolabor enable', deactivate with 'autolabor disable'.\n" - "Current state: %s.\n", enable_autolabor ? "enabled" : "disabled"); + "Activate with 'labormanager enable', deactivate with 'labormanager disable'.\n" + "Current state: %s.\n", enable_labormanager ? "enabled" : "disabled"); return CR_OK; } From 61bcfd4bf3b74a833ec43e4b03b748eaedbd178e Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 27 Jun 2016 20:58:38 -0500 Subject: [PATCH 008/413] labormanager improvements Add some debugging facilities. Change some hauling, construction, and deconstruction labors to reflect changes in DF since 34.11. --- plugins/devel/labormanager.cpp | 40 +++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 12e4e8ca1..ffabde36a 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -80,6 +80,7 @@ using df::global::world; DFHACK_PLUGIN_IS_ENABLED(enable_labormanager); static bool print_debug = 0; +static bool pause_on_error = 1; static std::vector state_count(5); @@ -525,8 +526,6 @@ struct dwarf_info_t ~dwarf_info_t() { - if (print_debug) - debug("LABORMANAGER: destroying dwarf %p\n", (void*) this); } @@ -608,7 +607,7 @@ static df::unit_labor hauling_labor_map[] = df::unit_labor::HAUL_FOOD, /* FISH_RAW */ df::unit_labor::HAUL_REFUSE, /* VERMIN */ df::unit_labor::HAUL_ITEM, /* PET */ - df::unit_labor::HAUL_FOOD, /* SEEDS */ + df::unit_labor::HAUL_ITEM, /* SEEDS */ df::unit_labor::HAUL_FOOD, /* PLANT */ df::unit_labor::HAUL_ITEM, /* SKIN_TANNED */ df::unit_labor::HAUL_FOOD, /* LEAVES */ @@ -716,6 +715,14 @@ void debug (char* fmt, ...) } } +void debug_pause () +{ + if (pause_on_error) + { + debug("LABORMANAGER: Game paused so you can investigate the above message.\nUse 'labormanager pause-on-error no' to disable autopausing.\n"); + *df::global::pause_state = true; + } +} class JobLaborMapper { @@ -804,9 +811,10 @@ private: return workshop_build_labor[ws->type]; } break; + case df::building_type::Construction: + return df::unit_labor::BUILD_CONSTRUCTION; case df::building_type::Furnace: case df::building_type::TradeDepot: - case df::building_type::Construction: case df::building_type::Bridge: case df::building_type::ArcheryTarget: case df::building_type::WaterWheel: @@ -870,6 +878,7 @@ private: debug ("LABORMANAGER: Cannot deduce labor for construct building job of type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); + debug_pause(); return df::unit_labor::NONE; } @@ -900,9 +909,10 @@ private: return workshop_build_labor[ws->type]; } break; + case df::building_type::Construction: + return df::unit_labor::REMOVE_CONSTRUCTION; case df::building_type::Furnace: case df::building_type::TradeDepot: - case df::building_type::Construction: case df::building_type::Wagon: case df::building_type::Bridge: case df::building_type::ScrewPump: @@ -964,6 +974,7 @@ private: debug ("LABORMANAGER: Cannot deduce labor for destroy building job of type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); + debug_pause(); return df::unit_labor::NONE; } @@ -998,6 +1009,7 @@ private: else { debug ("LABORMANAGER: Cannot deduce labor for make crafts job (not bone)\n"); + debug_pause(); return df::unit_labor::NONE; } case df::item_type::WOOD: @@ -1005,6 +1017,7 @@ private: default: debug ("LABORMANAGER: Cannot deduce labor for make crafts job, item type %s\n", ENUM_KEY_STR(item_type, jobitem).c_str()); + debug_pause(); return df::unit_labor::NONE; } } @@ -1022,6 +1035,7 @@ private: default: debug ("LABORMANAGER: Cannot deduce labor for make job, workshop type %s\n", ENUM_KEY_STR(workshop_type, type).c_str()); + debug_pause(); return df::unit_labor::NONE; } } @@ -1036,12 +1050,14 @@ private: default: debug ("LABORMANAGER: Cannot deduce labor for make job, furnace type %s\n", ENUM_KEY_STR(furnace_type, type).c_str()); + debug_pause(); return df::unit_labor::NONE; } } debug ("LABORMANAGER: Cannot deduce labor for make job, building type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); + debug_pause(); return df::unit_labor::NONE; } @@ -1382,6 +1398,7 @@ public: if (job_to_labor_table.count(j->job_type) == 0) { debug("LABORMANAGER: job has no job to labor table entry: %s\n", ENUM_KEY_STR(job_type, j->job_type).c_str()); + debug_pause(); labor = df::unit_labor::NONE; } else { @@ -1941,6 +1958,7 @@ private: else { out.print("Dwarf \"%s\" has unknown job %i\n", dwarf->dwarf->name.first_name.c_str(), job); + debug_pause(); state = OTHER; } if (state == BUSY) @@ -2780,6 +2798,18 @@ command_result labormanager (color_ostream &out, std::vector & par return CR_OK; } + else if (parameters.size() == 2 && parameters[0] == "pause-on-error") + { + if (!enable_labormanager) + { + out << "Error: The plugin is not enabled." << endl; + return CR_FAILURE; + } + + pause_on_error = parameters[1] == "yes" || parameters[1] == "true"; + + return CR_OK; + } else if (parameters.size() == 1 && parameters[0] == "debug") { if (!enable_labormanager) From e94804ca9f7a8d594874e942cb66e481e1e46362 Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Tue, 28 Jun 2016 06:53:23 -0500 Subject: [PATCH 009/413] Convince the build system to generate VS2015 project files Signed-off-by: Michael Casadevall --- CMakeLists.txt | 4 ++-- build/build-debug.bat | 4 ++-- build/build-release.bat | 4 ++-- build/generate-MSVC-all-breakfast.bat | 6 +++--- build/generate-MSVC-all.bat | 6 +++--- build/generate-MSVC-gui.bat | 6 +++--- build/generate-MSVC-minimal.bat | 6 +++--- build/generate-MSVC-release.bat | 6 +++--- build/install-debug.bat | 4 ++-- build/install-release.bat | 4 ++-- build/package-debug.bat | 4 ++-- build/package-release.bat | 4 ++-- 12 files changed, 29 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bd89edce..c71cb8c94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,8 +48,8 @@ if(UNIX) endif() if(WIN32) - if((NOT MSVC) OR (NOT MSVC_VERSION STREQUAL 1600)) - message(SEND_ERROR "MSVC 2010 is required") + if((NOT MSVC) OR (NOT MSVC_VERSION STREQUAL 1900)) + message(SEND_ERROR "MSVC 2015 is required") endif() endif() diff --git a/build/build-debug.bat b/build/build-debug.bat index a9492de13..b75676ff4 100644 --- a/build/build-debug.bat +++ b/build/build-debug.bat @@ -1,4 +1,4 @@ -call "%VS100COMNTOOLS%vsvars32.bat" -cd VC2010 +call "%VS140COMNTOOLS%vsvars32.bat" +cd VC2015_32 msbuild /m /p:Platform=Win32 /p:Configuration=RelWithDebInfo ALL_BUILD.vcxproj cd .. \ No newline at end of file diff --git a/build/build-release.bat b/build/build-release.bat index e1ad315e5..0b7a2a407 100644 --- a/build/build-release.bat +++ b/build/build-release.bat @@ -1,5 +1,5 @@ -call "%VS100COMNTOOLS%vsvars32.bat" -cd VC2010 +call "%VS140COMNTOOLS%vsvars32.bat" +cd VC2015_32 msbuild /m /p:Platform=Win32 /p:Configuration=Release ALL_BUILD.vcxproj cd .. pause \ No newline at end of file diff --git a/build/generate-MSVC-all-breakfast.bat b/build/generate-MSVC-all-breakfast.bat index 1921fba6c..4ef5ed677 100644 --- a/build/generate-MSVC-all-breakfast.bat +++ b/build/generate-MSVC-all-breakfast.bat @@ -1,9 +1,9 @@ @echo off IF EXIST DF_PATH.txt SET /P _DF_PATH= Date: Tue, 28 Jun 2016 07:13:18 -0500 Subject: [PATCH 010/413] Backport new hash.h from git upstream to add support for VS2015 Signed-off-by: Michael Casadevall --- depends/protobuf/google/protobuf/stubs/hash.h | 556 ++++++++++++------ 1 file changed, 387 insertions(+), 169 deletions(-) diff --git a/depends/protobuf/google/protobuf/stubs/hash.h b/depends/protobuf/google/protobuf/stubs/hash.h index 822d60501..b4b2da574 100644 --- a/depends/protobuf/google/protobuf/stubs/hash.h +++ b/depends/protobuf/google/protobuf/stubs/hash.h @@ -1,6 +1,6 @@ // Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ +// https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -37,184 +37,402 @@ #include #include -#include "config.h" -#if defined(HAVE_HASH_MAP) && defined(HAVE_HASH_SET) -#include HASH_MAP_H -#include HASH_SET_H +#define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1 +#define GOOGLE_PROTOBUF_HAVE_HASH_SET 1 + +// Android +#if defined(__ANDROID__) +# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP +# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP + +// Use C++11 unordered_{map|set} if available. +#elif ((_LIBCPP_STD_VER >= 11) || \ + (((__cplusplus >= 201103L) || defined(__GXX_EXPERIMENTAL_CXX0X)) && \ + (__GLIBCXX__ > 20090421))) +# define GOOGLE_PROTOBUF_HAS_CXX11_HASH + +// For XCode >= 4.6: the compiler is clang with libc++. +// For earlier XCode version: the compiler is gcc-4.2.1 with libstdc++. +// libc++ provides and friends even in non C++11 mode, +// and it does not provide the tr1 library. Therefore the following macro +// checks against this special case. +// Note that we should not test the __APPLE_CC__ version number or the +// __clang__ macro, since the new compiler can still use -stdlib=libstdc++, in +// which case is not compilable without -std=c++11 +#elif defined(__APPLE_CC__) +# if __GNUC__ >= 4 +# define GOOGLE_PROTOBUF_HAS_TR1 +# else +// Not tested for gcc < 4... These setting can compile under 4.2.1 though. +# define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# endif + +// Version checks for gcc. +#elif defined(__GNUC__) +// For GCC 4.x+, use tr1::unordered_map/set; otherwise, follow the +// instructions from: +// https://gcc.gnu.org/onlinedocs/libstdc++/manual/backwards.html +# if __GNUC__ >= 4 +# define GOOGLE_PROTOBUF_HAS_TR1 +# elif __GNUC__ >= 3 +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# if __GNUC__ == 3 && __GNUC_MINOR__ == 0 +# define GOOGLE_PROTOBUF_HASH_NAMESPACE std // GCC 3.0 +# else +# define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx // GCC 3.1 and later +# endif +# else +# define GOOGLE_PROTOBUF_HASH_NAMESPACE +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# endif + +// Version checks for MSC. +// Apparently Microsoft decided to move hash_map *back* to the std namespace in +// MSVC 2010: +// http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx +// And.. they are moved back to stdext in MSVC 2013 (haven't checked 2012). That +// said, use unordered_map for MSVC 2010 and beyond is our safest bet. +#elif defined(_MSC_VER) +# if _MSC_VER >= 1600 // Since Visual Studio 2010 +# define GOOGLE_PROTOBUF_HAS_CXX11_HASH +# define GOOGLE_PROTOBUF_HASH_COMPARE std::hash_compare +# elif _MSC_VER >= 1500 // Since Visual Studio 2008 +# define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare +# define GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE +# elif _MSC_VER >= 1310 +# define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare +# else +# define GOOGLE_PROTOBUF_HASH_NAMESPACE std +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set +# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare +# endif + +// **ADD NEW COMPILERS SUPPORT HERE.** +// For other compilers, undefine the macro and fallback to use std::map, in +// google/protobuf/stubs/hash.h #else -#define MISSING_HASH -#include -#include +# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP +# undef GOOGLE_PROTOBUF_HAVE_HASH_SET #endif -namespace google { -namespace protobuf { - -#ifdef MISSING_HASH - -// This system doesn't have hash_map or hash_set. Emulate them using map and -// set. - -// Make hash be the same as less. Note that everywhere where custom -// hash functions are defined in the protobuf code, they are also defined such -// that they can be used as "less" functions, which is required by MSVC anyway. -template -struct hash { - // Dummy, just to make derivative hash functions compile. - int operator()(const Key& key) { - GOOGLE_LOG(FATAL) << "Should never be called."; - return 0; - } - - inline bool operator()(const Key& a, const Key& b) const { - return a < b; - } -}; - -// Make sure char* is compared by value. -template <> -struct hash { - // Dummy, just to make derivative hash functions compile. - int operator()(const char* key) { - GOOGLE_LOG(FATAL) << "Should never be called."; - return 0; - } - - inline bool operator()(const char* a, const char* b) const { - return strcmp(a, b) < 0; - } -}; - -template , - typename EqualKey = int > -class hash_map : public std::map { -}; - -template , - typename EqualKey = int > -class hash_set : public std::set { -}; +#if defined(GOOGLE_PROTOBUF_HAS_CXX11_HASH) +# define GOOGLE_PROTOBUF_HASH_NAMESPACE std +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set +#elif defined(GOOGLE_PROTOBUF_HAS_TR1) +# define GOOGLE_PROTOBUF_HASH_NAMESPACE std::tr1 +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set +#endif -#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION) +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \ + namespace google { \ + namespace protobuf { +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }} -template -struct hash : public HASH_NAMESPACE::hash_compare { -}; - -// MSVC's hash_compare hashes based on the string contents but -// compares based on the string pointer. WTF? -class CstringLess { - public: - inline bool operator()(const char* a, const char* b) const { - return strcmp(a, b) < 0; - } -}; - -template <> -struct hash - : public HASH_NAMESPACE::hash_compare { -}; - -template , - typename EqualKey = int > -class hash_map : public HASH_NAMESPACE::hash_map< - Key, Data, HashFcn> { -}; - -template , - typename EqualKey = int > -class hash_set : public HASH_NAMESPACE::hash_set< - Key, HashFcn> { -}; +#undef GOOGLE_PROTOBUF_HAS_CXX11_HASH +#undef GOOGLE_PROTOBUF_HAS_TR1 +#if defined(GOOGLE_PROTOBUF_HAVE_HASH_MAP) && \ + defined(GOOGLE_PROTOBUF_HAVE_HASH_SET) #else +#define GOOGLE_PROTOBUF_MISSING_HASH +#include +#include +#endif -template -struct hash : public HASH_NAMESPACE::hash { -}; - -template -struct hash { - inline size_t operator()(const Key* key) const { - return reinterpret_cast(key); - } -}; - -// Unlike the old SGI version, the TR1 "hash" does not special-case char*. So, -// we go ahead and provide our own implementation. -template <> -struct hash { - inline size_t operator()(const char* str) const { - size_t result = 0; - for (; *str != '\0'; str++) { - result = 5 * result + *str; - } - return result; - } -}; - -template , - typename EqualKey = std::equal_to > -class hash_map : public HASH_NAMESPACE::HASH_MAP_CLASS< - Key, Data, HashFcn, EqualKey> { -}; - -template , - typename EqualKey = std::equal_to > -class hash_set : public HASH_NAMESPACE::HASH_SET_CLASS< - Key, HashFcn, EqualKey> { -}; +namespace google { + namespace protobuf { + +#ifdef GOOGLE_PROTOBUF_MISSING_HASH +#undef GOOGLE_PROTOBUF_MISSING_HASH + + // This system doesn't have hash_map or hash_set. Emulate them using map and + // set. + + // Make hash be the same as less. Note that everywhere where custom + // hash functions are defined in the protobuf code, they are also defined such + // that they can be used as "less" functions, which is required by MSVC anyway. + template + struct hash { + // Dummy, just to make derivative hash functions compile. + int operator()(const Key& key) { + GOOGLE_LOG(FATAL) << "Should never be called."; + return 0; + } + + inline bool operator()(const Key& a, const Key& b) const { + return a < b; + } + }; + + // Make sure char* is compared by value. + template <> + struct hash { + // Dummy, just to make derivative hash functions compile. + int operator()(const char* key) { + GOOGLE_LOG(FATAL) << "Should never be called."; + return 0; + } + + inline bool operator()(const char* a, const char* b) const { + return strcmp(a, b) < 0; + } + }; + + template , + typename EqualKey = std::equal_to, + typename Alloc = std::allocator< std::pair > > + class hash_map : public std::map { + typedef std::map BaseClass; + + public: + hash_map(int a = 0, const HashFcn& b = HashFcn(), + const EqualKey& c = EqualKey(), + const Alloc& d = Alloc()) : BaseClass(b, d) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + + template , + typename EqualKey = std::equal_to > + class hash_set : public std::set { + public: + hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } + }; -#endif +#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION) -template <> -struct hash { - inline size_t operator()(const string& key) const { - return hash()(key.c_str()); - } - - static const size_t bucket_size = 4; - static const size_t min_buckets = 8; - inline size_t operator()(const string& a, const string& b) const { - return a < b; - } -}; - -template -struct hash > { - inline size_t operator()(const pair& key) const { - size_t first_hash = hash()(key.first); - size_t second_hash = hash()(key.second); - - // FIXME(kenton): What is the best way to compute this hash? I have - // no idea! This seems a bit better than an XOR. - return first_hash * ((1 << 16) - 1) + second_hash; - } - - static const size_t bucket_size = 4; - static const size_t min_buckets = 8; - inline size_t operator()(const pair& a, - const pair& b) const { - return a < b; - } -}; - -// Used by GCC/SGI STL only. (Why isn't this provided by the standard -// library? :( ) -struct streq { - inline bool operator()(const char* a, const char* b) const { - return strcmp(a, b) == 0; - } -}; - -} // namespace protobuf + template + struct hash : public GOOGLE_PROTOBUF_HASH_COMPARE { + }; + + // MSVC's hash_compare hashes based on the string contents but + // compares based on the string pointer. WTF? + class CstringLess { + public: + inline bool operator()(const char* a, const char* b) const { + return strcmp(a, b) < 0; + } + }; + + template <> + struct hash + : public GOOGLE_PROTOBUF_HASH_COMPARE {}; + +#ifdef GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE + + template + struct InternalHashCompare : public GOOGLE_PROTOBUF_HASH_COMPARE { + InternalHashCompare() {} + InternalHashCompare(HashFcn hashfcn, EqualKey equalkey) + : hashfcn_(hashfcn), equalkey_(equalkey) {} + size_t operator()(const Key& key) const { return hashfcn_(key); } + bool operator()(const Key& key1, const Key& key2) const { + return !equalkey_(key1, key2); + } + HashFcn hashfcn_; + EqualKey equalkey_; + }; + + template , + typename EqualKey = std::equal_to, + typename Alloc = std::allocator< std::pair > > + class hash_map + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, InternalHashCompare, Alloc> { + typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, InternalHashCompare, Alloc> BaseClass; + + public: + hash_map(int a = 0, const HashFcn& b = HashFcn(), + const EqualKey& c = EqualKey(), const Alloc& d = Alloc()) + : BaseClass(InternalHashCompare(b, c), d) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + + template , + typename EqualKey = std::equal_to > + class hash_set + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS< + Key, InternalHashCompare > { + public: + hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + +#else // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE + + template , + typename EqualKey = std::equal_to, + typename Alloc = std::allocator< std::pair > > + class hash_map + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, HashFcn, EqualKey, Alloc> { + typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, HashFcn, EqualKey, Alloc> BaseClass; + + public: + hash_map(int a = 0, const HashFcn& b = HashFcn(), + const EqualKey& c = EqualKey(), + const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + + template , + typename EqualKey = std::equal_to > + class hash_set + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS< + Key, HashFcn, EqualKey> { + public: + hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } + }; +#endif // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE + +#else // defined(_MSC_VER) && !defined(_STLPORT_VERSION) + + template + struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash { + }; + + template + struct hash { + inline size_t operator()(const Key* key) const { + return reinterpret_cast(key); + } + }; + + // Unlike the old SGI version, the TR1 "hash" does not special-case char*. So, + // we go ahead and provide our own implementation. + template <> + struct hash { + inline size_t operator()(const char* str) const { + size_t result = 0; + for (; *str != '\0'; str++) { + result = 5 * result + *str; + } + return result; + } + }; + + template<> + struct hash { + size_t operator()(bool x) const { + return static_cast(x); + } + }; + + template , + typename EqualKey = std::equal_to, + typename Alloc = std::allocator< std::pair > > + class hash_map + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, HashFcn, EqualKey, Alloc> { + typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< + Key, Data, HashFcn, EqualKey, Alloc> BaseClass; + + public: + hash_map(int a = 0, const HashFcn& b = HashFcn(), + const EqualKey& c = EqualKey(), + const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + + template , + typename EqualKey = std::equal_to > + class hash_set + : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS< + Key, HashFcn, EqualKey> { + public: + hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } + }; + +#endif // !GOOGLE_PROTOBUF_MISSING_HASH + + template <> + struct hash { + inline size_t operator()(const string& key) const { + return hash()(key.c_str()); + } + + static const size_t bucket_size = 4; + static const size_t min_buckets = 8; + inline bool operator()(const string& a, const string& b) const { + return a < b; + } + }; + + template + struct hash > { + inline size_t operator()(const pair& key) const { + size_t first_hash = hash()(key.first); + size_t second_hash = hash()(key.second); + + // FIXME(kenton): What is the best way to compute this hash? I have + // no idea! This seems a bit better than an XOR. + return first_hash * ((1 << 16) - 1) + second_hash; + } + + static const size_t bucket_size = 4; + static const size_t min_buckets = 8; + inline bool operator()(const pair& a, + const pair& b) const { + return a < b; + } + }; + + // Used by GCC/SGI STL only. (Why isn't this provided by the standard + // library? :( ) + struct streq { + inline bool operator()(const char* a, const char* b) const { + return strcmp(a, b) == 0; + } + }; + + } // namespace protobuf } // namespace google -#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__ +#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__ \ No newline at end of file From c3188b1d6cce63b71f7fc5992bb0c47ce2dd9a61 Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Tue, 28 Jun 2016 07:13:46 -0500 Subject: [PATCH 011/413] Make our build checks relate to the new compiler world order (thanks lethosor) Signed-off-by: Michael Casadevall --- depends/protobuf/CMakeLists.txt | 92 +++++++++++++++------------------ 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index 4fec34125..085af746f 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -13,68 +13,62 @@ IF(CMAKE_COMPILER_IS_GNUCC) #ENDIF() SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") - SET(HAVE_HASH_MAP 0) - SET(HASH_MAP_CLASS unordered_map) +ENDIF() + +SET(HAVE_HASH_MAP 0) +SET(HASH_MAP_CLASS unordered_map) - #Check for all of the possible combinations of unordered_map and hash_map +#Check for all of the possible combinations of unordered_map and hash_map - FOREACH(header tr1/unordered_map unordered_map) - FOREACH(namespace std::tr1 std ) - IF(HAVE_HASH_MAP EQUAL 0 AND NOT STL_HASH_OLD_GCC) +FOREACH(header tr1/unordered_map unordered_map) + FOREACH(namespace std::tr1 std ) + IF(HAVE_HASH_MAP EQUAL 0 AND NOT STL_HASH_OLD_GCC) + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") + IF(CMAKE_CROSSCOMPILING) + TRY_COMPILE(HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") + SET(HASH_MAP_RUN_RESULT ${HASH_MAP_COMPILE_RESULT}) + ELSE() + TRY_RUN(HASH_MAP_RUN_RESULT HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") + ENDIF() + IF (HASH_MAP_COMPILE_RESULT AND HASH_MAP_RUN_RESULT EQUAL 1) + SET(HASH_MAP_H <${header}>) + STRING(REPLACE "map" "set" HASH_SET_H ${HASH_MAP_H}) + SET(HASH_NAMESPACE ${namespace}) + SET(HASH_MAP_CLASS unordered_map) + SET(HASH_SET_CLASS unordered_set) + SET(HAVE_HASH_MAP 1) + SET(HAVE_HASH_SET 1) + ENDIF() + ENDIF() + ENDFOREACH(namespace) +ENDFOREACH(header) +IF (HAVE_HASH_MAP EQUAL 0) + SET(HASH_MAP_CLASS hash_map) + FOREACH(header ext/hash_map hash_map) + FOREACH(namespace __gnu_cxx "" std stdext) + IF (HAVE_HASH_MAP EQUAL 0) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") - IF(CMAKE_CROSSCOMPILING) - TRY_COMPILE(HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") - SET(HASH_MAP_RUN_RESULT ${HASH_MAP_COMPILE_RESULT}) - ELSE() - TRY_RUN(HASH_MAP_RUN_RESULT HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") - ENDIF() - IF (HASH_MAP_COMPILE_RESULT AND HASH_MAP_RUN_RESULT EQUAL 1) + TRY_COMPILE(HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") + IF (HASH_MAP_COMPILE_RESULT) SET(HASH_MAP_H <${header}>) STRING(REPLACE "map" "set" HASH_SET_H ${HASH_MAP_H}) SET(HASH_NAMESPACE ${namespace}) - SET(HASH_MAP_CLASS unordered_map) - SET(HASH_SET_CLASS unordered_set) + SET(HASH_MAP_CLASS hash_map) + SET(HASH_SET_CLASS hash_set) SET(HAVE_HASH_MAP 1) SET(HAVE_HASH_SET 1) ENDIF() ENDIF() - ENDFOREACH(namespace) - ENDFOREACH(header) - IF (HAVE_HASH_MAP EQUAL 0) - SET(HASH_MAP_CLASS hash_map) - FOREACH(header ext/hash_map hash_map) - FOREACH(namespace __gnu_cxx "" std stdext) - IF (HAVE_HASH_MAP EQUAL 0) - CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") - TRY_COMPILE(HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") - IF (HASH_MAP_COMPILE_RESULT) - SET(HASH_MAP_H <${header}>) - STRING(REPLACE "map" "set" HASH_SET_H ${HASH_MAP_H}) - SET(HASH_NAMESPACE ${namespace}) - SET(HASH_MAP_CLASS hash_map) - SET(HASH_SET_CLASS hash_set) - SET(HAVE_HASH_MAP 1) - SET(HAVE_HASH_SET 1) - ENDIF() - ENDIF() - ENDFOREACH() ENDFOREACH() - ENDIF() + ENDFOREACH() +ENDIF() - IF (HAVE_HASH_MAP EQUAL 0) - MESSAGE(SEND_ERROR "Could not find a working hash map implementation. Please install GCC >= 4.4, and all necessary 32-bit C++ development libraries.") - ENDIF() +IF (HAVE_HASH_MAP EQUAL 0) + MESSAGE(SEND_ERROR "Could not find a working hash map implementation. Please install GCC >= 4.4, and all necessary 32-bit C++ development libraries.") +ENDIF() +IF(UNIX) FIND_PACKAGE(Threads) - -ELSE() - SET(HASH_MAP_H ) - SET(HASH_NAMESPACE std) - SET(HASH_SET_H ) - SET(HAVE_HASH_MAP 1) - SET(HAVE_HASH_SET 1) - SET(HASH_MAP_CLASS hash_map) - SET(HASH_SET_CLASS hash_set) ENDIF() CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h") @@ -250,4 +244,4 @@ IF(NOT CMAKE_CROSSCOMPILING) TARGET_LINK_LIBRARIES(protoc-bin protoc) EXPORT(TARGETS protoc-bin FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake ) -ENDIF() +ENDIF() \ No newline at end of file From d49032ef73210942a442b3f1109258178f38fafe Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Tue, 28 Jun 2016 08:34:11 -0500 Subject: [PATCH 012/413] Supress a lot of compiler noise in hopes of finding real errors. Right now, a plugin free DFHack can be built with VS2015 --- CMakeLists.txt | 9 +++++++++ library/include/Error.h | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c71cb8c94..ffc379724 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,15 @@ endif() if(MSVC) # disable C4819 code-page warning add_definitions( "/wd4819" ) + +# Disable use of POSIX name warnings +add_definitions ( "/D_CRT_NONSTDC_NO_WARNINGS") + +# supress C4503 - VC++ dislikes if a name is too long. If you get +# weird and mysterious linking errors, you can disable this, but you'll have to +# deal with a LOT of compiler noise over it +# see https://msdn.microsoft.com/en-us/library/074af4b6.aspx +add_definitions( "/wd4503") endif() IF(CMAKE_CROSSCOMPILING) diff --git a/library/include/Error.h b/library/include/Error.h index 4e3ff269c..4e3224f49 100644 --- a/library/include/Error.h +++ b/library/include/Error.h @@ -38,8 +38,18 @@ namespace DFHack * our wrapper for the C++ exception. used to differentiate * the whole array of DFHack exceptions from the rest */ - class DFHACK_EXPORT All : public std::exception{}; - +#ifdef _MSC_VER +#pragma push +/** + * C4275 is - The warning officially is non dll-interface class 'std::exception' used as base for + * dll-interface class + * + * Basically, its saying that you might have an ABI problem if you mismatch compilers. We don't + * care since we build all of DFhack at once against whatever Toady is using + */ +#pragma warning(disable: 4275) + class DFHACK_EXPORT All : public std::exception{}; +#endif class DFHACK_EXPORT NullPointer : public All { const char *varname_; public: From d509cf2fb507aa243286f0aac98ac776fdc2163b Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Tue, 28 Jun 2016 09:39:46 -0500 Subject: [PATCH 013/413] It helps when you pop pragmas Signed-off-by: Michael Casadevall --- library/include/Error.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/include/Error.h b/library/include/Error.h index 4e3224f49..1c8afe44c 100644 --- a/library/include/Error.h +++ b/library/include/Error.h @@ -48,7 +48,10 @@ namespace DFHack * care since we build all of DFhack at once against whatever Toady is using */ #pragma warning(disable: 4275) +#endif class DFHACK_EXPORT All : public std::exception{}; +#ifdef _MSC_VER +#pragma pop #endif class DFHACK_EXPORT NullPointer : public All { const char *varname_; From b516c8e0dcb18d3f1e8cf2e957351803e14bd509 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 28 Jun 2016 22:36:45 -0500 Subject: [PATCH 014/413] labormanager: more tweaks to bring up to date This update fixes some labors and attempts to address changes in the way DF maintains the job list. --- plugins/devel/labormanager.cpp | 155 +++++++++++++++------------------ 1 file changed, 72 insertions(+), 83 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index ffabde36a..256841cb7 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -1154,7 +1154,7 @@ public: job_to_labor_table[df::job_type::GatherPlants] = jlf_const(df::unit_labor::HERBALIST); job_to_labor_table[df::job_type::RemoveConstruction] = jlf_no_labor; job_to_labor_table[df::job_type::CollectWebs] = jlf_const(df::unit_labor::WEAVER); - job_to_labor_table[df::job_type::BringItemToDepot] = jlf_no_labor; + job_to_labor_table[df::job_type::BringItemToDepot] = jlf_const(df::unit_labor::HAUL_TRADE); job_to_labor_table[df::job_type::BringItemToShop] = jlf_no_labor; job_to_labor_table[df::job_type::Eat] = jlf_no_labor; job_to_labor_table[df::job_type::GetProvisions] = jlf_no_labor; @@ -1178,13 +1178,13 @@ public: job_to_labor_table[df::job_type::CheckChest] = jlf_no_labor; job_to_labor_table[df::job_type::StoreOwnedItem] = jlf_no_labor; job_to_labor_table[df::job_type::PlaceItemInTomb] = jlf_const(df::unit_labor::HAUL_BODY); - job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInBag] = jlf_hauling; + job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list + job_to_labor_table[df::job_type::StoreItemInBag] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list job_to_labor_table[df::job_type::StoreItemInHospital] = jlf_hauling; job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling; job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInBin] = jlf_const(df::unit_labor::HAUL_ITEM); + job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list + job_to_labor_table[df::job_type::StoreItemInBin] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list job_to_labor_table[df::job_type::SeekArtifact] = jlf_no_labor; job_to_labor_table[df::job_type::SeekInfant] = jlf_no_labor; job_to_labor_table[df::job_type::AttendParty] = jlf_no_labor; @@ -1293,14 +1293,14 @@ public: job_to_labor_table[df::job_type::TameVermin] = jlf_const(df::unit_labor::ANIMALTRAIN) ; job_to_labor_table[df::job_type::TameAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN) ; job_to_labor_table[df::job_type::ChainAnimal] = jlf_no_labor; - job_to_labor_table[df::job_type::UnchainAnimal] = jlf_no_labor; + job_to_labor_table[df::job_type::UnchainAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::UnchainPet] = jlf_no_labor; - job_to_labor_table[df::job_type::ReleaseLargeCreature] = jlf_no_labor; + job_to_labor_table[df::job_type::ReleaseLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::ReleasePet] = jlf_no_labor; job_to_labor_table[df::job_type::ReleaseSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::HandleSmallCreature] = jlf_no_labor; - job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_no_labor; - job_to_labor_table[df::job_type::CageLargeCreature] = jlf_no_labor; + job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); + job_to_labor_table[df::job_type::CageLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::CageSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::RecoverWounded] = jlf_const(df::unit_labor::RECOVER_WOUNDED); job_to_labor_table[df::job_type::DiagnosePatient] = jlf_const(df::unit_labor::DIAGNOSE) ; @@ -1640,6 +1640,7 @@ private: int priority_food; std::map labor_needed; + std::map labor_in_use; std::map labor_outside; std::vector dwarf_info; std::list available_dwarfs; @@ -1668,6 +1669,7 @@ private: { df::building_tradedepotst* depot = (df::building_tradedepotst*) build; trader_requested = depot->trade_flags.bits.trader_requested; + if (print_debug) { if (trader_requested) @@ -1819,20 +1821,23 @@ private: } df::unit_labor labor = labor_mapper->find_job_labor (j); + labor_needed[labor]++; if (labor != df::unit_labor::NONE) { - labor_needed[labor]++; - - if (worker != -1) + if (worker == -1) + { + if (j->pos.isValid()) + { + df::tile_designation* d = Maps::getTileDesignation(j->pos); + if (d->bits.outside) + labor_outside[labor] = true; + } + } else { labor_infos[labor].mark_assigned(); + labor_in_use[labor]++; + } - if (j->pos.isValid()) - { - df::tile_designation* d = Maps::getTileDesignation(j->pos); - if (d->bits.outside) - labor_outside[labor] = true; - } } } @@ -1979,8 +1984,6 @@ private: } } } - if (state == OTHER) - dwarf->clear_all = true; } dwarf->state = state; @@ -2199,7 +2202,7 @@ public: // add job entries for health care labor_needed[df::unit_labor::RECOVER_WOUNDED] += cnt_recover_wounded; - labor_needed[df::unit_labor::DIAGNOSE] += cnt_diagnosis; + labor_needed[df::unit_labor::DIAGNOSE] += cnt_diagnosis; labor_needed[df::unit_labor::BONE_SETTING] += cnt_immobilize; labor_needed[df::unit_labor::DRESSING_WOUNDS] += cnt_dressing; labor_needed[df::unit_labor::DRESSING_WOUNDS] += cnt_cleaning; @@ -2260,43 +2263,14 @@ public: // note: this doesn't test to see if the trainer is actually needed, and thus will overallocate trainers. bleah. } - /* move idle dwarfs ready to be assigned to busy list */ - for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); ) - { - bool busy = false; + /* set requirements to zero for labors with currently idle dwarfs, and remove from requirement dwarfs actually working */ - FOR_ENUM_ITEMS(unit_labor, l) - { - if (l == df::unit_labor::NONE) - continue; - - - if (labor_needed[l] > 0 && (*d)->dwarf->status.labors[l]) - { - busy = true; - labor_needed[l] = max(labor_needed[l]-1, 0); - } - } - - if (busy) - { - busy_dwarfs.push_back(*d); - d = available_dwarfs.erase(d); - } else { - d++; - } - } - - /* adjust for over/under */ - FOR_ENUM_ITEMS(unit_labor, l) - { - if (l == df::unit_labor::NONE) - continue; - if (labor_infos[l].idle_dwarfs > 0) - labor_needed[l] = 0; - else - labor_needed[l] = std::max(labor_needed[l] - labor_infos[l].busy_dwarfs, 0); - } + FOR_ENUM_ITEMS(unit_labor, l) { + if (labor_infos[l].idle_dwarfs > 0) + labor_needed[l] = 0; + else + labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); + } /* assign food haulers for rotting food items */ @@ -2401,7 +2375,6 @@ public: priority /= 2; pq.push(make_pair(priority, labor)); } - } int canary = (1 << df::unit_labor::HAUL_STONE) | @@ -2476,6 +2449,7 @@ public: to_assign[best_labor]--; } + busy_dwarfs.push_back(*bestdwarf); available_dwarfs.erase(bestdwarf); } @@ -2510,42 +2484,57 @@ public: ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score); } } - else - (*d)->clear_labor (l); } } - if (canary != 0) - { - dwarf_info_t* d = 0; - - for (auto di = busy_dwarfs.begin(); di != busy_dwarfs.end(); di++) - if (!(*di)->clear_all) - { - d = *di; - break; - } + dwarf_info_t* canary_dwarf = 0; - if (d) + for (auto di = busy_dwarfs.begin(); di != busy_dwarfs.end(); di++) + if (!(*di)->clear_all) { - - FOR_ENUM_ITEMS (unit_labor, l) - { - if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && - canary & (1 << l)) - d->set_labor(l); - } - if (print_debug) - out.print ("Setting %s as the hauling canary\n", d->dwarf->name.first_name.c_str()); + canary_dwarf = *di; + break; } - else + + if (canary_dwarf) + { + + FOR_ENUM_ITEMS (unit_labor, l) { - if (print_debug) - out.print ("No dwarf available to set as the hauling canary!\n"); + if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && + canary & (1 << l)) + canary_dwarf->set_labor(l); } + + /* Also set the canary to remove constructions, because we have no way yet to tell if there are constructions needing removal */ + + canary_dwarf->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); + + if (print_debug) + out.print ("Setting %s as the hauling canary\n", canary_dwarf->dwarf->name.first_name.c_str()); + } + else + { + if (print_debug) + out.print ("No dwarf available to set as the hauling canary!\n"); } + /* Assign any leftover dwarfs to "standard" labors */ + + for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); d++) + { + FOR_ENUM_ITEMS (unit_labor, l) + { + if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && + canary & (1 << l)) + (*d)->set_labor(l); + } + + (*d)->set_labor(df::unit_labor::CLEAN); + (*d)->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); + } + /* set reequip on any dwarfs who are carrying tools needed by others */ for (auto d = dwarf_info.begin(); d != dwarf_info.end(); d++) From 1927eda6f33aa813da94eaeceb1bfc1db4111d3d Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 28 Jun 2016 22:57:12 -0500 Subject: [PATCH 015/413] labormanager: whitespace MSVC is evil. --- plugins/devel/labormanager.cpp | 60 +++++++++++++++++----------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 256841cb7..8acae7524 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -1299,7 +1299,7 @@ public: job_to_labor_table[df::job_type::ReleasePet] = jlf_no_labor; job_to_labor_table[df::job_type::ReleaseSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::HandleSmallCreature] = jlf_no_labor; - job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); + job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::CageLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::CageSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::RecoverWounded] = jlf_const(df::unit_labor::RECOVER_WOUNDED); @@ -1640,7 +1640,7 @@ private: int priority_food; std::map labor_needed; - std::map labor_in_use; + std::map labor_in_use; std::map labor_outside; std::vector dwarf_info; std::list available_dwarfs; @@ -1821,22 +1821,22 @@ private: } df::unit_labor labor = labor_mapper->find_job_labor (j); - labor_needed[labor]++; + labor_needed[labor]++; if (labor != df::unit_labor::NONE) { - if (worker == -1) - { - if (j->pos.isValid()) - { - df::tile_designation* d = Maps::getTileDesignation(j->pos); - if (d->bits.outside) - labor_outside[labor] = true; - } - } else { + if (worker == -1) + { + if (j->pos.isValid()) + { + df::tile_designation* d = Maps::getTileDesignation(j->pos); + if (d->bits.outside) + labor_outside[labor] = true; + } + } else { labor_infos[labor].mark_assigned(); - labor_in_use[labor]++; - } + labor_in_use[labor]++; + } } } @@ -2263,14 +2263,14 @@ public: // note: this doesn't test to see if the trainer is actually needed, and thus will overallocate trainers. bleah. } - /* set requirements to zero for labors with currently idle dwarfs, and remove from requirement dwarfs actually working */ + /* set requirements to zero for labors with currently idle dwarfs, and remove from requirement dwarfs actually working */ - FOR_ENUM_ITEMS(unit_labor, l) { - if (labor_infos[l].idle_dwarfs > 0) - labor_needed[l] = 0; - else - labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); - } + FOR_ENUM_ITEMS(unit_labor, l) { + if (labor_infos[l].idle_dwarfs > 0) + labor_needed[l] = 0; + else + labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); + } /* assign food haulers for rotting food items */ @@ -2449,7 +2449,7 @@ public: to_assign[best_labor]--; } - busy_dwarfs.push_back(*bestdwarf); + busy_dwarfs.push_back(*bestdwarf); available_dwarfs.erase(bestdwarf); } @@ -2507,9 +2507,9 @@ public: canary_dwarf->set_labor(l); } - /* Also set the canary to remove constructions, because we have no way yet to tell if there are constructions needing removal */ + /* Also set the canary to remove constructions, because we have no way yet to tell if there are constructions needing removal */ - canary_dwarf->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); + canary_dwarf->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); if (print_debug) out.print ("Setting %s as the hauling canary\n", canary_dwarf->dwarf->name.first_name.c_str()); @@ -2520,10 +2520,10 @@ public: out.print ("No dwarf available to set as the hauling canary!\n"); } - /* Assign any leftover dwarfs to "standard" labors */ + /* Assign any leftover dwarfs to "standard" labors */ - for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); d++) - { + for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); d++) + { FOR_ENUM_ITEMS (unit_labor, l) { if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && @@ -2531,9 +2531,9 @@ public: (*d)->set_labor(l); } - (*d)->set_labor(df::unit_labor::CLEAN); - (*d)->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); - } + (*d)->set_labor(df::unit_labor::CLEAN); + (*d)->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); + } /* set reequip on any dwarfs who are carrying tools needed by others */ From b45fb7c5640b1ddc6ef8360ec965876a3f5f6f2e Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 28 Jun 2016 23:28:44 -0500 Subject: [PATCH 016/413] labormanager: fix stupid --- plugins/devel/labormanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 8acae7524..d78d06b97 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -2337,6 +2337,9 @@ public: for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) { df::unit_labor l = i->first; + if (l == df::unit_labor::NONE) + continue; + if (labor_infos[l].maximum_dwarfs() > 0 && i->second > labor_infos[l].maximum_dwarfs()) i->second = labor_infos[l].maximum_dwarfs(); From 857058752ba56321024e08244dd004347ad55cf5 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Wed, 29 Jun 2016 14:54:03 -0500 Subject: [PATCH 017/413] labormanager: rework for better behavior with 43.03 The main thing here is that the process loop exits if the DF process_job or process_dig flags are set since if these are set the job list is going to change soon anyway. The plugin also sets these flags when it changes any labors, which has the side effect of effectively disabling the process loop while DF is paused, which prevents flapping while editing job preferences in-game, and also allows changing job preferences in game (although such changes may not last when the clock starts up again). --- plugins/devel/labormanager.cpp | 78 +++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index d78d06b97..8d614ed36 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -528,23 +528,6 @@ struct dwarf_info_t { } - - void set_labor(df::unit_labor labor) - { - if (labor >= 0 && labor <= ENUM_LAST_ITEM(unit_labor)) - { - dwarf->status.labors[labor] = true; - } - } - - void clear_labor(df::unit_labor labor) - { - if (labor >= 0 && labor <= ENUM_LAST_ITEM(unit_labor)) - { - dwarf->status.labors[labor] = false; - } - } - }; /* @@ -1621,6 +1604,8 @@ private: int plant_count; int detail_count; + bool labors_changed; + int tool_count[TOOLS_MAX]; bool reequip_needed[TOOLS_MAX]; @@ -1647,11 +1632,23 @@ private: std::list busy_dwarfs; private: + void set_labor (dwarf_info_t* dwarf, df::unit_labor labor, bool value) + { + if (labor >= 0 && labor <= ENUM_LAST_ITEM(unit_labor)) + { + bool old = dwarf->dwarf->status.labors[labor]; + dwarf->dwarf->status.labors[labor] = value; + if (old != value) + labors_changed = true; + } + } + void scan_buildings() { has_butchers = false; has_fishery = false; trader_requested = false; + labors_changed = false; for (auto b = world->buildings.all.begin(); b != world->buildings.all.end(); b++) { @@ -1821,10 +1818,10 @@ private: } df::unit_labor labor = labor_mapper->find_job_labor (j); - labor_needed[labor]++; if (labor != df::unit_labor::NONE) { + labor_needed[labor]++; if (worker == -1) { if (j->pos.isValid()) @@ -2088,7 +2085,7 @@ private: if (labor == unit_labor::NONE) continue; - dwarf->clear_labor(labor); + set_labor(dwarf, labor, false); } } else { if (state == IDLE) @@ -2152,6 +2149,9 @@ private: public: void process() { + if (*df::global::process_dig || *df::global::process_jobs) + return; + release_dwarf_list(); dig_count = tree_count = plant_count = detail_count = 0; @@ -2266,6 +2266,9 @@ public: /* set requirements to zero for labors with currently idle dwarfs, and remove from requirement dwarfs actually working */ FOR_ENUM_ITEMS(unit_labor, l) { + if (l == df::unit_labor::NONE) + continue; + if (labor_infos[l].idle_dwarfs > 0) labor_needed[l] = 0; else @@ -2309,10 +2312,7 @@ public: if (l == df::unit_labor::NONE) continue; - if (l == df::unit_labor::HAUL_FOOD) - (*bestdwarf)->set_labor(l); - else - (*bestdwarf)->clear_labor(l); + set_labor (*bestdwarf, l, l == df::unit_labor::HAUL_FOOD); } available_dwarfs.erase(bestdwarf); @@ -2337,7 +2337,7 @@ public: for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) { df::unit_labor l = i->first; - if (l == df::unit_labor::NONE) + if (l == df::unit_labor::NONE) continue; if (labor_infos[l].maximum_dwarfs() > 0 && @@ -2394,7 +2394,7 @@ public: std::list::iterator bestdwarf = available_dwarfs.begin(); int best_score = INT_MIN; - df::unit_labor best_labor = df::unit_labor::CLEAN; + df::unit_labor best_labor = df::unit_labor::NONE; for (auto j = to_assign.begin(); j != to_assign.end(); j++) { @@ -2416,6 +2416,9 @@ public: } } + if (best_labor == df::unit_labor::NONE) + break; + if (print_debug) out.print("assign \"%s\" labor %s score=%d\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(unit_labor, best_labor).c_str(), best_score); @@ -2426,7 +2429,7 @@ public: if (l == best_labor) { - (*bestdwarf)->set_labor(l); + set_labor(*bestdwarf, l, true); tools_enum t = default_labor_infos[l].tool; if (t != TOOL_NONE) { @@ -2436,7 +2439,7 @@ public: } } else if ((*bestdwarf)->state == IDLE) - (*bestdwarf)->clear_labor(l); + set_labor(*bestdwarf, l, false); } if (best_labor == df::unit_labor::HAUL_FOOD && priority_food > 0) @@ -2479,7 +2482,7 @@ public: tools_enum t = default_labor_infos[l].tool; if (t == TOOL_NONE || (*d)->has_tool[t]) { - (*d)->set_labor (l); + set_labor(*d, l, true); if (print_debug) out.print("assign \"%s\" extra labor %s score=%d current %s score=%d\n", (*d)->dwarf->name.first_name.c_str(), @@ -2507,12 +2510,12 @@ public: { if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && canary & (1 << l)) - canary_dwarf->set_labor(l); + set_labor(canary_dwarf, l, true); } /* Also set the canary to remove constructions, because we have no way yet to tell if there are constructions needing removal */ - canary_dwarf->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); + set_labor(canary_dwarf, df::unit_labor::REMOVE_CONSTRUCTION, true); if (print_debug) out.print ("Setting %s as the hauling canary\n", canary_dwarf->dwarf->name.first_name.c_str()); @@ -2531,11 +2534,12 @@ public: { if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && canary & (1 << l)) - (*d)->set_labor(l); + set_labor(*d, l, true); + else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION) + set_labor(*d, l, true); + else + set_labor(*d, l, false); } - - (*d)->set_labor(df::unit_labor::CLEAN); - (*d)->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); } /* set reequip on any dwarfs who are carrying tools needed by others */ @@ -2558,7 +2562,11 @@ public: release_dwarf_list(); - *df::global::process_jobs = true; + if (labors_changed) + { + *df::global::process_dig = true; + *df::global::process_jobs = true; + } print_debug = 0; From d8f4d79b977c126d18201f3875f724731d40acc0 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 30 Jun 2016 23:58:56 -0500 Subject: [PATCH 018/413] labormanager: significant restructuring to use job posting list Updated here to get potential jobs off the job posting lists, which is apparently where certain map-designated live after being designated but before they move to the actual job list. Also changes to how tools are handled, and lever pulling is assigned by default to all idle dwarfs. --- plugins/devel/labormanager.cpp | 273 ++++++++++++++++++++------------- 1 file changed, 169 insertions(+), 104 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 8d614ed36..545ca7f1c 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -184,7 +184,7 @@ static const dwarf_state dwarf_states[] = { OTHER /* GoShopping2 */, BUSY /* Clean */, OTHER /* Rest */, - BUSY /* PickupEquipment */, + OTHER /* PickupEquipment */, BUSY /* DumpItem */, OTHER /* StrangeMoodCrafter */, OTHER /* StrangeMoodJeweller */, @@ -414,7 +414,7 @@ struct labor_default static std::vector labor_infos; static const struct labor_default default_labor_infos[] = { - /* MINE */ {200, 0, TOOL_PICK}, + /* MINEa */ {200, 0, TOOL_PICK}, /* HAUL_STONE */ {100, 0, TOOL_NONE}, /* HAUL_WOOD */ {100, 0, TOOL_NONE}, /* HAUL_BODY */ {200, 0, TOOL_NONE}, @@ -1607,7 +1607,7 @@ private: bool labors_changed; int tool_count[TOOLS_MAX]; - bool reequip_needed[TOOLS_MAX]; + int tool_in_use[TOOLS_MAX]; int cnt_recover_wounded; int cnt_diagnosis; @@ -1639,7 +1639,69 @@ private: bool old = dwarf->dwarf->status.labors[labor]; dwarf->dwarf->status.labors[labor] = value; if (old != value) + { labors_changed = true; + + tools_enum tool = default_labor_infos[labor].tool; + if (tool != TOOL_NONE) + tool_in_use[tool] += value ? 1 : -1; + } + } + } + + void process_job (df::job* j) + { + if (j->flags.bits.suspend || j->flags.bits.item_lost) + return; + + int worker = -1; + int bld = -1; + + for (int r = 0; r < j->general_refs.size(); ++r) + { + if (j->general_refs[r]->getType() == df::general_ref_type::UNIT_WORKER) + worker = ((df::general_ref_unit_workerst *)(j->general_refs[r]))->unit_id; + if (j->general_refs[r]->getType() == df::general_ref_type::BUILDING_HOLDER) + bld = ((df::general_ref_building_holderst *)(j->general_refs[r]))->building_id; + } + + if (bld != -1) + { + df::building* b = binsearch_in_vector(world->buildings.all, bld); + int fjid = -1; + for (int jn = 0; jn < b->jobs.size(); jn++) + { + if (b->jobs[jn]->flags.bits.suspend) + continue; + fjid = b->jobs[jn]->id; + break; + } + // check if this job is the first nonsuspended job on this building; if not, ignore it + // (except for farms and trade depots) + if (fjid != j->id && + b->getType() != df::building_type::FarmPlot && + b->getType() != df::building_type::TradeDepot) + return; + } + + df::unit_labor labor = labor_mapper->find_job_labor (j); + + if (labor != df::unit_labor::NONE) + { + labor_needed[labor]++; + if (worker == -1) + { + if (j->pos.isValid()) + { + df::tile_designation* d = Maps::getTileDesignation(j->pos); + if (d->bits.outside) + labor_outside[labor] = true; + } + } else { + labor_infos[labor].mark_assigned(); + labor_in_use[labor]++; + } + } } @@ -1674,6 +1736,7 @@ private: else out.print("Trade depot found but trader is not requested.\n"); } + } } } @@ -1729,7 +1792,10 @@ private: void count_tools() { for (int e = TOOL_NONE; e < TOOLS_MAX; e++) + { tool_count[e] = 0; + tool_in_use[e] = 0; + } priority_food = 0; @@ -1776,66 +1842,20 @@ private: void collect_job_list() { - labor_needed.clear(); - for (df::job_list_link* jll = world->job_list.next; jll; jll = jll->next) { df::job* j = jll->item; if (!j) continue; + process_job(j); + } - if (j->flags.bits.suspend || j->flags.bits.item_lost) + for (auto jp = world->job_postings.begin(); jp != world->job_postings.end(); jp++) + { + if ((*jp)->flags.bits.dead) continue; - int worker = -1; - int bld = -1; - - for (int r = 0; r < j->general_refs.size(); ++r) - { - if (j->general_refs[r]->getType() == df::general_ref_type::UNIT_WORKER) - worker = ((df::general_ref_unit_workerst *)(j->general_refs[r]))->unit_id; - if (j->general_refs[r]->getType() == df::general_ref_type::BUILDING_HOLDER) - bld = ((df::general_ref_building_holderst *)(j->general_refs[r]))->building_id; - } - - if (bld != -1) - { - df::building* b = binsearch_in_vector(world->buildings.all, bld); - int fjid = -1; - for (int jn = 0; jn < b->jobs.size(); jn++) - { - if (b->jobs[jn]->flags.bits.suspend) - continue; - fjid = b->jobs[jn]->id; - break; - } - // check if this job is the first nonsuspended job on this building; if not, ignore it - // (except for farms) - if (fjid != j->id && b->getType() != df::building_type::FarmPlot) { - continue; - } - - } - - df::unit_labor labor = labor_mapper->find_job_labor (j); - - if (labor != df::unit_labor::NONE) - { - labor_needed[labor]++; - if (worker == -1) - { - if (j->pos.isValid()) - { - df::tile_designation* d = Maps::getTileDesignation(j->pos); - if (d->bits.outside) - labor_outside[labor] = true; - } - } else { - labor_infos[labor].mark_assigned(); - labor_in_use[labor]++; - } - - } + process_job((*jp)->job); } } @@ -1909,6 +1929,32 @@ private: } } + // check if dwarf has an axe, pick, or crossbow + + for (int j = 0; j < dwarf->dwarf->inventory.size(); j++) + { + df::unit_inventory_item* ui = dwarf->dwarf->inventory[j]; + if (ui->mode == df::unit_inventory_item::Weapon && ui->item->isWeapon()) + { + dwarf->armed = true; + df::itemdef_weaponst* weapondef = ((df::item_weaponst*)(ui->item))->subtype; + df::job_skill weaponsk = (df::job_skill) weapondef->skill_melee; + df::job_skill rangesk = (df::job_skill) weapondef->skill_ranged; + if (weaponsk == df::job_skill::AXE) + { + dwarf->has_tool[TOOL_AXE] = true; + } + else if (weaponsk == df::job_skill::MINING) + { + dwarf->has_tool[TOOL_PICK] = true; + } + else if (rangesk == df::job_skill::CROSSBOW) + { + dwarf->has_tool[TOOL_CROSSBOW] = true; + } + } + } + // Find the activity state for each dwarf bool is_on_break = false; @@ -1972,12 +2018,9 @@ private: if (labor != df::unit_labor::NONE) { labor_infos[labor].busy_dwarfs++; - - if (!dwarf->dwarf->status.labors[labor]) + if (default_labor_infos[labor].tool != TOOL_NONE) { - out.print("LABORMANAGER: dwarf %s (id %d) is doing job %s(%d) but is not enabled for labor %s(%d).\n", - dwarf->dwarf->name.first_name.c_str(), dwarf->dwarf->id, - ENUM_KEY_STR(job_type, job).c_str(), job, ENUM_KEY_STR(unit_labor, labor).c_str(), labor); + tool_in_use[default_labor_infos[labor].tool]++; } } } @@ -2044,37 +2087,7 @@ private: } dwarf->high_skill = high_skill; - // check if dwarf has an axe, pick, or crossbow - for (int j = 0; j < dwarf->dwarf->inventory.size(); j++) - { - df::unit_inventory_item* ui = dwarf->dwarf->inventory[j]; - if (ui->mode == df::unit_inventory_item::Weapon && ui->item->isWeapon()) - { - dwarf->armed = true; - df::itemdef_weaponst* weapondef = ((df::item_weaponst*)(ui->item))->subtype; - df::job_skill weaponsk = (df::job_skill) weapondef->skill_melee; - df::job_skill rangesk = (df::job_skill) weapondef->skill_ranged; - if (weaponsk == df::job_skill::AXE) - { - dwarf->has_tool[TOOL_AXE] = true; - if (state != IDLE) - tool_count[TOOL_AXE]--; - } - else if (weaponsk == df::job_skill::MINING) - { - dwarf->has_tool[TOOL_PICK] = 1; - if (state != IDLE) - tool_count[TOOL_PICK]--; - } - else if (rangesk == df::job_skill::CROSSBOW) - { - dwarf->has_tool[TOOL_CROSSBOW] = 1; - if (state != IDLE) - tool_count[TOOL_CROSSBOW]--; - } - } - } // clear labors of dwarfs with clear_all set @@ -2136,7 +2149,10 @@ private: score += 1000; if (default_labor_infos[labor].tool != TOOL_NONE && d->has_tool[default_labor_infos[labor].tool]) - score += 5000; + score += 30000; + if (default_labor_infos[labor].tool != TOOL_NONE && + !d->has_tool[default_labor_infos[labor].tool]) + score -= 30000; if (d->has_children && labor_outside[labor]) score -= 15000; if (d->armed && labor_outside[labor]) @@ -2159,6 +2175,8 @@ public: cnt_setting = cnt_traction = cnt_crutch = 0; need_food_water = 0; + labor_needed.clear(); + for (int e = 0; e < TOOLS_MAX; e++) tool_count[e] = 0; @@ -2194,8 +2212,8 @@ public: // add job entries for designation-related jobs - labor_needed[df::unit_labor::MINE] += std::min(tool_count[TOOL_PICK], dig_count); - labor_needed[df::unit_labor::CUTWOOD] += std::min(tool_count[TOOL_AXE], tree_count); + labor_needed[df::unit_labor::MINE] += dig_count; + labor_needed[df::unit_labor::CUTWOOD] += tree_count; labor_needed[df::unit_labor::DETAIL] += detail_count; labor_needed[df::unit_labor::HERBALIST] += plant_count; @@ -2269,10 +2287,19 @@ public: if (l == df::unit_labor::NONE) continue; + int before = labor_needed[l]; + if (labor_infos[l].idle_dwarfs > 0) labor_needed[l] = 0; else labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); + + if (default_labor_infos[l].tool != TOOL_NONE) + labor_needed[l] = std::min(labor_needed[l], tool_count[default_labor_infos[l].tool] - tool_in_use[default_labor_infos[l].tool]); + + if (print_debug && before != labor_needed[l]) + out.print ("labor %s reduced from %d to %d\n", ENUM_KEY_STR(unit_labor, l).c_str(), before, labor_needed[l]); + } /* assign food haulers for rotting food items */ @@ -2427,19 +2454,30 @@ public: if (l == df::unit_labor::NONE) continue; - if (l == best_labor) + tools_enum t = default_labor_infos[l].tool; + + if (l == best_labor && ( t == TOOL_NONE || tool_in_use[t] < tool_count[t]) ) { set_labor(*bestdwarf, l, true); - tools_enum t = default_labor_infos[l].tool; - if (t != TOOL_NONE) + if (t != TOOL_NONE && (*bestdwarf)->has_tool[t]) { - tool_count[t]--; - if (!(*bestdwarf)->has_tool[t]) - (*bestdwarf)->dwarf->military.pickup_flags.bits.update = true; + df::job_type j; + j = df::job_type::NONE; + + if ((*bestdwarf)->dwarf->job.current_job) + j = (*bestdwarf)->dwarf->job.current_job->job_type; + + if (print_debug) + out.print("LABORMANAGER: asking %s to pick up tools, current job %s\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(job_type, j).c_str()); + + (*bestdwarf)->dwarf->military.pickup_flags.bits.update = true; + labors_changed = true; } } else if ((*bestdwarf)->state == IDLE) + { set_labor(*bestdwarf, l, false); + } } if (best_labor == df::unit_labor::HAUL_FOOD && priority_food > 0) @@ -2450,7 +2488,6 @@ public: if (best_labor != df::unit_labor::NONE) { - busy_dwarfs.push_back(*bestdwarf); labor_infos[best_labor].active_dwarfs++; to_assign[best_labor]--; } @@ -2489,6 +2526,8 @@ public: ENUM_KEY_STR(unit_labor, l).c_str(), score, ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score); } + if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000) + set_labor(*d, (*d)->using_labor, false); } } } @@ -2535,7 +2574,7 @@ public: if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && canary & (1 << l)) set_labor(*d, l, true); - else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION) + else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION || l == df::unit_labor::PULL_LEVER) set_labor(*d, l, true); else set_labor(*d, l, false); @@ -2546,16 +2585,42 @@ public: for (auto d = dwarf_info.begin(); d != dwarf_info.end(); d++) { + if ((*d)->dwarf->job.current_job && (*d)->dwarf->job.current_job->job_type == df::job_type::PickupEquipment) + continue; + + if ((*d)->dwarf->military.pickup_flags.bits.update) + continue; + FOR_ENUM_ITEMS (unit_labor, l) { if (l == df::unit_labor::NONE) continue; tools_enum t = default_labor_infos[l].tool; - if (t != TOOL_NONE && tool_count[t] < 0 && (*d)->has_tool[t] && !(*d)->dwarf->status.labors[l]) + if (t == TOOL_NONE) + continue; + + bool has_tool = (*d)->has_tool[t]; + bool needs_tool = (*d)->dwarf->status.labors[l]; + + if (has_tool != needs_tool) { - tool_count[t]++; - (*d)->dwarf->military.pickup_flags.bits.update = 1; + if (has_tool && tool_count[t] > tool_in_use[t]) + continue; + + df::job_type j = df::job_type::NONE; + + if ((*d)->dwarf->job.current_job) + j = (*d)->dwarf->job.current_job->job_type; + + if (print_debug) + out.print("LABORMANAGER: asking %s to %s tools, current job %s, %d %d \n", (*d)->dwarf->name.first_name.c_str(), (has_tool) ? "drop" : "pick up", ENUM_KEY_STR(job_type, j).c_str(), has_tool, needs_tool); + + (*d)->dwarf->military.pickup_flags.bits.update = true; + labors_changed = true; + + if (needs_tool) + tool_in_use[t]++; } } } From 2455e36510a10ccac291c78d9db747ad631702d2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 3 Jul 2016 23:32:43 -0400 Subject: [PATCH 019/413] Initial 64-bit support --- CMakeLists.txt | 23 ++++++- depends/lua/CMakeLists.txt | 8 ++- library/DataDefs.cpp | 8 +-- library/DataStaticsFields.cpp | 2 + library/LuaApi.cpp | 16 ++--- library/LuaWrapper.cpp | 2 +- library/Process-darwin.cpp | 18 ++++- library/Process-linux.cpp | 4 +- library/VTableInterpose.cpp | 2 +- library/VersionInfoFactory.cpp | 4 +- library/include/DataIdentity.h | 2 + library/include/VersionInfo.h | 24 +++---- library/include/VersionInfoFactory.h | 2 +- library/include/modules/EventManager.h | 2 +- library/modules/Buildings.cpp | 92 +++++++++++++------------- plugins/Plugins.cmake | 15 +++-- 16 files changed, 136 insertions(+), 88 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b9b985c2..b74f94b39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,18 @@ if(MSVC) add_definitions( "/wd4819" ) endif() +SET(DFHACK_BUILD_ARCH "32" CACHE STRING "Architecture to build ('32' or '64')") +IF("${DFHACK_BUILD_ARCH}" STREQUAL "32") + SET(DFHACK_BUILD_32 1) + SET(DFHACK_BUILD_64 0) +ELSEIF("${DFHACK_BUILD_ARCH}" STREQUAL "64") + SET(DFHACK_BUILD_32 0) + SET(DFHACK_BUILD_64 1) + ADD_DEFINITIONS(-DDFHACK64) +ELSE() + MESSAGE(SEND_ERROR "Invalid build architecture (should be 32/64): ${DFHACK_BUILD_ARCH}") +ENDIF() + IF(CMAKE_CROSSCOMPILING) SET(DFHACK_NATIVE_BUILD_DIR "DFHACK_NATIVE_BUILD_DIR-NOTFOUND" CACHE FILEPATH "Path to a native build directory") INCLUDE("${DFHACK_NATIVE_BUILD_DIR}/ImportExecutables.cmake") @@ -152,8 +164,15 @@ IF(UNIX) # enable C++11 features add_definitions(-DLINUX_BUILD) SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g -Wall -Wno-unused-variable") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -m32 -march=i686 -mtune=generic -std=c++0x") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -m32 -march=i686 -mtune=generic") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -mtune=generic -std=c++0x") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -mtune=generic") + IF(DFHACK_BUILD_64) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -mno-avx") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64 -mno-avx") + ELSE() + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -march=i686") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -march=i686") + ENDIF() ELSEIF(MSVC) # for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /vmm /MP") diff --git a/depends/lua/CMakeLists.txt b/depends/lua/CMakeLists.txt index b77bce6f7..782bb5e96 100644 --- a/depends/lua/CMakeLists.txt +++ b/depends/lua/CMakeLists.txt @@ -11,8 +11,12 @@ ELSE() ENDIF() IF(UNIX) - add_definitions(-DLINUX_BUILD) - SET(CMAKE_C_FLAGS "-m32") + ADD_DEFINITIONS(-DLINUX_BUILD) + IF(DFHACK_BUILD_64) + SET(CMAKE_C_FLAGS "-m64 -mno-avx") + ELSE() + SET(CMAKE_C_FLAGS "-m32") + ENDIF() ENDIF() SET (HDR_LIBLUA diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index f9187ff09..be381d860 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -276,11 +276,11 @@ virtual_identity *virtual_identity::find(void *vtable) if (p->vtable_ptr && p->vtable_ptr != vtable) { std::cerr << "Conflicting vtable ptr for class '" << p->getName() - << "': found 0x" << std::hex << unsigned(vtable) - << ", previous 0x" << unsigned(p->vtable_ptr) << std::dec << std::endl; + << "': found 0x" << std::hex << uintptr_t(vtable) + << ", previous 0x" << uintptr_t(p->vtable_ptr) << std::dec << std::endl; abort(); } else if (!p->vtable_ptr) { - uint32_t pv = unsigned(vtable); + uintptr_t pv = uintptr_t(vtable); pv -= Core::getInstance().vinfo->getRebaseDelta(); std::cerr << "" << std::endl; @@ -292,7 +292,7 @@ virtual_identity *virtual_identity::find(void *vtable) } std::cerr << "UNKNOWN CLASS '" << name << "': vtable = 0x" - << std::hex << unsigned(vtable) << std::dec << std::endl; + << std::hex << uintptr_t(vtable) << std::dec << std::endl; known[vtable] = NULL; return NULL; diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index 583e4d6a4..96f91dd66 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -30,6 +30,8 @@ namespace df { NUMBER_IDENTITY_TRAITS(uint32_t); NUMBER_IDENTITY_TRAITS(int64_t); NUMBER_IDENTITY_TRAITS(uint64_t); + NUMBER_IDENTITY_TRAITS(intptr_t); + NUMBER_IDENTITY_TRAITS(uintptr_t); NUMBER_IDENTITY_TRAITS(float); NUMBER_IDENTITY_TRAITS(double); diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 712ccb541..74019c4e1 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2310,8 +2310,8 @@ static void *checkaddr(lua_State *L, int idx, bool allow_null = false) return rv; } -static uint32_t getImageBase() { return Core::getInstance().p->getBase(); } -static int getRebaseDelta() { return Core::getInstance().vinfo->getRebaseDelta(); } +static uintptr_t getImageBase() { return Core::getInstance().p->getBase(); } +static intptr_t getRebaseDelta() { return Core::getInstance().vinfo->getRebaseDelta(); } static int8_t getModstate() { return Core::getInstance().getModstate(); } static std::string internal_strerror(int n) { return strerror(n); } @@ -2344,7 +2344,7 @@ static int internal_getPE(lua_State *L) static int internal_getAddress(lua_State *L) { const char *name = luaL_checkstring(L, 1); - uint32_t addr = Core::getInstance().vinfo->getAddress(name); + uintptr_t addr = Core::getInstance().vinfo->getAddress(name); if (addr) lua_pushnumber(L, addr); else @@ -2355,7 +2355,7 @@ static int internal_getAddress(lua_State *L) static int internal_setAddress(lua_State *L) { std::string name = luaL_checkstring(L, 1); - uint32_t addr = (uint32_t)checkaddr(L, 2, true); + uintptr_t addr = (uintptr_t)checkaddr(L, 2, true); internal_getAddress(L); // Set the address @@ -2372,7 +2372,7 @@ static int internal_setAddress(lua_State *L) } // Print via printerr, so that it is definitely logged to stderr.log. - uint32_t iaddr = addr - Core::getInstance().vinfo->getRebaseDelta(); + uintptr_t iaddr = addr - Core::getInstance().vinfo->getRebaseDelta(); fprintf(stderr, "Setting global '%s' to %x (%x)\n", name.c_str(), addr, iaddr); fflush(stderr); @@ -2382,7 +2382,7 @@ static int internal_setAddress(lua_State *L) static int internal_getVTable(lua_State *L) { const char *name = luaL_checkstring(L, 1); - uint32_t addr = (uint32_t)Core::getInstance().vinfo->getVTable(name); + uintptr_t addr = (uintptr_t)Core::getInstance().vinfo->getVTable(name); if (addr) lua_pushnumber(L, addr); else @@ -2412,9 +2412,9 @@ static int internal_getMemRanges(lua_State *L) for(size_t i = 0; i < ranges.size(); i++) { lua_newtable(L); - lua_pushnumber(L, (uint32_t)ranges[i].start); + lua_pushnumber(L, (uintptr_t)ranges[i].start); lua_setfield(L, -2, "start_addr"); - lua_pushnumber(L, (uint32_t)ranges[i].end); + lua_pushnumber(L, (uintptr_t)ranges[i].end); lua_setfield(L, -2, "end_addr"); lua_pushstring(L, ranges[i].name); lua_setfield(L, -2, "name"); diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index dac458709..08af93e78 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -993,7 +993,7 @@ static int meta_ptr_tostring(lua_State *state) lua_getfield(state, UPVAL_METATABLE, "__metatable"); const char *cname = lua_tostring(state, -1); - lua_pushstring(state, stl_sprintf("<%s: 0x%08x>", cname, (unsigned)ptr).c_str()); + lua_pushstring(state, stl_sprintf("<%s: 0x%08x>", cname, (uintptr_t)ptr).c_str()); return 1; } diff --git a/library/Process-darwin.cpp b/library/Process-darwin.cpp index 6f159e5fe..95c347368 100644 --- a/library/Process-darwin.cpp +++ b/library/Process-darwin.cpp @@ -118,8 +118,8 @@ Process::~Process() string Process::doReadClassName (void * vptr) { //FIXME: BAD!!!!! - char * typeinfo = Process::readPtr(((char *)vptr - 0x4)); - char * typestring = Process::readPtr(typeinfo + 0x4); + char * typeinfo = Process::readPtr(((char *)vptr - sizeof(void*))); + char * typestring = Process::readPtr(typeinfo + sizeof(void*)); string raw = readCString(typestring); size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers size_t end = raw.length(); @@ -151,9 +151,15 @@ void Process::getMemRanges( vector & ranges ) the_task = mach_task_self(); +#ifdef DFHACK64 + mach_vm_size_t vmsize; + mach_vm_address_t address; + vm_region_basic_info_data_64_t info; +#else vm_size_t vmsize; vm_address_t address; vm_region_basic_info_data_t info; +#endif mach_msg_type_number_t info_count; vm_region_flavor_t flavor; memory_object_name_t object; @@ -162,10 +168,18 @@ void Process::getMemRanges( vector & ranges ) address = 0; do { +#ifdef DFHACK64 + flavor = VM_REGION_BASIC_INFO_64; + info_count = VM_REGION_BASIC_INFO_COUNT_64; + kr = mach_vm_region(the_task, &address, &vmsize, flavor, + (vm_region_info_64_t)&info, &info_count, &object); +#else flavor = VM_REGION_BASIC_INFO; info_count = VM_REGION_BASIC_INFO_COUNT; kr = vm_region(the_task, &address, &vmsize, flavor, (vm_region_info_t)&info, &info_count, &object); +#endif + if (kr == KERN_SUCCESS) { if (info.reserved==1) { address += vmsize; diff --git a/library/Process-linux.cpp b/library/Process-linux.cpp index 1a1e754d0..14c70a802 100644 --- a/library/Process-linux.cpp +++ b/library/Process-linux.cpp @@ -122,8 +122,8 @@ Process::~Process() string Process::doReadClassName (void * vptr) { //FIXME: BAD!!!!! - char * typeinfo = Process::readPtr(((char *)vptr - 0x4)); - char * typestring = Process::readPtr(typeinfo + 0x4); + char * typeinfo = Process::readPtr(((char *)vptr - sizeof(void*))); + char * typestring = Process::readPtr(typeinfo + sizeof(void*)); string raw = readCString(typestring); size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers size_t end = raw.length(); diff --git a/library/VTableInterpose.cpp b/library/VTableInterpose.cpp index eb8dec861..d81c6d730 100644 --- a/library/VTableInterpose.cpp +++ b/library/VTableInterpose.cpp @@ -305,7 +305,7 @@ VMethodInterposeLinkBase::VMethodInterposeLinkBase(virtual_identity *host, int v */ fprintf(stderr, "Bad VMethodInterposeLinkBase arguments: %d %08x (%s)\n", - vmethod_idx, unsigned(interpose_method), name_str); + vmethod_idx, uintptr_t(interpose_method), name_str); fflush(stderr); abort(); } diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index f6bd5cba9..02dac568c 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -69,7 +69,7 @@ VersionInfo * VersionInfoFactory::getVersionInfoByMD5(string hash) return 0; } -VersionInfo * VersionInfoFactory::getVersionInfoByPETimestamp(uint32_t timestamp) +VersionInfo * VersionInfoFactory::getVersionInfoByPETimestamp(uintptr_t timestamp) { for(size_t i = 0; i < versions.size();i++) { @@ -140,7 +140,7 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem) } if ((is_vtable && no_vtables) || (!is_vtable && no_globals)) continue; - uint32_t addr = strtol(cstr_value, 0, 0); + uintptr_t addr = strtol(cstr_value, 0, 0); if (is_vtable) mem->setVTable(cstr_key, addr); else diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index e6dfc6a18..c94129f9b 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -487,6 +487,8 @@ namespace df NUMBER_IDENTITY_TRAITS(uint32_t); NUMBER_IDENTITY_TRAITS(int64_t); NUMBER_IDENTITY_TRAITS(uint64_t); + NUMBER_IDENTITY_TRAITS(intptr_t); + NUMBER_IDENTITY_TRAITS(uintptr_t); NUMBER_IDENTITY_TRAITS(float); NUMBER_IDENTITY_TRAITS(double); diff --git a/library/include/VersionInfo.h b/library/include/VersionInfo.h index cf7dd60c0..58ecb2c28 100644 --- a/library/include/VersionInfo.h +++ b/library/include/VersionInfo.h @@ -49,10 +49,10 @@ namespace DFHack { private: std::vector md5_list; - std::vector PE_list; - std::map Addresses; - std::map VTables; - uint32_t base; + std::vector PE_list; + std::map Addresses; + std::map VTables; + uintptr_t base; int rebase_delta; std::string version; OSType OS; @@ -75,10 +75,10 @@ namespace DFHack OS = rhs.OS; }; - uint32_t getBase () const { return base; }; + uintptr_t getBase () const { return base; }; int getRebaseDelta() const { return rebase_delta; } - void setBase (const uint32_t _base) { base = _base; }; - void rebaseTo(const uint32_t new_base) + void setBase (const uintptr_t _base) { base = _base; }; + void rebaseTo(const uintptr_t new_base) { int64_t old = base; int64_t newx = new_base; @@ -100,11 +100,11 @@ namespace DFHack return std::find(md5_list.begin(), md5_list.end(), _md5) != md5_list.end(); }; - void addPE (uint32_t PE_) + void addPE (uintptr_t PE_) { PE_list.push_back(PE_); }; - bool hasPE (uint32_t PE_) const + bool hasPE (uintptr_t PE_) const { return std::find(PE_list.begin(), PE_list.end(), PE_) != PE_list.end(); }; @@ -115,7 +115,7 @@ namespace DFHack }; std::string getVersion() const { return version; }; - void setAddress (const std::string& key, const uint32_t value) + void setAddress (const std::string& key, const uintptr_t value) { Addresses[key] = value; }; @@ -129,7 +129,7 @@ namespace DFHack return true; }; - uint32_t getAddress (const std::string& key) const + uintptr_t getAddress (const std::string& key) const { auto i = Addresses.find(key); if(i == Addresses.end()) @@ -137,7 +137,7 @@ namespace DFHack return (*i).second; } - void setVTable (const std::string& key, const uint32_t value) + void setVTable (const std::string& key, const uintptr_t value) { VTables[key] = value; }; diff --git a/library/include/VersionInfoFactory.h b/library/include/VersionInfoFactory.h index f69f37fee..8a2cabdc3 100644 --- a/library/include/VersionInfoFactory.h +++ b/library/include/VersionInfoFactory.h @@ -40,7 +40,7 @@ namespace DFHack bool loadFile( std::string path_to_xml); bool isInErrorState() const {return error;}; VersionInfo * getVersionInfoByMD5(std::string md5string); - VersionInfo * getVersionInfoByPETimestamp(uint32_t timestamp); + VersionInfo * getVersionInfoByPETimestamp(uintptr_t timestamp); std::vector versions; // trash existing list void clear(); diff --git a/library/include/modules/EventManager.h b/library/include/modules/EventManager.h index 6e4be47be..d22fa2310 100644 --- a/library/include/modules/EventManager.h +++ b/library/include/modules/EventManager.h @@ -116,7 +116,7 @@ namespace std { std::size_t operator()(const DFHack::EventManager::EventHandler& h) const { size_t r = 17; const size_t m = 65537; - r = m*(r+(int32_t)h.eventHandler); + r = m*(r+(intptr_t)h.eventHandler); r = m*(r+h.freq); return r; } diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index a6589bac1..d819d358c 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -1173,52 +1173,52 @@ void Buildings::clearBuildings(color_ostream& out) { void Buildings::updateBuildings(color_ostream& out, void* ptr) { - int32_t id = (int32_t)ptr; - auto building = df::building::find(id); - - if (building) - { - // Already cached -> weird, so bail out - if (corner1.count(id)) - return; - // Civzones cannot be cached because they can - // overlap each other and normal buildings. - if (!building->isSettingOccupancy()) - return; - - df::coord p1(min(building->x1, building->x2), min(building->y1,building->y2), building->z); - df::coord p2(max(building->x1, building->x2), max(building->y1,building->y2), building->z); - - corner1[id] = p1; - corner2[id] = p2; - - for ( int32_t x = p1.x; x <= p2.x; x++ ) { - for ( int32_t y = p1.y; y <= p2.y; y++ ) { - df::coord pt(x,y,building->z); - if (containsTile(building, pt, false)) - locationToBuilding[pt] = id; - } - } - } - else if (corner1.count(id)) - { - //existing building: destroy it - df::coord p1 = corner1[id]; - df::coord p2 = corner2[id]; - - for ( int32_t x = p1.x; x <= p2.x; x++ ) { - for ( int32_t y = p1.y; y <= p2.y; y++ ) { - df::coord pt(x,y,p1.z); - - auto cur = locationToBuilding.find(pt); - if (cur != locationToBuilding.end() && cur->second == id) - locationToBuilding.erase(cur); - } - } - - corner1.erase(id); - corner2.erase(id); - } + // int32_t id = (int32_t)ptr; + // auto building = df::building::find(id); + + // if (building) + // { + // // Already cached -> weird, so bail out + // if (corner1.count(id)) + // return; + // // Civzones cannot be cached because they can + // // overlap each other and normal buildings. + // if (!building->isSettingOccupancy()) + // return; + + // df::coord p1(min(building->x1, building->x2), min(building->y1,building->y2), building->z); + // df::coord p2(max(building->x1, building->x2), max(building->y1,building->y2), building->z); + + // corner1[id] = p1; + // corner2[id] = p2; + + // for ( int32_t x = p1.x; x <= p2.x; x++ ) { + // for ( int32_t y = p1.y; y <= p2.y; y++ ) { + // df::coord pt(x,y,building->z); + // if (containsTile(building, pt, false)) + // locationToBuilding[pt] = id; + // } + // } + // } + // else if (corner1.count(id)) + // { + // //existing building: destroy it + // df::coord p1 = corner1[id]; + // df::coord p2 = corner2[id]; + + // for ( int32_t x = p1.x; x <= p2.x; x++ ) { + // for ( int32_t y = p1.y; y <= p2.y; y++ ) { + // df::coord pt(x,y,p1.z); + + // auto cur = locationToBuilding.find(pt); + // if (cur != locationToBuilding.end() && cur->second == id) + // locationToBuilding.erase(cur); + // } + // } + + // corner1.erase(id); + // corner2.erase(id); + // } } void Buildings::getStockpileContents(df::building_stockpilest *stockpile, std::vector *items) diff --git a/plugins/Plugins.cmake b/plugins/Plugins.cmake index c801570db..4871c1f0c 100644 --- a/plugins/Plugins.cmake +++ b/plugins/Plugins.cmake @@ -1,8 +1,15 @@ IF(UNIX) - add_definitions(-DLINUX_BUILD) - SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall") - SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -m32 -std=c++0x") - SET(CMAKE_C_FLAGS "-fvisibility=hidden -m32") + add_definitions(-DLINUX_BUILD) + SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall") + SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -std=c++0x") + SET(CMAKE_C_FLAGS "-fvisibility=hidden") + IF(DFHACK_BUILD_64) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64 -mno-avx") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64 -mno-avx") + ELSE() + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") + ENDIF() ENDIF() include_directories("${dfhack_SOURCE_DIR}/library/include") From b4063352cf29dfecb5b2f878e18310049fe7c297 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 3 Jul 2016 23:33:07 -0400 Subject: [PATCH 020/413] Fix crash in vprinterr due to va_list misuse --- library/ColorText.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/ColorText.cpp b/library/ColorText.cpp index 359b717e6..7f417e0a8 100644 --- a/library/ColorText.cpp +++ b/library/ColorText.cpp @@ -126,10 +126,18 @@ void color_ostream::vprinterr(const char *format, va_list args) color_value save = cur_color; if (log_errors_to_stderr) - vfprintf(stderr, format, args); + { + va_list args1; + va_copy(args1, args); + vfprintf(stderr, format, args1); + va_end(args1); + } color(COLOR_LIGHTRED); - vprint(format, args); + va_list args2; + va_copy(args2, args); + vprint(format, args2); + va_end(args2); color(save); } From a386228f0ede21bdd4a72cea9c9b5d9b3008c0b3 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 5 Jul 2016 13:16:34 -0500 Subject: [PATCH 021/413] labormanager: add StoreItemInLocation labor, reduce tool churn Note: this commit requires updated df-structures (77968973b28d0e828f880d119a700abb079f3521 or later) --- library/xml | 2 +- plugins/devel/labormanager.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/library/xml b/library/xml index b9178de68..77968973b 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit b9178de68bd67442ff720f18b04d222302ce9f8c +Subproject commit 77968973b28d0e828f880d119a700abb079f3521 diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 545ca7f1c..98b7f0f6f 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -1359,6 +1359,8 @@ public: job_to_labor_table[df::job_type::MakeEarring] = jlf_make_object; job_to_labor_table[df::job_type::MakeBracelet] = jlf_make_object; job_to_labor_table[df::job_type::MakeGem] = jlf_make_object; + + job_to_labor_table[df::job_type::StoreItemInLocation] = jlf_no_labor; // StoreItemInLocation }; df::unit_labor find_job_labor(df::job* j) @@ -1380,7 +1382,7 @@ public: df::unit_labor labor; if (job_to_labor_table.count(j->job_type) == 0) { - debug("LABORMANAGER: job has no job to labor table entry: %s\n", ENUM_KEY_STR(job_type, j->job_type).c_str()); + debug("LABORMANAGER: job has no job to labor table entry: %s (%d)\n", ENUM_KEY_STR(job_type, j->job_type).c_str(), j->job_type); debug_pause(); labor = df::unit_labor::NONE; } else { @@ -2526,7 +2528,7 @@ public: ENUM_KEY_STR(unit_labor, l).c_str(), score, ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score); } - if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000) + if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000 && default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) set_labor(*d, (*d)->using_labor, false); } } From 7f1d4506d4c59d6bfc9b6e6c1bda61099acf5a60 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 7 Jul 2016 02:10:43 -0500 Subject: [PATCH 022/413] labormanager: fix several job-to-labor mappings --- plugins/devel/labormanager.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 98b7f0f6f..46322a90c 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -1135,7 +1135,7 @@ public: job_to_labor_table[df::job_type::DigChannel] = jlf_const(df::unit_labor::MINE); job_to_labor_table[df::job_type::FellTree] = jlf_const(df::unit_labor::CUTWOOD); job_to_labor_table[df::job_type::GatherPlants] = jlf_const(df::unit_labor::HERBALIST); - job_to_labor_table[df::job_type::RemoveConstruction] = jlf_no_labor; + job_to_labor_table[df::job_type::RemoveConstruction] = jlf_const(df::unit_labor::REMOVE_CONSTRUCTION); job_to_labor_table[df::job_type::CollectWebs] = jlf_const(df::unit_labor::WEAVER); job_to_labor_table[df::job_type::BringItemToDepot] = jlf_const(df::unit_labor::HAUL_TRADE); job_to_labor_table[df::job_type::BringItemToShop] = jlf_no_labor; @@ -1269,13 +1269,13 @@ public: job_to_labor_table[df::job_type::CleanTrap] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::CastSpell] = jlf_no_labor; job_to_labor_table[df::job_type::LinkBuildingToTrigger] = jlf_const(df::unit_labor::MECHANIC) ; - job_to_labor_table[df::job_type::PullLever] = jlf_no_labor; + job_to_labor_table[df::job_type::PullLever] = jlf_const(df::unit_labor::PULL_LEVER); job_to_labor_table[df::job_type::ExtractFromPlants] = jlf_const(df::unit_labor::HERBALIST) ; job_to_labor_table[df::job_type::ExtractFromRawFish] = jlf_const(df::unit_labor::DISSECT_FISH) ; job_to_labor_table[df::job_type::ExtractFromLandAnimal] = jlf_const(df::unit_labor::DISSECT_VERMIN) ; job_to_labor_table[df::job_type::TameVermin] = jlf_const(df::unit_labor::ANIMALTRAIN) ; job_to_labor_table[df::job_type::TameAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN) ; - job_to_labor_table[df::job_type::ChainAnimal] = jlf_no_labor; + job_to_labor_table[df::job_type::ChainAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::UnchainAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::UnchainPet] = jlf_no_labor; job_to_labor_table[df::job_type::ReleaseLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); @@ -1335,7 +1335,7 @@ public: job_to_labor_table[df::job_type::EngraveSlab] = jlf_const(df::unit_labor::DETAIL); job_to_labor_table[df::job_type::ShearCreature] = jlf_const(df::unit_labor::SHEARER); job_to_labor_table[df::job_type::SpinThread] = jlf_const(df::unit_labor::SPINNER); - job_to_labor_table[df::job_type::PenLargeAnimal] = jlf_no_labor; + job_to_labor_table[df::job_type::PenLargeAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::PenSmallAnimal] = jlf_no_labor; job_to_labor_table[df::job_type::MakeTool] = jlf_make_furniture; job_to_labor_table[df::job_type::CollectClay] = jlf_const(df::unit_labor::POTTERY); @@ -2291,10 +2291,7 @@ public: int before = labor_needed[l]; - if (labor_infos[l].idle_dwarfs > 0) - labor_needed[l] = 0; - else - labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); + labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); if (default_labor_infos[l].tool != TOOL_NONE) labor_needed[l] = std::min(labor_needed[l], tool_count[default_labor_infos[l].tool] - tool_in_use[default_labor_infos[l].tool]); From ed6fb690121d0a433a37a29251de447c2f68c0f8 Mon Sep 17 00:00:00 2001 From: Michael Casadevall Date: Mon, 11 Jul 2016 18:54:03 -0500 Subject: [PATCH 023/413] Fix whitespace spacing Signed-off-by: Michael Casadevall --- library/include/Error.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/include/Error.h b/library/include/Error.h index 1c8afe44c..6b4781028 100644 --- a/library/include/Error.h +++ b/library/include/Error.h @@ -38,19 +38,19 @@ namespace DFHack * our wrapper for the C++ exception. used to differentiate * the whole array of DFHack exceptions from the rest */ -#ifdef _MSC_VER +#ifdef _MSC_VER #pragma push /** - * C4275 is - The warning officially is non dll-interface class 'std::exception' used as base for - * dll-interface class + * C4275 is - The warning officially is non dll-interface class 'std::exception' used as base for + * dll-interface class * * Basically, its saying that you might have an ABI problem if you mismatch compilers. We don't * care since we build all of DFhack at once against whatever Toady is using */ -#pragma warning(disable: 4275) +#pragma warning(disable: 4275) #endif class DFHACK_EXPORT All : public std::exception{}; -#ifdef _MSC_VER +#ifdef _MSC_VER #pragma pop #endif class DFHACK_EXPORT NullPointer : public All { From bcffc53d5a2e589a7cdf5a129e99c75b46d53c95 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 11 Jul 2016 22:29:38 -0500 Subject: [PATCH 024/413] labormanager: add labors for bookcase (de)construct --- plugins/devel/labormanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 46322a90c..cb5f11dfc 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -840,6 +840,7 @@ private: case df::building_type::BarsFloor: case df::building_type::BarsVertical: case df::building_type::GrateWall: + case df::building_type::Bookcase: return df::unit_labor::HAUL_FURNITURE; case df::building_type::Trap: case df::building_type::GearAssembly: @@ -942,6 +943,7 @@ private: case df::building_type::BarsVertical: case df::building_type::GrateFloor: case df::building_type::GrateWall: + case df::building_type::Bookcase: return df::unit_labor::HAUL_FURNITURE; case df::building_type::AnimalTrap: return df::unit_labor::TRAPPER; From 824275b23b6ca6c1b155c3c0fac3625def90aa98 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 27 Jun 2016 12:04:51 -0500 Subject: [PATCH 025/413] Rename autolabor2 to labormanager and bring up to date with current --- plugins/devel/CMakeLists.txt | 2 +- .../{autolabor2.cpp => labormanager.cpp} | 487 +++++++++++++----- 2 files changed, 354 insertions(+), 135 deletions(-) rename plugins/devel/{autolabor2.cpp => labormanager.cpp} (86%) diff --git a/plugins/devel/CMakeLists.txt b/plugins/devel/CMakeLists.txt index 1f3ff6f75..a1e5b7f14 100644 --- a/plugins/devel/CMakeLists.txt +++ b/plugins/devel/CMakeLists.txt @@ -3,13 +3,13 @@ DFHACK_PLUGIN(vectors vectors.cpp) endif() ADD_DEFINITIONS(-DDEV_PLUGIN) -#DFHACK_PLUGIN(autolabor2 autolabor2.cpp) DFHACK_PLUGIN(buildprobe buildprobe.cpp) DFHACK_PLUGIN(color-dfhack-text color-dfhack-text.cpp) DFHACK_PLUGIN(counters counters.cpp) DFHACK_PLUGIN(dumpmats dumpmats.cpp) DFHACK_PLUGIN(eventExample eventExample.cpp) DFHACK_PLUGIN(frozen frozen.cpp) +DFHACK_PLUGIN(labormanager labormanager.cpp) DFHACK_PLUGIN(kittens kittens.cpp) DFHACK_PLUGIN(memview memview.cpp) DFHACK_PLUGIN(nestboxes nestboxes.cpp) diff --git a/plugins/devel/autolabor2.cpp b/plugins/devel/labormanager.cpp similarity index 86% rename from plugins/devel/autolabor2.cpp rename to plugins/devel/labormanager.cpp index 4897832d4..12e4e8ca1 100644 --- a/plugins/devel/autolabor2.cpp +++ b/plugins/devel/labormanager.cpp @@ -1,5 +1,5 @@ /* -* Autolabor 2.0 module for dfhack +* Labor manager (formerly Autolabor 2) module for dfhack * * */ @@ -77,7 +77,7 @@ using df::global::world; #define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0])) -DFHACK_PLUGIN_IS_ENABLED(enable_autolabor); +DFHACK_PLUGIN_IS_ENABLED(enable_labormanager); static bool print_debug = 0; @@ -94,11 +94,11 @@ enum ConfigFlags { // Here go all the command declarations... // mostly to allow having the mandatory stuff on top of the file and commands on the bottom -command_result autolabor (color_ostream &out, std::vector & parameters); +command_result labormanager (color_ostream &out, std::vector & parameters); // A plugin must be able to return its name and version. -// The name string provided must correspond to the filename - autolabor2.plug.so or autolabor2.plug.dll in this case -DFHACK_PLUGIN("autolabor2"); +// The name string provided must correspond to the filename - labormanager.plug.so or labormanager.plug.dll in this case +DFHACK_PLUGIN("labormanager"); static void generate_labor_to_skill_map(); @@ -486,9 +486,20 @@ static const struct labor_default default_labor_infos[] = { /* PRESSING */ {200, 0, TOOL_NONE}, /* BEEKEEPING */ {200, 0, TOOL_NONE}, /* WAX_WORKING */ {200, 0, TOOL_NONE}, - /* PUSH_HAUL_VEHICLES */ {200, 0, TOOL_NONE} + /* PUSH_HAUL_VEHICLES */ {200, 0, TOOL_NONE}, + /* HAUL_TRADE */ {200, 0, TOOL_NONE}, + /* PULL_LEVER */ {200, 0, TOOL_NONE}, + /* REMOVE_CONSTRUCTION */ {200, 0, TOOL_NONE}, + /* HAUL_WATER */ {200, 0, TOOL_NONE}, + /* GELD */ {200, 0, TOOL_NONE}, + /* BUILD_ROAD */ {200, 0, TOOL_NONE}, + /* BUILD_CONSTRUCTION */ {200, 0, TOOL_NONE}, + /* PAPERMAKING */ {200, 0, TOOL_NONE}, + /* BOOKBINDING */ {200, 0, TOOL_NONE} }; +void debug (char* fmt, ...); + struct dwarf_info_t { df::unit* dwarf; @@ -506,12 +517,19 @@ struct dwarf_info_t df::unit_labor using_labor; dwarf_info_t(df::unit* dw) : dwarf(dw), clear_all(false), - state(OTHER), high_skill(0), has_children(false), armed(false) + state(OTHER), high_skill(0), has_children(false), armed(false), using_labor(df::unit_labor::NONE) { for (int e = TOOL_NONE; e < TOOLS_MAX; e++) has_tool[e] = false; } + ~dwarf_info_t() + { + if (print_debug) + debug("LABORMANAGER: destroying dwarf %p\n", (void*) this); + } + + void set_labor(df::unit_labor labor) { if (labor >= 0 && labor <= ENUM_LAST_ITEM(unit_labor)) @@ -554,10 +572,10 @@ static df::unit_labor hauling_labor_map[] = df::unit_labor::HAUL_ITEM, /* INSTRUMENT */ df::unit_labor::HAUL_ITEM, /* TOY */ df::unit_labor::HAUL_FURNITURE, /* WINDOW */ - df::unit_labor::HAUL_ANIMAL, /* CAGE */ + df::unit_labor::HAUL_ANIMALS, /* CAGE */ df::unit_labor::HAUL_ITEM, /* BARREL */ df::unit_labor::HAUL_ITEM, /* BUCKET */ - df::unit_labor::HAUL_ANIMAL, /* ANIMALTRAP */ + df::unit_labor::HAUL_ANIMALS, /* ANIMALTRAP */ df::unit_labor::HAUL_FURNITURE, /* TABLE */ df::unit_labor::HAUL_FURNITURE, /* COFFIN */ df::unit_labor::HAUL_FURNITURE, /* STATUE */ @@ -850,7 +868,7 @@ private: return df::unit_labor::SIEGECRAFT; } - debug ("AUTOLABOR: Cannot deduce labor for construct building job of type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for construct building job of type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); return df::unit_labor::NONE; @@ -944,7 +962,7 @@ private: return df::unit_labor::SIEGECRAFT; } - debug ("AUTOLABOR: Cannot deduce labor for destroy building job of type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for destroy building job of type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); return df::unit_labor::NONE; @@ -979,13 +997,13 @@ private: return df::unit_labor::BONE_CARVE; else { - debug ("AUTOLABOR: Cannot deduce labor for make crafts job (not bone)\n"); + debug ("LABORMANAGER: Cannot deduce labor for make crafts job (not bone)\n"); return df::unit_labor::NONE; } case df::item_type::WOOD: return df::unit_labor::WOOD_CRAFT; default: - debug ("AUTOLABOR: Cannot deduce labor for make crafts job, item type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for make crafts job, item type %s\n", ENUM_KEY_STR(item_type, jobitem).c_str()); return df::unit_labor::NONE; } @@ -1002,7 +1020,7 @@ private: case df::workshop_type::MetalsmithsForge: return metaltype; default: - debug ("AUTOLABOR: Cannot deduce labor for make job, workshop type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for make job, workshop type %s\n", ENUM_KEY_STR(workshop_type, type).c_str()); return df::unit_labor::NONE; } @@ -1016,13 +1034,13 @@ private: case df::furnace_type::GlassFurnace: return df::unit_labor::GLASSMAKER; default: - debug ("AUTOLABOR: Cannot deduce labor for make job, furnace type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for make job, furnace type %s\n", ENUM_KEY_STR(furnace_type, type).c_str()); return df::unit_labor::NONE; } } - debug ("AUTOLABOR: Cannot deduce labor for make job, building type %s\n", + debug ("LABORMANAGER: Cannot deduce labor for make job, building type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); return df::unit_labor::NONE; @@ -1147,8 +1165,6 @@ public: job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInBag] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInHospital] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInChest] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInCabinet] = jlf_hauling; job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling; job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling; @@ -1219,7 +1235,6 @@ public: job_to_labor_table[df::job_type::MilkCreature] = jlf_const(df::unit_labor::MILK); job_to_labor_table[df::job_type::MakeCheese] = jlf_const(df::unit_labor::MAKE_CHEESE); job_to_labor_table[df::job_type::ProcessPlants] = jlf_const(df::unit_labor::PROCESS_PLANT); - job_to_labor_table[df::job_type::ProcessPlantsBag] = jlf_const(df::unit_labor::PROCESS_PLANT); job_to_labor_table[df::job_type::ProcessPlantsVial] = jlf_const(df::unit_labor::PROCESS_PLANT); job_to_labor_table[df::job_type::ProcessPlantsBarrel] = jlf_const(df::unit_labor::PROCESS_PLANT); job_to_labor_table[df::job_type::PrepareMeal] = jlf_const(df::unit_labor::COOK); @@ -1256,7 +1271,6 @@ public: job_to_labor_table[df::job_type::CastSpell] = jlf_no_labor; job_to_labor_table[df::job_type::LinkBuildingToTrigger] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::PullLever] = jlf_no_labor; - job_to_labor_table[df::job_type::BrewDrink] = jlf_const(df::unit_labor::BREWER) ; job_to_labor_table[df::job_type::ExtractFromPlants] = jlf_const(df::unit_labor::HERBALIST) ; job_to_labor_table[df::job_type::ExtractFromRawFish] = jlf_const(df::unit_labor::DISSECT_FISH) ; job_to_labor_table[df::job_type::ExtractFromLandAnimal] = jlf_const(df::unit_labor::DISSECT_VERMIN) ; @@ -1334,9 +1348,9 @@ public: job_to_labor_table[df::job_type::ExecuteCriminal] = jlf_no_labor; job_to_labor_table[df::job_type::TrainAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN); job_to_labor_table[df::job_type::CarveTrack] = jlf_const(df::unit_labor::DETAIL); - job_to_labor_table[df::job_type::PushTrackVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE); - job_to_labor_table[df::job_type::PlaceTrackVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE); - job_to_labor_table[df::job_type::StoreItemInVehicle] = jlf_const(df::unit_labor::PUSH_HAUL_VEHICLE); + job_to_labor_table[df::job_type::PushTrackVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES); + job_to_labor_table[df::job_type::PlaceTrackVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES); + job_to_labor_table[df::job_type::StoreItemInVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES); job_to_labor_table[df::job_type::GeldAnimal] = jlf_const(df::unit_labor::GELD); job_to_labor_table[df::job_type::MakeFigurine] = jlf_make_object; job_to_labor_table[df::job_type::MakeAmulet] = jlf_make_object; @@ -1365,7 +1379,14 @@ public: df::unit_labor labor; - labor = job_to_labor_table[j->job_type]->get_labor(j); + if (job_to_labor_table.count(j->job_type) == 0) + { + debug("LABORMANAGER: job has no job to labor table entry: %s\n", ENUM_KEY_STR(job_type, j->job_type).c_str()); + labor = df::unit_labor::NONE; + } else { + + labor = job_to_labor_table[j->job_type]->get_labor(j); + } return labor; } @@ -1375,6 +1396,8 @@ public: static JobLaborMapper* labor_mapper = 0; +static bool initialized = false; + static bool isOptionEnabled(unsigned flag) { return config.isValid() && (config.ival(0) & flag) != 0; @@ -1393,8 +1416,9 @@ static void setOptionEnabled(ConfigFlags flag, bool on) static void cleanup_state() { - enable_autolabor = false; + enable_labormanager = false; labor_infos.clear(); + initialized = false; } static void reset_labor(df::unit_labor labor) @@ -1405,25 +1429,25 @@ static void reset_labor(df::unit_labor labor) static void init_state() { - config = World::GetPersistentData("autolabor/2.0/config"); + config = World::GetPersistentData("labormanager/2.0/config"); if (config.isValid() && config.ival(0) == -1) config.ival(0) = 0; - enable_autolabor = isOptionEnabled(CF_ENABLED); + enable_labormanager = isOptionEnabled(CF_ENABLED); - if (!enable_autolabor) + if (!enable_labormanager) return; // Load labors from save labor_infos.resize(ARRAY_COUNT(default_labor_infos)); std::vector items; - World::GetPersistentData(&items, "autolabor/2.0/labors/", true); + World::GetPersistentData(&items, "labormanager/2.0/labors/", true); for (auto p = items.begin(); p != items.end(); p++) { string key = p->key(); - df::unit_labor labor = (df::unit_labor) atoi(key.substr(strlen("autolabor/2.0/labors/")).c_str()); + df::unit_labor labor = (df::unit_labor) atoi(key.substr(strlen("labormanager/2.0/labors/")).c_str()); if (labor >= 0 && labor <= labor_infos.size()) { labor_infos[labor].config = *p; @@ -1437,7 +1461,7 @@ static void init_state() continue; std::stringstream name; - name << "autolabor/2.0/labors/" << i; + name << "labormanager/2.0/labors/" << i; labor_infos[i].config = World::AddPersistentData(name.str()); labor_infos[i].mark_assigned(); @@ -1445,6 +1469,8 @@ static void init_state() reset_labor((df::unit_labor) i); } + initialized = true; + } static df::job_skill labor_to_skill[ENUM_LAST_ITEM(unit_labor) + 1]; @@ -1477,12 +1503,12 @@ static void enable_plugin(color_ostream &out) { if (!config.isValid()) { - config = World::AddPersistentData("autolabor/2.0/config"); + config = World::AddPersistentData("labormanager/2.0/config"); config.ival(0) = 0; } setOptionEnabled(CF_ENABLED, true); - enable_autolabor = true; + enable_labormanager = true; out << "Enabling the plugin." << endl; cleanup_state(); @@ -1497,32 +1523,32 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector \n" + " labormanager max \n" " Set max number of dwarves assigned to a labor.\n" - " autolabor2 max none\n" + " labormanager max none\n" " Unrestrict the number of dwarves assigned to a labor.\n" - " autolabor2 priority \n" + " labormanager priority \n" " Change the assignment priority of a labor (default is 100)\n" - " autolabor2 reset \n" + " labormanager reset \n" " Return a labor to the default handling.\n" - " autolabor2 reset-all\n" + " labormanager reset-all\n" " Return all labors to the default handling.\n" - " autolabor2 list\n" + " labormanager list\n" " List current status of all labors.\n" - " autolabor2 status\n" + " labormanager status\n" " Show basic status information.\n" "Function:\n" - " When enabled, autolabor periodically checks your dwarves and enables or\n" + " When enabled, labormanager periodically checks your dwarves and enables or\n" " disables labors. Generally, each dwarf will be assigned exactly one labor.\n" - " Warning: autolabor will override any manual changes you make to labors\n" - " while it is enabled. Do not try to run both autolabor and autolabor2 at\n" - " the same time." + " Warning: labormanager will override any manual changes you make to labors\n" + " while it is enabled. Do not try to run both labormanager and labormanager at\n" + " the same time.\n" )); generate_labor_to_skill_map(); @@ -1594,14 +1620,21 @@ private: int need_food_water; + int priority_food; + std::map labor_needed; std::map labor_outside; std::vector dwarf_info; std::list available_dwarfs; + std::list busy_dwarfs; private: void scan_buildings() { + has_butchers = false; + has_fishery = false; + trader_requested = false; + for (auto b = world->buildings.all.begin(); b != world->buildings.all.end(); b++) { df::building *build = *b; @@ -1658,16 +1691,14 @@ private: if (dig != df::enums::tile_dig_designation::No) { df::tiletype tt = bl->tiletype[x][y]; + df::tiletype_material ttm = ENUM_ATTR(tiletype, material, tt); df::tiletype_shape tts = ENUM_ATTR(tiletype, shape, tt); - switch (tts) - { - case df::enums::tiletype_shape::TREE: - tree_count++; break; - case df::enums::tiletype_shape::SHRUB: - plant_count++; break; - default: - dig_count++; break; - } + if (ttm == df::enums::tiletype_material::TREE) + tree_count++; + else if (tts == df::enums::tiletype_shape::SHRUB) + plant_count++; + else + dig_count++; } if (bl->designation[x][y].bits.smooth != 0) detail_count++; @@ -1684,13 +1715,15 @@ private: for (int e = TOOL_NONE; e < TOOLS_MAX; e++) tool_count[e] = 0; + priority_food = 0; + df::item_flags bad_flags; bad_flags.whole = 0; #define F(x) bad_flags.bits.x = true; F(dump); F(forbid); F(garbage_collect); F(hostile); F(on_fire); F(rotten); F(trader); - F(in_building); F(construction); F(artifact); + F(in_building); F(construction); #undef F auto& v = world->items.all; @@ -1704,6 +1737,11 @@ private: if (item->flags.whole & bad_flags.whole) continue; + df::item_type t = item->getType(); + + if (item->materialRots() && t != df::item_type::CORPSEPIECE && t != df::item_type::CORPSE && item->getRotTimer() > 1) + priority_food++; + if (!item->isWeapon()) continue; @@ -1869,14 +1907,20 @@ private: { state = CHILD; } + else if (ENUM_ATTR(profession, military, dwarf->dwarf->profession)) state = MILITARY; + + else if (dwarf->dwarf->burrows.size() > 0) + state = OTHER; // dwarfs assigned to burrows are treated as if permanently busy + else if (dwarf->dwarf->job.current_job == NULL) { - if (is_on_break) + if (is_on_break || dwarf->dwarf->flags1.bits.chained || dwarf->dwarf->flags1.bits.caged) + { state = OTHER; - else if (dwarf->dwarf->burrows.size() > 0) - state = OTHER; // dwarfs assigned to burrows are treated as if permanently busy + dwarf->clear_all = true; + } else if (dwarf->dwarf->status2.limbs_grasp_count == 0) { state = OTHER; // dwarfs unable to grasp are incapable of nearly all labors @@ -1902,18 +1946,23 @@ private: if (state == BUSY) { df::unit_labor labor = labor_mapper->find_job_labor(dwarf->dwarf->job.current_job); + + dwarf->using_labor = labor; + if (labor != df::unit_labor::NONE) { - dwarf->using_labor = labor; + labor_infos[labor].busy_dwarfs++; - if (!dwarf->dwarf->status.labors[labor] && print_debug) + if (!dwarf->dwarf->status.labors[labor]) { - out.print("AUTOLABOR: dwarf %s (id %d) is doing job %s(%d) but is not enabled for labor %s(%d).\n", + out.print("LABORMANAGER: dwarf %s (id %d) is doing job %s(%d) but is not enabled for labor %s(%d).\n", dwarf->dwarf->name.first_name.c_str(), dwarf->dwarf->id, ENUM_KEY_STR(job_type, job).c_str(), job, ENUM_KEY_STR(unit_labor, labor).c_str(), labor); } } } + if (state == OTHER) + dwarf->clear_all = true; } dwarf->state = state; @@ -1925,8 +1974,6 @@ private: if (dwarf->dwarf->status.labors[l]) if (state == IDLE) labor_infos[l].idle_dwarfs++; - else if (state == BUSY) - labor_infos[l].busy_dwarfs++; } @@ -2022,19 +2069,69 @@ private: dwarf->clear_labor(labor); } + } else { + if (state == IDLE) + available_dwarfs.push_back(dwarf); + + if (state == BUSY) + busy_dwarfs.push_back(dwarf); } - else if (state == IDLE || state == BUSY) - available_dwarfs.push_back(dwarf); + } + + } + } + void release_dwarf_list() + { + while (!dwarf_info.empty()) { + auto d = dwarf_info.begin(); + delete *d; + dwarf_info.erase(d); + } + available_dwarfs.clear(); + busy_dwarfs.clear(); + } + + int score_labor (dwarf_info_t* d, df::unit_labor labor) + { + int skill_level = 0; + int xp = 0; + + if (labor != df::unit_labor::NONE) + { + df::job_skill skill = labor_to_skill[labor]; + if (skill != df::job_skill::NONE) + { + skill_level = Units::getEffectiveSkill(d->dwarf, skill); + xp = Units::getExperience(d->dwarf, skill, false); } + } + int score = skill_level * 1000 - (d->high_skill - skill_level) * 2000 + (xp / (skill_level + 5) * 10); + + if (labor != df::unit_labor::NONE) + { + if (d->dwarf->status.labors[labor]) + if (labor == df::unit_labor::OPERATE_PUMP) + score += 50000; + else + score += 1000; + if (default_labor_infos[labor].tool != TOOL_NONE && + d->has_tool[default_labor_infos[labor].tool]) + score += 5000; + if (d->has_children && labor_outside[labor]) + score -= 15000; + if (d->armed && labor_outside[labor]) + score += 5000; } + + return score; } public: void process() { - dwarf_info.clear(); + release_dwarf_list(); dig_count = tree_count = plant_count = detail_count = 0; cnt_recover_wounded = cnt_diagnosis = cnt_immobilize = cnt_dressing = cnt_cleaning = cnt_surgery = cnt_suture = @@ -2106,13 +2203,27 @@ public: labor_needed[df::unit_labor::HAUL_FOOD] += world->stockpile.num_jobs[6]; labor_needed[df::unit_labor::HAUL_REFUSE] += world->stockpile.num_jobs[7]; labor_needed[df::unit_labor::HAUL_FURNITURE] += world->stockpile.num_jobs[8]; - labor_needed[df::unit_labor::HAUL_ANIMAL] += world->stockpile.num_jobs[9]; + labor_needed[df::unit_labor::HAUL_ANIMALS] += world->stockpile.num_jobs[9]; + + labor_needed[df::unit_labor::HAUL_STONE] += (world->stockpile.num_jobs[1] >= world->stockpile.num_haulers[1]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_WOOD] += (world->stockpile.num_jobs[2] >= world->stockpile.num_haulers[2]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_ITEM] += (world->stockpile.num_jobs[3] >= world->stockpile.num_haulers[3]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_BODY] += (world->stockpile.num_jobs[5] >= world->stockpile.num_haulers[5]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_FOOD] += (world->stockpile.num_jobs[6] >= world->stockpile.num_haulers[6]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_REFUSE] += (world->stockpile.num_jobs[7] >= world->stockpile.num_haulers[7]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_FURNITURE] += (world->stockpile.num_jobs[8] >= world->stockpile.num_haulers[8]) ? 1 : 0; + labor_needed[df::unit_labor::HAUL_ANIMALS] += (world->stockpile.num_jobs[9] >= world->stockpile.num_haulers[9]) ? 1 : 0; + + int binjobs = world->stockpile.num_jobs[4] + ((world->stockpile.num_jobs[4] >= world->stockpile.num_haulers[4]) ? 1 : 0); + + labor_needed[df::unit_labor::HAUL_ITEM] += binjobs; + labor_needed[df::unit_labor::HAUL_FOOD] += priority_food; // add entries for vehicle hauling for (auto v = world->vehicles.all.begin(); v != world->vehicles.all.end(); v++) if ((*v)->route_id != -1) - labor_needed[df::unit_labor::PUSH_HAUL_VEHICLE]++; + labor_needed[df::unit_labor::HANDLE_VEHICLES]++; // add fishing & hunting @@ -2131,33 +2242,101 @@ public: // note: this doesn't test to see if the trainer is actually needed, and thus will overallocate trainers. bleah. } + /* move idle dwarfs ready to be assigned to busy list */ + for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); ) + { + bool busy = false; + + FOR_ENUM_ITEMS(unit_labor, l) + { + if (l == df::unit_labor::NONE) + continue; + + + if (labor_needed[l] > 0 && (*d)->dwarf->status.labors[l]) + { + busy = true; + labor_needed[l] = max(labor_needed[l]-1, 0); + } + } + + if (busy) + { + busy_dwarfs.push_back(*d); + d = available_dwarfs.erase(d); + } else { + d++; + } + } + /* adjust for over/under */ FOR_ENUM_ITEMS(unit_labor, l) { if (l == df::unit_labor::NONE) continue; - if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMAL) - continue; - if (labor_infos[l].idle_dwarfs > 0 && labor_needed[l] > labor_infos[l].busy_dwarfs) + if (labor_infos[l].idle_dwarfs > 0) + labor_needed[l] = 0; + else + labor_needed[l] = std::max(labor_needed[l] - labor_infos[l].busy_dwarfs, 0); + } + + /* assign food haulers for rotting food items */ + + if (priority_food > 0 && labor_infos[df::unit_labor::HAUL_FOOD].idle_dwarfs > 0) + priority_food = 1; + + if (print_debug) + out.print ("priority food count = %d\n", priority_food); + + while (!available_dwarfs.empty() && priority_food > 0) + { + std::list::iterator bestdwarf = available_dwarfs.begin(); + + int best_score = INT_MIN; + + for (std::list::iterator k = available_dwarfs.begin(); k != available_dwarfs.end(); k++) { - int clawback = labor_infos[l].busy_dwarfs; - if (clawback == 0 && labor_needed[l] > 0) - clawback = 1; + dwarf_info_t* d = (*k); + int score = score_labor(d, df::unit_labor::HAUL_FOOD); + + if (score > best_score) + { + bestdwarf = k; + best_score = score; + } + } + + if (best_score > INT_MIN) + { if (print_debug) - out.print("reducing labor %s to %d (%d needed, %d busy, %d idle)\n", ENUM_KEY_STR(unit_labor, l).c_str(), - clawback, - labor_needed[l], labor_infos[l].busy_dwarfs, labor_infos[l].idle_dwarfs); - labor_needed[l] = clawback; + out.print("LABORMANAGER: assign \"%s\" labor %s score=%d (priority food)\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(unit_labor, df::unit_labor::HAUL_FOOD).c_str(), best_score); + + FOR_ENUM_ITEMS(unit_labor, l) + { + if (l == df::unit_labor::NONE) + continue; + + if (l == df::unit_labor::HAUL_FOOD) + (*bestdwarf)->set_labor(l); + else + (*bestdwarf)->clear_labor(l); + } + + available_dwarfs.erase(bestdwarf); + priority_food--; } + else + break; + } if (print_debug) { for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) { - out.print ("labor_needed [%s] = %d, outside = %d, idle = %d\n", ENUM_KEY_STR(unit_labor, i->first).c_str(), i->second, - labor_outside[i->first], labor_infos[i->first].idle_dwarfs); + out.print ("labor_needed [%s] = %d, busy = %d, outside = %d, idle = %d\n", ENUM_KEY_STR(unit_labor, i->first).c_str(), i->second, + labor_infos[i->first].busy_dwarfs, labor_outside[i->first], labor_infos[i->first].idle_dwarfs); } } @@ -2173,6 +2352,8 @@ public: { int priority = labor_infos[l].priority(); priority += labor_infos[l].time_since_last_assigned()/12; + for (int n = 0; n < labor_infos[l].busy_dwarfs; n++) + priority /= 2; pq.push(make_pair(priority, l)); } } @@ -2212,7 +2393,7 @@ public: (1 << df::unit_labor::HAUL_REFUSE) | (1 << df::unit_labor::HAUL_ITEM) | (1 << df::unit_labor::HAUL_FURNITURE) | - (1 << df::unit_labor::HAUL_ANIMAL); + (1 << df::unit_labor::HAUL_ANIMALS); while (!available_dwarfs.empty()) { @@ -2227,36 +2408,11 @@ public: continue; df::unit_labor labor = j->first; - df::job_skill skill = labor_to_skill[labor]; for (std::list::iterator k = available_dwarfs.begin(); k != available_dwarfs.end(); k++) { dwarf_info_t* d = (*k); - int skill_level = 0; - int xp = 0; - if (skill != df::job_skill::NONE) - { - skill_level = Units::getEffectiveSkill(d->dwarf, skill); - xp = Units::getExperience(d->dwarf, skill, false); - } - int score = skill_level * 1000 - (d->high_skill - skill_level) * 2000 + (xp / (skill_level + 5) * 10); - if (d->dwarf->status.labors[labor]) - if (labor == df::unit_labor::OPERATE_PUMP) - score += 50000; - else - score += 1000; - if (default_labor_infos[labor].tool != TOOL_NONE && - d->has_tool[default_labor_infos[labor].tool]) - score += 5000; - if (d->has_children && labor_outside[labor]) - score -= 15000; - if (d->armed && labor_outside[labor]) - score += 5000; - if (d->state == BUSY) - if (d->using_labor == labor) - score += 7500; - else - score -= 7500; + int score = score_labor(d, labor); if (score > best_score) { bestdwarf = k; @@ -2289,11 +2445,15 @@ public: (*bestdwarf)->clear_labor(l); } - if (best_labor >= df::unit_labor::HAUL_STONE && best_labor <= df::unit_labor::HAUL_ANIMAL) + if (best_labor == df::unit_labor::HAUL_FOOD && priority_food > 0) + priority_food--; + + if (best_labor >= df::unit_labor::HAUL_STONE && best_labor <= df::unit_labor::HAUL_ANIMALS) canary &= ~(1 << best_labor); if (best_labor != df::unit_labor::NONE) { + busy_dwarfs.push_back(*bestdwarf); labor_infos[best_labor].active_dwarfs++; to_assign[best_labor]--; } @@ -2301,17 +2461,71 @@ public: available_dwarfs.erase(bestdwarf); } - if (canary != 0) + for (auto d = busy_dwarfs.begin(); d != busy_dwarfs.end(); d++) { - dwarf_info_t* d = dwarf_info.front(); + int current_score = score_labor (*d, (*d)->using_labor); + FOR_ENUM_ITEMS (unit_labor, l) { - if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMAL && - canary & (1 << l)) - d->set_labor(l); + if (l == df::unit_labor::NONE) + continue; + if (l == (*d)->using_labor) + continue; + if (labor_needed[l] <= 0) + continue; + + int score = score_labor (*d, l); + score += labor_infos[l].time_since_last_assigned()/12; + if (l == df::unit_labor::HAUL_FOOD && priority_food > 0) + score += 1000000; + + if (score > current_score) + { + tools_enum t = default_labor_infos[l].tool; + if (t == TOOL_NONE || (*d)->has_tool[t]) + { + (*d)->set_labor (l); + if (print_debug) + out.print("assign \"%s\" extra labor %s score=%d current %s score=%d\n", + (*d)->dwarf->name.first_name.c_str(), + ENUM_KEY_STR(unit_labor, l).c_str(), score, + ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score); + } + } + else + (*d)->clear_labor (l); + } + } + + + if (canary != 0) + { + dwarf_info_t* d = 0; + + for (auto di = busy_dwarfs.begin(); di != busy_dwarfs.end(); di++) + if (!(*di)->clear_all) + { + d = *di; + break; + } + + if (d) + { + + FOR_ENUM_ITEMS (unit_labor, l) + { + if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && + canary & (1 << l)) + d->set_labor(l); + } + if (print_debug) + out.print ("Setting %s as the hauling canary\n", d->dwarf->name.first_name.c_str()); + } + else + { + if (print_debug) + out.print ("No dwarf available to set as the hauling canary!\n"); } - if (print_debug) - out.print ("Setting %s as the hauling canary\n", d->dwarf->name.first_name.c_str()); } /* set reequip on any dwarfs who are carrying tools needed by others */ @@ -2320,6 +2534,9 @@ public: { FOR_ENUM_ITEMS (unit_labor, l) { + if (l == df::unit_labor::NONE) + continue; + tools_enum t = default_labor_infos[l].tool; if (t != TOOL_NONE && tool_count[t] < 0 && (*d)->has_tool[t] && !(*d)->dwarf->status.labors[l]) { @@ -2329,6 +2546,8 @@ public: } } + release_dwarf_list(); + *df::global::process_jobs = true; print_debug = 0; @@ -2359,7 +2578,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) { static int step_count = 0; // check run conditions - if(!world || !world->map.block_index || !enable_autolabor) + if(!initialized || !world || !world->map.block_index || !enable_labormanager) { // give up if we shouldn't be running' return CR_OK; @@ -2406,26 +2625,26 @@ df::unit_labor lookup_labor_by_name (std::string& name) DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable ) { if (!Core::getInstance().isWorldLoaded()) { - out.printerr("World is not loaded: please load a game first.\n"); + out.printerr("World is not loaded: please load a fort first.\n"); return CR_FAILURE; } - if (enable && !enable_autolabor) + if (enable && !enable_labormanager) { enable_plugin(out); } - else if(!enable && enable_autolabor) + else if(!enable && enable_labormanager) { - enable_autolabor = false; + enable_labormanager = false; setOptionEnabled(CF_ENABLED, false); - out << "Autolabor is disabled." << endl; + out << "LaborManager is disabled." << endl; } return CR_OK; } -command_result autolabor (color_ostream &out, std::vector & parameters) +command_result labormanager (color_ostream &out, std::vector & parameters) { CoreSuspender suspend; @@ -2443,7 +2662,7 @@ command_result autolabor (color_ostream &out, std::vector & parame else if (parameters.size() == 3 && (parameters[0] == "max" || parameters[0] == "priority")) { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2474,7 +2693,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 2 && parameters[0] == "reset") { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2493,7 +2712,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 1 && (parameters[0] == "allow-fishing" || parameters[0] == "forbid-fishing")) { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2504,7 +2723,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 1 && (parameters[0] == "allow-hunting" || parameters[0] == "forbid-hunting")) { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2515,7 +2734,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 1 && parameters[0] == "reset-all") { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2530,7 +2749,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 1 && parameters[0] == "list" || parameters[0] == "status") { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2563,7 +2782,7 @@ command_result autolabor (color_ostream &out, std::vector & parame } else if (parameters.size() == 1 && parameters[0] == "debug") { - if (!enable_autolabor) + if (!enable_labormanager) { out << "Error: The plugin is not enabled." << endl; return CR_FAILURE; @@ -2576,8 +2795,8 @@ command_result autolabor (color_ostream &out, std::vector & parame else { out.print("Automatically assigns labors to dwarves.\n" - "Activate with 'autolabor enable', deactivate with 'autolabor disable'.\n" - "Current state: %s.\n", enable_autolabor ? "enabled" : "disabled"); + "Activate with 'labormanager enable', deactivate with 'labormanager disable'.\n" + "Current state: %s.\n", enable_labormanager ? "enabled" : "disabled"); return CR_OK; } From 07e1c819691622b450bbc4bb9dd0fb141008b38e Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 27 Jun 2016 20:58:38 -0500 Subject: [PATCH 026/413] labormanager improvements Add some debugging facilities. Change some hauling, construction, and deconstruction labors to reflect changes in DF since 34.11. --- plugins/devel/labormanager.cpp | 40 +++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 12e4e8ca1..ffabde36a 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -80,6 +80,7 @@ using df::global::world; DFHACK_PLUGIN_IS_ENABLED(enable_labormanager); static bool print_debug = 0; +static bool pause_on_error = 1; static std::vector state_count(5); @@ -525,8 +526,6 @@ struct dwarf_info_t ~dwarf_info_t() { - if (print_debug) - debug("LABORMANAGER: destroying dwarf %p\n", (void*) this); } @@ -608,7 +607,7 @@ static df::unit_labor hauling_labor_map[] = df::unit_labor::HAUL_FOOD, /* FISH_RAW */ df::unit_labor::HAUL_REFUSE, /* VERMIN */ df::unit_labor::HAUL_ITEM, /* PET */ - df::unit_labor::HAUL_FOOD, /* SEEDS */ + df::unit_labor::HAUL_ITEM, /* SEEDS */ df::unit_labor::HAUL_FOOD, /* PLANT */ df::unit_labor::HAUL_ITEM, /* SKIN_TANNED */ df::unit_labor::HAUL_FOOD, /* LEAVES */ @@ -716,6 +715,14 @@ void debug (char* fmt, ...) } } +void debug_pause () +{ + if (pause_on_error) + { + debug("LABORMANAGER: Game paused so you can investigate the above message.\nUse 'labormanager pause-on-error no' to disable autopausing.\n"); + *df::global::pause_state = true; + } +} class JobLaborMapper { @@ -804,9 +811,10 @@ private: return workshop_build_labor[ws->type]; } break; + case df::building_type::Construction: + return df::unit_labor::BUILD_CONSTRUCTION; case df::building_type::Furnace: case df::building_type::TradeDepot: - case df::building_type::Construction: case df::building_type::Bridge: case df::building_type::ArcheryTarget: case df::building_type::WaterWheel: @@ -870,6 +878,7 @@ private: debug ("LABORMANAGER: Cannot deduce labor for construct building job of type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); + debug_pause(); return df::unit_labor::NONE; } @@ -900,9 +909,10 @@ private: return workshop_build_labor[ws->type]; } break; + case df::building_type::Construction: + return df::unit_labor::REMOVE_CONSTRUCTION; case df::building_type::Furnace: case df::building_type::TradeDepot: - case df::building_type::Construction: case df::building_type::Wagon: case df::building_type::Bridge: case df::building_type::ScrewPump: @@ -964,6 +974,7 @@ private: debug ("LABORMANAGER: Cannot deduce labor for destroy building job of type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); + debug_pause(); return df::unit_labor::NONE; } @@ -998,6 +1009,7 @@ private: else { debug ("LABORMANAGER: Cannot deduce labor for make crafts job (not bone)\n"); + debug_pause(); return df::unit_labor::NONE; } case df::item_type::WOOD: @@ -1005,6 +1017,7 @@ private: default: debug ("LABORMANAGER: Cannot deduce labor for make crafts job, item type %s\n", ENUM_KEY_STR(item_type, jobitem).c_str()); + debug_pause(); return df::unit_labor::NONE; } } @@ -1022,6 +1035,7 @@ private: default: debug ("LABORMANAGER: Cannot deduce labor for make job, workshop type %s\n", ENUM_KEY_STR(workshop_type, type).c_str()); + debug_pause(); return df::unit_labor::NONE; } } @@ -1036,12 +1050,14 @@ private: default: debug ("LABORMANAGER: Cannot deduce labor for make job, furnace type %s\n", ENUM_KEY_STR(furnace_type, type).c_str()); + debug_pause(); return df::unit_labor::NONE; } } debug ("LABORMANAGER: Cannot deduce labor for make job, building type %s\n", ENUM_KEY_STR(building_type, bld->getType()).c_str()); + debug_pause(); return df::unit_labor::NONE; } @@ -1382,6 +1398,7 @@ public: if (job_to_labor_table.count(j->job_type) == 0) { debug("LABORMANAGER: job has no job to labor table entry: %s\n", ENUM_KEY_STR(job_type, j->job_type).c_str()); + debug_pause(); labor = df::unit_labor::NONE; } else { @@ -1941,6 +1958,7 @@ private: else { out.print("Dwarf \"%s\" has unknown job %i\n", dwarf->dwarf->name.first_name.c_str(), job); + debug_pause(); state = OTHER; } if (state == BUSY) @@ -2780,6 +2798,18 @@ command_result labormanager (color_ostream &out, std::vector & par return CR_OK; } + else if (parameters.size() == 2 && parameters[0] == "pause-on-error") + { + if (!enable_labormanager) + { + out << "Error: The plugin is not enabled." << endl; + return CR_FAILURE; + } + + pause_on_error = parameters[1] == "yes" || parameters[1] == "true"; + + return CR_OK; + } else if (parameters.size() == 1 && parameters[0] == "debug") { if (!enable_labormanager) From f095e139aaafbe7207439a2bd3eadc4e90683352 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 28 Jun 2016 22:36:45 -0500 Subject: [PATCH 027/413] labormanager: more tweaks to bring up to date This update fixes some labors and attempts to address changes in the way DF maintains the job list. --- plugins/devel/labormanager.cpp | 155 +++++++++++++++------------------ 1 file changed, 72 insertions(+), 83 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index ffabde36a..256841cb7 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -1154,7 +1154,7 @@ public: job_to_labor_table[df::job_type::GatherPlants] = jlf_const(df::unit_labor::HERBALIST); job_to_labor_table[df::job_type::RemoveConstruction] = jlf_no_labor; job_to_labor_table[df::job_type::CollectWebs] = jlf_const(df::unit_labor::WEAVER); - job_to_labor_table[df::job_type::BringItemToDepot] = jlf_no_labor; + job_to_labor_table[df::job_type::BringItemToDepot] = jlf_const(df::unit_labor::HAUL_TRADE); job_to_labor_table[df::job_type::BringItemToShop] = jlf_no_labor; job_to_labor_table[df::job_type::Eat] = jlf_no_labor; job_to_labor_table[df::job_type::GetProvisions] = jlf_no_labor; @@ -1178,13 +1178,13 @@ public: job_to_labor_table[df::job_type::CheckChest] = jlf_no_labor; job_to_labor_table[df::job_type::StoreOwnedItem] = jlf_no_labor; job_to_labor_table[df::job_type::PlaceItemInTomb] = jlf_const(df::unit_labor::HAUL_BODY); - job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInBag] = jlf_hauling; + job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list + job_to_labor_table[df::job_type::StoreItemInBag] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list job_to_labor_table[df::job_type::StoreItemInHospital] = jlf_hauling; job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling; job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInBin] = jlf_const(df::unit_labor::HAUL_ITEM); + job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list + job_to_labor_table[df::job_type::StoreItemInBin] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list job_to_labor_table[df::job_type::SeekArtifact] = jlf_no_labor; job_to_labor_table[df::job_type::SeekInfant] = jlf_no_labor; job_to_labor_table[df::job_type::AttendParty] = jlf_no_labor; @@ -1293,14 +1293,14 @@ public: job_to_labor_table[df::job_type::TameVermin] = jlf_const(df::unit_labor::ANIMALTRAIN) ; job_to_labor_table[df::job_type::TameAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN) ; job_to_labor_table[df::job_type::ChainAnimal] = jlf_no_labor; - job_to_labor_table[df::job_type::UnchainAnimal] = jlf_no_labor; + job_to_labor_table[df::job_type::UnchainAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::UnchainPet] = jlf_no_labor; - job_to_labor_table[df::job_type::ReleaseLargeCreature] = jlf_no_labor; + job_to_labor_table[df::job_type::ReleaseLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::ReleasePet] = jlf_no_labor; job_to_labor_table[df::job_type::ReleaseSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::HandleSmallCreature] = jlf_no_labor; - job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_no_labor; - job_to_labor_table[df::job_type::CageLargeCreature] = jlf_no_labor; + job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); + job_to_labor_table[df::job_type::CageLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::CageSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::RecoverWounded] = jlf_const(df::unit_labor::RECOVER_WOUNDED); job_to_labor_table[df::job_type::DiagnosePatient] = jlf_const(df::unit_labor::DIAGNOSE) ; @@ -1640,6 +1640,7 @@ private: int priority_food; std::map labor_needed; + std::map labor_in_use; std::map labor_outside; std::vector dwarf_info; std::list available_dwarfs; @@ -1668,6 +1669,7 @@ private: { df::building_tradedepotst* depot = (df::building_tradedepotst*) build; trader_requested = depot->trade_flags.bits.trader_requested; + if (print_debug) { if (trader_requested) @@ -1819,20 +1821,23 @@ private: } df::unit_labor labor = labor_mapper->find_job_labor (j); + labor_needed[labor]++; if (labor != df::unit_labor::NONE) { - labor_needed[labor]++; - - if (worker != -1) + if (worker == -1) + { + if (j->pos.isValid()) + { + df::tile_designation* d = Maps::getTileDesignation(j->pos); + if (d->bits.outside) + labor_outside[labor] = true; + } + } else { labor_infos[labor].mark_assigned(); + labor_in_use[labor]++; + } - if (j->pos.isValid()) - { - df::tile_designation* d = Maps::getTileDesignation(j->pos); - if (d->bits.outside) - labor_outside[labor] = true; - } } } @@ -1979,8 +1984,6 @@ private: } } } - if (state == OTHER) - dwarf->clear_all = true; } dwarf->state = state; @@ -2199,7 +2202,7 @@ public: // add job entries for health care labor_needed[df::unit_labor::RECOVER_WOUNDED] += cnt_recover_wounded; - labor_needed[df::unit_labor::DIAGNOSE] += cnt_diagnosis; + labor_needed[df::unit_labor::DIAGNOSE] += cnt_diagnosis; labor_needed[df::unit_labor::BONE_SETTING] += cnt_immobilize; labor_needed[df::unit_labor::DRESSING_WOUNDS] += cnt_dressing; labor_needed[df::unit_labor::DRESSING_WOUNDS] += cnt_cleaning; @@ -2260,43 +2263,14 @@ public: // note: this doesn't test to see if the trainer is actually needed, and thus will overallocate trainers. bleah. } - /* move idle dwarfs ready to be assigned to busy list */ - for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); ) - { - bool busy = false; + /* set requirements to zero for labors with currently idle dwarfs, and remove from requirement dwarfs actually working */ - FOR_ENUM_ITEMS(unit_labor, l) - { - if (l == df::unit_labor::NONE) - continue; - - - if (labor_needed[l] > 0 && (*d)->dwarf->status.labors[l]) - { - busy = true; - labor_needed[l] = max(labor_needed[l]-1, 0); - } - } - - if (busy) - { - busy_dwarfs.push_back(*d); - d = available_dwarfs.erase(d); - } else { - d++; - } - } - - /* adjust for over/under */ - FOR_ENUM_ITEMS(unit_labor, l) - { - if (l == df::unit_labor::NONE) - continue; - if (labor_infos[l].idle_dwarfs > 0) - labor_needed[l] = 0; - else - labor_needed[l] = std::max(labor_needed[l] - labor_infos[l].busy_dwarfs, 0); - } + FOR_ENUM_ITEMS(unit_labor, l) { + if (labor_infos[l].idle_dwarfs > 0) + labor_needed[l] = 0; + else + labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); + } /* assign food haulers for rotting food items */ @@ -2401,7 +2375,6 @@ public: priority /= 2; pq.push(make_pair(priority, labor)); } - } int canary = (1 << df::unit_labor::HAUL_STONE) | @@ -2476,6 +2449,7 @@ public: to_assign[best_labor]--; } + busy_dwarfs.push_back(*bestdwarf); available_dwarfs.erase(bestdwarf); } @@ -2510,42 +2484,57 @@ public: ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score); } } - else - (*d)->clear_labor (l); } } - if (canary != 0) - { - dwarf_info_t* d = 0; - - for (auto di = busy_dwarfs.begin(); di != busy_dwarfs.end(); di++) - if (!(*di)->clear_all) - { - d = *di; - break; - } + dwarf_info_t* canary_dwarf = 0; - if (d) + for (auto di = busy_dwarfs.begin(); di != busy_dwarfs.end(); di++) + if (!(*di)->clear_all) { - - FOR_ENUM_ITEMS (unit_labor, l) - { - if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && - canary & (1 << l)) - d->set_labor(l); - } - if (print_debug) - out.print ("Setting %s as the hauling canary\n", d->dwarf->name.first_name.c_str()); + canary_dwarf = *di; + break; } - else + + if (canary_dwarf) + { + + FOR_ENUM_ITEMS (unit_labor, l) { - if (print_debug) - out.print ("No dwarf available to set as the hauling canary!\n"); + if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && + canary & (1 << l)) + canary_dwarf->set_labor(l); } + + /* Also set the canary to remove constructions, because we have no way yet to tell if there are constructions needing removal */ + + canary_dwarf->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); + + if (print_debug) + out.print ("Setting %s as the hauling canary\n", canary_dwarf->dwarf->name.first_name.c_str()); + } + else + { + if (print_debug) + out.print ("No dwarf available to set as the hauling canary!\n"); } + /* Assign any leftover dwarfs to "standard" labors */ + + for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); d++) + { + FOR_ENUM_ITEMS (unit_labor, l) + { + if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && + canary & (1 << l)) + (*d)->set_labor(l); + } + + (*d)->set_labor(df::unit_labor::CLEAN); + (*d)->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); + } + /* set reequip on any dwarfs who are carrying tools needed by others */ for (auto d = dwarf_info.begin(); d != dwarf_info.end(); d++) From 705134975d492a00f76e33c6549924f7c7c738f3 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 28 Jun 2016 22:57:12 -0500 Subject: [PATCH 028/413] labormanager: whitespace MSVC is evil. --- plugins/devel/labormanager.cpp | 60 +++++++++++++++++----------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 256841cb7..8acae7524 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -1299,7 +1299,7 @@ public: job_to_labor_table[df::job_type::ReleasePet] = jlf_no_labor; job_to_labor_table[df::job_type::ReleaseSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::HandleSmallCreature] = jlf_no_labor; - job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); + job_to_labor_table[df::job_type::HandleLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::CageLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::CageSmallCreature] = jlf_no_labor; job_to_labor_table[df::job_type::RecoverWounded] = jlf_const(df::unit_labor::RECOVER_WOUNDED); @@ -1640,7 +1640,7 @@ private: int priority_food; std::map labor_needed; - std::map labor_in_use; + std::map labor_in_use; std::map labor_outside; std::vector dwarf_info; std::list available_dwarfs; @@ -1821,22 +1821,22 @@ private: } df::unit_labor labor = labor_mapper->find_job_labor (j); - labor_needed[labor]++; + labor_needed[labor]++; if (labor != df::unit_labor::NONE) { - if (worker == -1) - { - if (j->pos.isValid()) - { - df::tile_designation* d = Maps::getTileDesignation(j->pos); - if (d->bits.outside) - labor_outside[labor] = true; - } - } else { + if (worker == -1) + { + if (j->pos.isValid()) + { + df::tile_designation* d = Maps::getTileDesignation(j->pos); + if (d->bits.outside) + labor_outside[labor] = true; + } + } else { labor_infos[labor].mark_assigned(); - labor_in_use[labor]++; - } + labor_in_use[labor]++; + } } } @@ -2263,14 +2263,14 @@ public: // note: this doesn't test to see if the trainer is actually needed, and thus will overallocate trainers. bleah. } - /* set requirements to zero for labors with currently idle dwarfs, and remove from requirement dwarfs actually working */ + /* set requirements to zero for labors with currently idle dwarfs, and remove from requirement dwarfs actually working */ - FOR_ENUM_ITEMS(unit_labor, l) { - if (labor_infos[l].idle_dwarfs > 0) - labor_needed[l] = 0; - else - labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); - } + FOR_ENUM_ITEMS(unit_labor, l) { + if (labor_infos[l].idle_dwarfs > 0) + labor_needed[l] = 0; + else + labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); + } /* assign food haulers for rotting food items */ @@ -2449,7 +2449,7 @@ public: to_assign[best_labor]--; } - busy_dwarfs.push_back(*bestdwarf); + busy_dwarfs.push_back(*bestdwarf); available_dwarfs.erase(bestdwarf); } @@ -2507,9 +2507,9 @@ public: canary_dwarf->set_labor(l); } - /* Also set the canary to remove constructions, because we have no way yet to tell if there are constructions needing removal */ + /* Also set the canary to remove constructions, because we have no way yet to tell if there are constructions needing removal */ - canary_dwarf->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); + canary_dwarf->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); if (print_debug) out.print ("Setting %s as the hauling canary\n", canary_dwarf->dwarf->name.first_name.c_str()); @@ -2520,10 +2520,10 @@ public: out.print ("No dwarf available to set as the hauling canary!\n"); } - /* Assign any leftover dwarfs to "standard" labors */ + /* Assign any leftover dwarfs to "standard" labors */ - for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); d++) - { + for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); d++) + { FOR_ENUM_ITEMS (unit_labor, l) { if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && @@ -2531,9 +2531,9 @@ public: (*d)->set_labor(l); } - (*d)->set_labor(df::unit_labor::CLEAN); - (*d)->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); - } + (*d)->set_labor(df::unit_labor::CLEAN); + (*d)->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); + } /* set reequip on any dwarfs who are carrying tools needed by others */ From dbc46c510ff83c877ca36e9b0e4a976001eff733 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 28 Jun 2016 23:28:44 -0500 Subject: [PATCH 029/413] labormanager: fix stupid --- plugins/devel/labormanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 8acae7524..d78d06b97 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -2337,6 +2337,9 @@ public: for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) { df::unit_labor l = i->first; + if (l == df::unit_labor::NONE) + continue; + if (labor_infos[l].maximum_dwarfs() > 0 && i->second > labor_infos[l].maximum_dwarfs()) i->second = labor_infos[l].maximum_dwarfs(); From 3a0ba332d9764dfbaa45c1bc0db4dca0abeead43 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Wed, 29 Jun 2016 14:54:03 -0500 Subject: [PATCH 030/413] labormanager: rework for better behavior with 43.03 The main thing here is that the process loop exits if the DF process_job or process_dig flags are set since if these are set the job list is going to change soon anyway. The plugin also sets these flags when it changes any labors, which has the side effect of effectively disabling the process loop while DF is paused, which prevents flapping while editing job preferences in-game, and also allows changing job preferences in game (although such changes may not last when the clock starts up again). --- plugins/devel/labormanager.cpp | 78 +++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index d78d06b97..8d614ed36 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -528,23 +528,6 @@ struct dwarf_info_t { } - - void set_labor(df::unit_labor labor) - { - if (labor >= 0 && labor <= ENUM_LAST_ITEM(unit_labor)) - { - dwarf->status.labors[labor] = true; - } - } - - void clear_labor(df::unit_labor labor) - { - if (labor >= 0 && labor <= ENUM_LAST_ITEM(unit_labor)) - { - dwarf->status.labors[labor] = false; - } - } - }; /* @@ -1621,6 +1604,8 @@ private: int plant_count; int detail_count; + bool labors_changed; + int tool_count[TOOLS_MAX]; bool reequip_needed[TOOLS_MAX]; @@ -1647,11 +1632,23 @@ private: std::list busy_dwarfs; private: + void set_labor (dwarf_info_t* dwarf, df::unit_labor labor, bool value) + { + if (labor >= 0 && labor <= ENUM_LAST_ITEM(unit_labor)) + { + bool old = dwarf->dwarf->status.labors[labor]; + dwarf->dwarf->status.labors[labor] = value; + if (old != value) + labors_changed = true; + } + } + void scan_buildings() { has_butchers = false; has_fishery = false; trader_requested = false; + labors_changed = false; for (auto b = world->buildings.all.begin(); b != world->buildings.all.end(); b++) { @@ -1821,10 +1818,10 @@ private: } df::unit_labor labor = labor_mapper->find_job_labor (j); - labor_needed[labor]++; if (labor != df::unit_labor::NONE) { + labor_needed[labor]++; if (worker == -1) { if (j->pos.isValid()) @@ -2088,7 +2085,7 @@ private: if (labor == unit_labor::NONE) continue; - dwarf->clear_labor(labor); + set_labor(dwarf, labor, false); } } else { if (state == IDLE) @@ -2152,6 +2149,9 @@ private: public: void process() { + if (*df::global::process_dig || *df::global::process_jobs) + return; + release_dwarf_list(); dig_count = tree_count = plant_count = detail_count = 0; @@ -2266,6 +2266,9 @@ public: /* set requirements to zero for labors with currently idle dwarfs, and remove from requirement dwarfs actually working */ FOR_ENUM_ITEMS(unit_labor, l) { + if (l == df::unit_labor::NONE) + continue; + if (labor_infos[l].idle_dwarfs > 0) labor_needed[l] = 0; else @@ -2309,10 +2312,7 @@ public: if (l == df::unit_labor::NONE) continue; - if (l == df::unit_labor::HAUL_FOOD) - (*bestdwarf)->set_labor(l); - else - (*bestdwarf)->clear_labor(l); + set_labor (*bestdwarf, l, l == df::unit_labor::HAUL_FOOD); } available_dwarfs.erase(bestdwarf); @@ -2337,7 +2337,7 @@ public: for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) { df::unit_labor l = i->first; - if (l == df::unit_labor::NONE) + if (l == df::unit_labor::NONE) continue; if (labor_infos[l].maximum_dwarfs() > 0 && @@ -2394,7 +2394,7 @@ public: std::list::iterator bestdwarf = available_dwarfs.begin(); int best_score = INT_MIN; - df::unit_labor best_labor = df::unit_labor::CLEAN; + df::unit_labor best_labor = df::unit_labor::NONE; for (auto j = to_assign.begin(); j != to_assign.end(); j++) { @@ -2416,6 +2416,9 @@ public: } } + if (best_labor == df::unit_labor::NONE) + break; + if (print_debug) out.print("assign \"%s\" labor %s score=%d\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(unit_labor, best_labor).c_str(), best_score); @@ -2426,7 +2429,7 @@ public: if (l == best_labor) { - (*bestdwarf)->set_labor(l); + set_labor(*bestdwarf, l, true); tools_enum t = default_labor_infos[l].tool; if (t != TOOL_NONE) { @@ -2436,7 +2439,7 @@ public: } } else if ((*bestdwarf)->state == IDLE) - (*bestdwarf)->clear_labor(l); + set_labor(*bestdwarf, l, false); } if (best_labor == df::unit_labor::HAUL_FOOD && priority_food > 0) @@ -2479,7 +2482,7 @@ public: tools_enum t = default_labor_infos[l].tool; if (t == TOOL_NONE || (*d)->has_tool[t]) { - (*d)->set_labor (l); + set_labor(*d, l, true); if (print_debug) out.print("assign \"%s\" extra labor %s score=%d current %s score=%d\n", (*d)->dwarf->name.first_name.c_str(), @@ -2507,12 +2510,12 @@ public: { if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && canary & (1 << l)) - canary_dwarf->set_labor(l); + set_labor(canary_dwarf, l, true); } /* Also set the canary to remove constructions, because we have no way yet to tell if there are constructions needing removal */ - canary_dwarf->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); + set_labor(canary_dwarf, df::unit_labor::REMOVE_CONSTRUCTION, true); if (print_debug) out.print ("Setting %s as the hauling canary\n", canary_dwarf->dwarf->name.first_name.c_str()); @@ -2531,11 +2534,12 @@ public: { if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && canary & (1 << l)) - (*d)->set_labor(l); + set_labor(*d, l, true); + else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION) + set_labor(*d, l, true); + else + set_labor(*d, l, false); } - - (*d)->set_labor(df::unit_labor::CLEAN); - (*d)->set_labor(df::unit_labor::REMOVE_CONSTRUCTION); } /* set reequip on any dwarfs who are carrying tools needed by others */ @@ -2558,7 +2562,11 @@ public: release_dwarf_list(); - *df::global::process_jobs = true; + if (labors_changed) + { + *df::global::process_dig = true; + *df::global::process_jobs = true; + } print_debug = 0; From 0509c455ddd2bb3fae6fbea4bd77a642a590e57d Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 30 Jun 2016 23:58:56 -0500 Subject: [PATCH 031/413] labormanager: significant restructuring to use job posting list Updated here to get potential jobs off the job posting lists, which is apparently where certain map-designated live after being designated but before they move to the actual job list. Also changes to how tools are handled, and lever pulling is assigned by default to all idle dwarfs. --- plugins/devel/labormanager.cpp | 273 ++++++++++++++++++++------------- 1 file changed, 169 insertions(+), 104 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 8d614ed36..545ca7f1c 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -184,7 +184,7 @@ static const dwarf_state dwarf_states[] = { OTHER /* GoShopping2 */, BUSY /* Clean */, OTHER /* Rest */, - BUSY /* PickupEquipment */, + OTHER /* PickupEquipment */, BUSY /* DumpItem */, OTHER /* StrangeMoodCrafter */, OTHER /* StrangeMoodJeweller */, @@ -414,7 +414,7 @@ struct labor_default static std::vector labor_infos; static const struct labor_default default_labor_infos[] = { - /* MINE */ {200, 0, TOOL_PICK}, + /* MINEa */ {200, 0, TOOL_PICK}, /* HAUL_STONE */ {100, 0, TOOL_NONE}, /* HAUL_WOOD */ {100, 0, TOOL_NONE}, /* HAUL_BODY */ {200, 0, TOOL_NONE}, @@ -1607,7 +1607,7 @@ private: bool labors_changed; int tool_count[TOOLS_MAX]; - bool reequip_needed[TOOLS_MAX]; + int tool_in_use[TOOLS_MAX]; int cnt_recover_wounded; int cnt_diagnosis; @@ -1639,7 +1639,69 @@ private: bool old = dwarf->dwarf->status.labors[labor]; dwarf->dwarf->status.labors[labor] = value; if (old != value) + { labors_changed = true; + + tools_enum tool = default_labor_infos[labor].tool; + if (tool != TOOL_NONE) + tool_in_use[tool] += value ? 1 : -1; + } + } + } + + void process_job (df::job* j) + { + if (j->flags.bits.suspend || j->flags.bits.item_lost) + return; + + int worker = -1; + int bld = -1; + + for (int r = 0; r < j->general_refs.size(); ++r) + { + if (j->general_refs[r]->getType() == df::general_ref_type::UNIT_WORKER) + worker = ((df::general_ref_unit_workerst *)(j->general_refs[r]))->unit_id; + if (j->general_refs[r]->getType() == df::general_ref_type::BUILDING_HOLDER) + bld = ((df::general_ref_building_holderst *)(j->general_refs[r]))->building_id; + } + + if (bld != -1) + { + df::building* b = binsearch_in_vector(world->buildings.all, bld); + int fjid = -1; + for (int jn = 0; jn < b->jobs.size(); jn++) + { + if (b->jobs[jn]->flags.bits.suspend) + continue; + fjid = b->jobs[jn]->id; + break; + } + // check if this job is the first nonsuspended job on this building; if not, ignore it + // (except for farms and trade depots) + if (fjid != j->id && + b->getType() != df::building_type::FarmPlot && + b->getType() != df::building_type::TradeDepot) + return; + } + + df::unit_labor labor = labor_mapper->find_job_labor (j); + + if (labor != df::unit_labor::NONE) + { + labor_needed[labor]++; + if (worker == -1) + { + if (j->pos.isValid()) + { + df::tile_designation* d = Maps::getTileDesignation(j->pos); + if (d->bits.outside) + labor_outside[labor] = true; + } + } else { + labor_infos[labor].mark_assigned(); + labor_in_use[labor]++; + } + } } @@ -1674,6 +1736,7 @@ private: else out.print("Trade depot found but trader is not requested.\n"); } + } } } @@ -1729,7 +1792,10 @@ private: void count_tools() { for (int e = TOOL_NONE; e < TOOLS_MAX; e++) + { tool_count[e] = 0; + tool_in_use[e] = 0; + } priority_food = 0; @@ -1776,66 +1842,20 @@ private: void collect_job_list() { - labor_needed.clear(); - for (df::job_list_link* jll = world->job_list.next; jll; jll = jll->next) { df::job* j = jll->item; if (!j) continue; + process_job(j); + } - if (j->flags.bits.suspend || j->flags.bits.item_lost) + for (auto jp = world->job_postings.begin(); jp != world->job_postings.end(); jp++) + { + if ((*jp)->flags.bits.dead) continue; - int worker = -1; - int bld = -1; - - for (int r = 0; r < j->general_refs.size(); ++r) - { - if (j->general_refs[r]->getType() == df::general_ref_type::UNIT_WORKER) - worker = ((df::general_ref_unit_workerst *)(j->general_refs[r]))->unit_id; - if (j->general_refs[r]->getType() == df::general_ref_type::BUILDING_HOLDER) - bld = ((df::general_ref_building_holderst *)(j->general_refs[r]))->building_id; - } - - if (bld != -1) - { - df::building* b = binsearch_in_vector(world->buildings.all, bld); - int fjid = -1; - for (int jn = 0; jn < b->jobs.size(); jn++) - { - if (b->jobs[jn]->flags.bits.suspend) - continue; - fjid = b->jobs[jn]->id; - break; - } - // check if this job is the first nonsuspended job on this building; if not, ignore it - // (except for farms) - if (fjid != j->id && b->getType() != df::building_type::FarmPlot) { - continue; - } - - } - - df::unit_labor labor = labor_mapper->find_job_labor (j); - - if (labor != df::unit_labor::NONE) - { - labor_needed[labor]++; - if (worker == -1) - { - if (j->pos.isValid()) - { - df::tile_designation* d = Maps::getTileDesignation(j->pos); - if (d->bits.outside) - labor_outside[labor] = true; - } - } else { - labor_infos[labor].mark_assigned(); - labor_in_use[labor]++; - } - - } + process_job((*jp)->job); } } @@ -1909,6 +1929,32 @@ private: } } + // check if dwarf has an axe, pick, or crossbow + + for (int j = 0; j < dwarf->dwarf->inventory.size(); j++) + { + df::unit_inventory_item* ui = dwarf->dwarf->inventory[j]; + if (ui->mode == df::unit_inventory_item::Weapon && ui->item->isWeapon()) + { + dwarf->armed = true; + df::itemdef_weaponst* weapondef = ((df::item_weaponst*)(ui->item))->subtype; + df::job_skill weaponsk = (df::job_skill) weapondef->skill_melee; + df::job_skill rangesk = (df::job_skill) weapondef->skill_ranged; + if (weaponsk == df::job_skill::AXE) + { + dwarf->has_tool[TOOL_AXE] = true; + } + else if (weaponsk == df::job_skill::MINING) + { + dwarf->has_tool[TOOL_PICK] = true; + } + else if (rangesk == df::job_skill::CROSSBOW) + { + dwarf->has_tool[TOOL_CROSSBOW] = true; + } + } + } + // Find the activity state for each dwarf bool is_on_break = false; @@ -1972,12 +2018,9 @@ private: if (labor != df::unit_labor::NONE) { labor_infos[labor].busy_dwarfs++; - - if (!dwarf->dwarf->status.labors[labor]) + if (default_labor_infos[labor].tool != TOOL_NONE) { - out.print("LABORMANAGER: dwarf %s (id %d) is doing job %s(%d) but is not enabled for labor %s(%d).\n", - dwarf->dwarf->name.first_name.c_str(), dwarf->dwarf->id, - ENUM_KEY_STR(job_type, job).c_str(), job, ENUM_KEY_STR(unit_labor, labor).c_str(), labor); + tool_in_use[default_labor_infos[labor].tool]++; } } } @@ -2044,37 +2087,7 @@ private: } dwarf->high_skill = high_skill; - // check if dwarf has an axe, pick, or crossbow - for (int j = 0; j < dwarf->dwarf->inventory.size(); j++) - { - df::unit_inventory_item* ui = dwarf->dwarf->inventory[j]; - if (ui->mode == df::unit_inventory_item::Weapon && ui->item->isWeapon()) - { - dwarf->armed = true; - df::itemdef_weaponst* weapondef = ((df::item_weaponst*)(ui->item))->subtype; - df::job_skill weaponsk = (df::job_skill) weapondef->skill_melee; - df::job_skill rangesk = (df::job_skill) weapondef->skill_ranged; - if (weaponsk == df::job_skill::AXE) - { - dwarf->has_tool[TOOL_AXE] = true; - if (state != IDLE) - tool_count[TOOL_AXE]--; - } - else if (weaponsk == df::job_skill::MINING) - { - dwarf->has_tool[TOOL_PICK] = 1; - if (state != IDLE) - tool_count[TOOL_PICK]--; - } - else if (rangesk == df::job_skill::CROSSBOW) - { - dwarf->has_tool[TOOL_CROSSBOW] = 1; - if (state != IDLE) - tool_count[TOOL_CROSSBOW]--; - } - } - } // clear labors of dwarfs with clear_all set @@ -2136,7 +2149,10 @@ private: score += 1000; if (default_labor_infos[labor].tool != TOOL_NONE && d->has_tool[default_labor_infos[labor].tool]) - score += 5000; + score += 30000; + if (default_labor_infos[labor].tool != TOOL_NONE && + !d->has_tool[default_labor_infos[labor].tool]) + score -= 30000; if (d->has_children && labor_outside[labor]) score -= 15000; if (d->armed && labor_outside[labor]) @@ -2159,6 +2175,8 @@ public: cnt_setting = cnt_traction = cnt_crutch = 0; need_food_water = 0; + labor_needed.clear(); + for (int e = 0; e < TOOLS_MAX; e++) tool_count[e] = 0; @@ -2194,8 +2212,8 @@ public: // add job entries for designation-related jobs - labor_needed[df::unit_labor::MINE] += std::min(tool_count[TOOL_PICK], dig_count); - labor_needed[df::unit_labor::CUTWOOD] += std::min(tool_count[TOOL_AXE], tree_count); + labor_needed[df::unit_labor::MINE] += dig_count; + labor_needed[df::unit_labor::CUTWOOD] += tree_count; labor_needed[df::unit_labor::DETAIL] += detail_count; labor_needed[df::unit_labor::HERBALIST] += plant_count; @@ -2269,10 +2287,19 @@ public: if (l == df::unit_labor::NONE) continue; + int before = labor_needed[l]; + if (labor_infos[l].idle_dwarfs > 0) labor_needed[l] = 0; else labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); + + if (default_labor_infos[l].tool != TOOL_NONE) + labor_needed[l] = std::min(labor_needed[l], tool_count[default_labor_infos[l].tool] - tool_in_use[default_labor_infos[l].tool]); + + if (print_debug && before != labor_needed[l]) + out.print ("labor %s reduced from %d to %d\n", ENUM_KEY_STR(unit_labor, l).c_str(), before, labor_needed[l]); + } /* assign food haulers for rotting food items */ @@ -2427,19 +2454,30 @@ public: if (l == df::unit_labor::NONE) continue; - if (l == best_labor) + tools_enum t = default_labor_infos[l].tool; + + if (l == best_labor && ( t == TOOL_NONE || tool_in_use[t] < tool_count[t]) ) { set_labor(*bestdwarf, l, true); - tools_enum t = default_labor_infos[l].tool; - if (t != TOOL_NONE) + if (t != TOOL_NONE && (*bestdwarf)->has_tool[t]) { - tool_count[t]--; - if (!(*bestdwarf)->has_tool[t]) - (*bestdwarf)->dwarf->military.pickup_flags.bits.update = true; + df::job_type j; + j = df::job_type::NONE; + + if ((*bestdwarf)->dwarf->job.current_job) + j = (*bestdwarf)->dwarf->job.current_job->job_type; + + if (print_debug) + out.print("LABORMANAGER: asking %s to pick up tools, current job %s\n", (*bestdwarf)->dwarf->name.first_name.c_str(), ENUM_KEY_STR(job_type, j).c_str()); + + (*bestdwarf)->dwarf->military.pickup_flags.bits.update = true; + labors_changed = true; } } else if ((*bestdwarf)->state == IDLE) + { set_labor(*bestdwarf, l, false); + } } if (best_labor == df::unit_labor::HAUL_FOOD && priority_food > 0) @@ -2450,7 +2488,6 @@ public: if (best_labor != df::unit_labor::NONE) { - busy_dwarfs.push_back(*bestdwarf); labor_infos[best_labor].active_dwarfs++; to_assign[best_labor]--; } @@ -2489,6 +2526,8 @@ public: ENUM_KEY_STR(unit_labor, l).c_str(), score, ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score); } + if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000) + set_labor(*d, (*d)->using_labor, false); } } } @@ -2535,7 +2574,7 @@ public: if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && canary & (1 << l)) set_labor(*d, l, true); - else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION) + else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION || l == df::unit_labor::PULL_LEVER) set_labor(*d, l, true); else set_labor(*d, l, false); @@ -2546,16 +2585,42 @@ public: for (auto d = dwarf_info.begin(); d != dwarf_info.end(); d++) { + if ((*d)->dwarf->job.current_job && (*d)->dwarf->job.current_job->job_type == df::job_type::PickupEquipment) + continue; + + if ((*d)->dwarf->military.pickup_flags.bits.update) + continue; + FOR_ENUM_ITEMS (unit_labor, l) { if (l == df::unit_labor::NONE) continue; tools_enum t = default_labor_infos[l].tool; - if (t != TOOL_NONE && tool_count[t] < 0 && (*d)->has_tool[t] && !(*d)->dwarf->status.labors[l]) + if (t == TOOL_NONE) + continue; + + bool has_tool = (*d)->has_tool[t]; + bool needs_tool = (*d)->dwarf->status.labors[l]; + + if (has_tool != needs_tool) { - tool_count[t]++; - (*d)->dwarf->military.pickup_flags.bits.update = 1; + if (has_tool && tool_count[t] > tool_in_use[t]) + continue; + + df::job_type j = df::job_type::NONE; + + if ((*d)->dwarf->job.current_job) + j = (*d)->dwarf->job.current_job->job_type; + + if (print_debug) + out.print("LABORMANAGER: asking %s to %s tools, current job %s, %d %d \n", (*d)->dwarf->name.first_name.c_str(), (has_tool) ? "drop" : "pick up", ENUM_KEY_STR(job_type, j).c_str(), has_tool, needs_tool); + + (*d)->dwarf->military.pickup_flags.bits.update = true; + labors_changed = true; + + if (needs_tool) + tool_in_use[t]++; } } } From 808afca9f01553888e82cec1ec69b25534a36fd8 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 5 Jul 2016 13:16:34 -0500 Subject: [PATCH 032/413] labormanager: add StoreItemInLocation labor, reduce tool churn Note: this commit requires updated df-structures (77968973b28d0e828f880d119a700abb079f3521 or later) --- plugins/devel/labormanager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 545ca7f1c..98b7f0f6f 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -1359,6 +1359,8 @@ public: job_to_labor_table[df::job_type::MakeEarring] = jlf_make_object; job_to_labor_table[df::job_type::MakeBracelet] = jlf_make_object; job_to_labor_table[df::job_type::MakeGem] = jlf_make_object; + + job_to_labor_table[df::job_type::StoreItemInLocation] = jlf_no_labor; // StoreItemInLocation }; df::unit_labor find_job_labor(df::job* j) @@ -1380,7 +1382,7 @@ public: df::unit_labor labor; if (job_to_labor_table.count(j->job_type) == 0) { - debug("LABORMANAGER: job has no job to labor table entry: %s\n", ENUM_KEY_STR(job_type, j->job_type).c_str()); + debug("LABORMANAGER: job has no job to labor table entry: %s (%d)\n", ENUM_KEY_STR(job_type, j->job_type).c_str(), j->job_type); debug_pause(); labor = df::unit_labor::NONE; } else { @@ -2526,7 +2528,7 @@ public: ENUM_KEY_STR(unit_labor, l).c_str(), score, ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score); } - if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000) + if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000 && default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) set_labor(*d, (*d)->using_labor, false); } } From 874a97ed9f8daf33c98c88d166c09fd183b6191b Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 7 Jul 2016 02:10:43 -0500 Subject: [PATCH 033/413] labormanager: fix several job-to-labor mappings --- plugins/devel/labormanager.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 98b7f0f6f..46322a90c 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -1135,7 +1135,7 @@ public: job_to_labor_table[df::job_type::DigChannel] = jlf_const(df::unit_labor::MINE); job_to_labor_table[df::job_type::FellTree] = jlf_const(df::unit_labor::CUTWOOD); job_to_labor_table[df::job_type::GatherPlants] = jlf_const(df::unit_labor::HERBALIST); - job_to_labor_table[df::job_type::RemoveConstruction] = jlf_no_labor; + job_to_labor_table[df::job_type::RemoveConstruction] = jlf_const(df::unit_labor::REMOVE_CONSTRUCTION); job_to_labor_table[df::job_type::CollectWebs] = jlf_const(df::unit_labor::WEAVER); job_to_labor_table[df::job_type::BringItemToDepot] = jlf_const(df::unit_labor::HAUL_TRADE); job_to_labor_table[df::job_type::BringItemToShop] = jlf_no_labor; @@ -1269,13 +1269,13 @@ public: job_to_labor_table[df::job_type::CleanTrap] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::CastSpell] = jlf_no_labor; job_to_labor_table[df::job_type::LinkBuildingToTrigger] = jlf_const(df::unit_labor::MECHANIC) ; - job_to_labor_table[df::job_type::PullLever] = jlf_no_labor; + job_to_labor_table[df::job_type::PullLever] = jlf_const(df::unit_labor::PULL_LEVER); job_to_labor_table[df::job_type::ExtractFromPlants] = jlf_const(df::unit_labor::HERBALIST) ; job_to_labor_table[df::job_type::ExtractFromRawFish] = jlf_const(df::unit_labor::DISSECT_FISH) ; job_to_labor_table[df::job_type::ExtractFromLandAnimal] = jlf_const(df::unit_labor::DISSECT_VERMIN) ; job_to_labor_table[df::job_type::TameVermin] = jlf_const(df::unit_labor::ANIMALTRAIN) ; job_to_labor_table[df::job_type::TameAnimal] = jlf_const(df::unit_labor::ANIMALTRAIN) ; - job_to_labor_table[df::job_type::ChainAnimal] = jlf_no_labor; + job_to_labor_table[df::job_type::ChainAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::UnchainAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::UnchainPet] = jlf_no_labor; job_to_labor_table[df::job_type::ReleaseLargeCreature] = jlf_const(df::unit_labor::HAUL_ANIMALS); @@ -1335,7 +1335,7 @@ public: job_to_labor_table[df::job_type::EngraveSlab] = jlf_const(df::unit_labor::DETAIL); job_to_labor_table[df::job_type::ShearCreature] = jlf_const(df::unit_labor::SHEARER); job_to_labor_table[df::job_type::SpinThread] = jlf_const(df::unit_labor::SPINNER); - job_to_labor_table[df::job_type::PenLargeAnimal] = jlf_no_labor; + job_to_labor_table[df::job_type::PenLargeAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::PenSmallAnimal] = jlf_no_labor; job_to_labor_table[df::job_type::MakeTool] = jlf_make_furniture; job_to_labor_table[df::job_type::CollectClay] = jlf_const(df::unit_labor::POTTERY); @@ -2291,10 +2291,7 @@ public: int before = labor_needed[l]; - if (labor_infos[l].idle_dwarfs > 0) - labor_needed[l] = 0; - else - labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); + labor_needed[l] = max(0, labor_needed[l] - labor_in_use[l]); if (default_labor_infos[l].tool != TOOL_NONE) labor_needed[l] = std::min(labor_needed[l], tool_count[default_labor_infos[l].tool] - tool_in_use[default_labor_infos[l].tool]); From 74f6f3d416bc785fa4d961fb6ce9cd244051d0cd Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 11 Jul 2016 22:29:38 -0500 Subject: [PATCH 034/413] labormanager: add labors for bookcase (de)construct --- plugins/devel/labormanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 46322a90c..cb5f11dfc 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -840,6 +840,7 @@ private: case df::building_type::BarsFloor: case df::building_type::BarsVertical: case df::building_type::GrateWall: + case df::building_type::Bookcase: return df::unit_labor::HAUL_FURNITURE; case df::building_type::Trap: case df::building_type::GearAssembly: @@ -942,6 +943,7 @@ private: case df::building_type::BarsVertical: case df::building_type::GrateFloor: case df::building_type::GrateWall: + case df::building_type::Bookcase: return df::unit_labor::HAUL_FURNITURE; case df::building_type::AnimalTrap: return df::unit_labor::TRAPPER; From ed96725293671eb2f42763c9f0dc6a6355382e44 Mon Sep 17 00:00:00 2001 From: Matthew Lindner Date: Wed, 29 Jun 2016 09:44:42 -0400 Subject: [PATCH 035/413] Add protection from spaces in path and add warning in documentation --- docs/Introduction.rst | 2 ++ package/darwin/dfhack | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/Introduction.rst b/docs/Introduction.rst index 64b6b36a5..9c4a276d2 100644 --- a/docs/Introduction.rst +++ b/docs/Introduction.rst @@ -52,6 +52,8 @@ into your DF folder, so that: * On Windows, ``SDL.dll`` is replaced * On Linux or OSX, the ``dfhack`` script is placed in the same folder as the ``df`` script +Additionally, on OSX, make sure that the directories in the DF folder path do not contain any '/' or ':' characters. + Uninstalling is basically the same, in reverse: * On Windows, replace ``SDL.dll`` with ``SDLreal.dll``, then remove the DFHack files. diff --git a/package/darwin/dfhack b/package/darwin/dfhack index 66b574cf8..a97970801 100755 --- a/package/darwin/dfhack +++ b/package/darwin/dfhack @@ -4,11 +4,11 @@ cd "${PWD}" #thanks to Iriel for figuring this out OSREV=`uname -r | cut -d. -f1` if [ "$OSREV" -ge 11 ] ; then - export DYLD_LIBRARY_PATH=${PWD}/hack:${PWD}/libs:${PWD}/hack/libs - export DYLD_FRAMEWORK_PATH=${PWD}/hack:${PWD}/libs:${PWD}/hack/libs + export DYLD_LIBRARY_PATH="${PWD}/hack:${PWD}/libs:${PWD}/hack/libs" + export DYLD_FRAMEWORK_PATH="${PWD}/hack:${PWD}/libs:${PWD}/hack/libs" else - export DYLD_FALLBACK_LIBRARY_PATH=${PWD}/hack:${PWD}/libs:${PWD}/hack/libs - export DYLD_FALLBACK_FRAMEWORK_PATH=${PWD}/hack:${PWD}/libs:${PWD}/hack/libs + export DYLD_FALLBACK_LIBRARY_PATH="${PWD}/hack:${PWD}/libs:${PWD}/hack/libs" + export DYLD_FALLBACK_FRAMEWORK_PATH="${PWD}/hack:${PWD}/libs:${PWD}/hack/libs" fi old_tty_settings=$(stty -g) From af6fed58f0cacccc8c379cbab625ef90dc0e13b5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 12 Jul 2016 14:51:31 -0400 Subject: [PATCH 036/413] Add @mlindner to Authors.rst --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index ee6f80390..5e919a846 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -52,6 +52,7 @@ Kurik Amudnil Lethosor lethosor Mason11987 Mason11987 Matthew Cline +Matthew Lindner mlindner Max maxthyme Max^TM melkor217 melkor217 Meneth32 From e357d9e40b5ea62d0ee1bdd960bdcbc18d6d6c6e Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 12 Jul 2016 14:53:22 -0400 Subject: [PATCH 037/413] OSX -> OS X --- docs/Introduction.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Introduction.rst b/docs/Introduction.rst index 9c4a276d2..68eb4844f 100644 --- a/docs/Introduction.rst +++ b/docs/Introduction.rst @@ -50,14 +50,14 @@ Installing DFhack involves copying files from a release archive into your DF folder, so that: * On Windows, ``SDL.dll`` is replaced -* On Linux or OSX, the ``dfhack`` script is placed in the same folder as the ``df`` script Additionally, on OSX, make sure that the directories in the DF folder path do not contain any '/' or ':' characters. +* On Linux or OS X, the ``dfhack`` script is placed in the same folder as the ``df`` script Uninstalling is basically the same, in reverse: * On Windows, replace ``SDL.dll`` with ``SDLreal.dll``, then remove the DFHack files. -* On Linux or OSX, remove the DFHack files. +* On Linux or OS X, remove the DFHack files. New players may wish to :wiki:`get a pack ` with DFHack preinstalled. From eef66b0db1ac6d3ca4578762e864b6b9903f7a48 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 12 Jul 2016 14:54:06 -0400 Subject: [PATCH 038/413] Get rid of OS X path restrictions (see package/linux/dfhack) --- docs/Introduction.rst | 2 -- package/darwin/dfhack | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/Introduction.rst b/docs/Introduction.rst index 68eb4844f..3a36aa538 100644 --- a/docs/Introduction.rst +++ b/docs/Introduction.rst @@ -50,8 +50,6 @@ Installing DFhack involves copying files from a release archive into your DF folder, so that: * On Windows, ``SDL.dll`` is replaced - -Additionally, on OSX, make sure that the directories in the DF folder path do not contain any '/' or ':' characters. * On Linux or OS X, the ``dfhack`` script is placed in the same folder as the ``df`` script Uninstalling is basically the same, in reverse: diff --git a/package/darwin/dfhack b/package/darwin/dfhack index a97970801..445b600f7 100755 --- a/package/darwin/dfhack +++ b/package/darwin/dfhack @@ -4,11 +4,11 @@ cd "${PWD}" #thanks to Iriel for figuring this out OSREV=`uname -r | cut -d. -f1` if [ "$OSREV" -ge 11 ] ; then - export DYLD_LIBRARY_PATH="${PWD}/hack:${PWD}/libs:${PWD}/hack/libs" - export DYLD_FRAMEWORK_PATH="${PWD}/hack:${PWD}/libs:${PWD}/hack/libs" + export DYLD_LIBRARY_PATH="./hack:./libs:./hack/libs" + export DYLD_FRAMEWORK_PATH="./hack:./libs:./hack/libs" else - export DYLD_FALLBACK_LIBRARY_PATH="${PWD}/hack:${PWD}/libs:${PWD}/hack/libs" - export DYLD_FALLBACK_FRAMEWORK_PATH="${PWD}/hack:${PWD}/libs:${PWD}/hack/libs" + export DYLD_FALLBACK_LIBRARY_PATH="./hack:./libs:./hack/libs" + export DYLD_FALLBACK_FRAMEWORK_PATH="./hack:./libs:./hack/libs" fi old_tty_settings=$(stty -g) From 29963f4b67b9edae74cd69e159bb63730b524d27 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 26 Jul 2016 22:51:42 -0400 Subject: [PATCH 039/413] Rename script-in-readme to script-docs --- .travis.yml | 2 +- travis/{script-in-readme.py => script-docs.py} | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) rename travis/{script-in-readme.py => script-docs.py} (90%) diff --git a/.travis.yml b/.travis.yml index 1455044aa..5e60a1461 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ script: - python travis/pr-check-base.py - python travis/lint.py - python travis/authors-rst.py -- python travis/script-in-readme.py +- python travis/script-docs.py - python travis/script-syntax.py --ext=lua --cmd="luac5.2 -p" - python travis/script-syntax.py --ext=rb --cmd="ruby -c" - mkdir build-travis diff --git a/travis/script-in-readme.py b/travis/script-docs.py similarity index 90% rename from travis/script-in-readme.py rename to travis/script-docs.py index 154304420..2bce4bfd2 100644 --- a/travis/script-in-readme.py +++ b/travis/script-docs.py @@ -4,6 +4,7 @@ import os from os.path import basename, dirname, join, splitext import sys +SCRIPT_PATH = sys.argv[1] if len(sys.argv) > 1 else 'scripts' def expected_cmd(path): """Get the command from the name of a script.""" @@ -54,9 +55,9 @@ def check_file(fname): def main(): - """Check that all DFHack scripts include documentation (not 3rdparty)""" + """Check that all DFHack scripts include documentation""" err = 0 - for root, _, files in os.walk('scripts'): + for root, _, files in os.walk(SCRIPT_PATH): for f in files: if f[-3:] in {'.rb', 'lua'}: err += check_file(join(root, f)) @@ -64,4 +65,4 @@ def main(): if __name__ == '__main__': - sys.exit(bool(main())) + sys.exit(min(100, main())) From e2c63509788fa3109ea0a6b3e06fe2a13e5f7cd7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 26 Jul 2016 23:23:26 -0400 Subject: [PATCH 040/413] Update Lua to 5.3.3 --- depends/lua/include/lapi.h | 2 +- depends/lua/include/lauxlib.h | 96 ++- depends/lua/include/lcode.h | 15 +- depends/lua/include/lctype.h | 2 +- depends/lua/include/ldebug.h | 19 +- depends/lua/include/ldo.h | 28 +- depends/lua/include/lfunc.h | 38 +- depends/lua/include/lgc.h | 112 ++- depends/lua/include/llex.h | 17 +- depends/lua/include/llimits.h | 280 +++---- depends/lua/include/lmem.h | 30 +- depends/lua/include/lobject.h | 424 +++++------ depends/lua/include/lopcodes.h | 39 +- depends/lua/include/lparser.h | 68 +- depends/lua/include/lprefix.h | 45 ++ depends/lua/include/lstate.h | 168 +++-- depends/lua/include/lstring.h | 21 +- depends/lua/include/ltable.h | 25 +- depends/lua/include/ltm.h | 29 +- depends/lua/include/lua.h | 178 +++-- depends/lua/include/luaconf.h | 712 +++++++++++------- depends/lua/include/lualib.h | 5 +- depends/lua/include/lundump.h | 26 +- depends/lua/include/lvm.h | 99 ++- depends/lua/include/lzio.h | 11 +- depends/lua/src/lapi.c | 582 ++++++++------- depends/lua/src/lauxlib.c | 370 ++++++---- depends/lua/src/lbaselib.c | 226 +++--- depends/lua/src/lbitlib.c | 111 +-- depends/lua/src/lcode.c | 828 ++++++++++++++------- depends/lua/src/lcorolib.c | 33 +- depends/lua/src/lctype.c | 5 +- depends/lua/src/ldblib.c | 230 +++--- depends/lua/src/ldebug.c | 240 ++++-- depends/lua/src/ldo.c | 387 ++++++---- depends/lua/src/ldump.c | 300 ++++---- depends/lua/src/lfunc.c | 118 ++- depends/lua/src/lgc.c | 936 +++++++++++------------ depends/lua/src/linit.c | 41 +- depends/lua/src/liolib.c | 298 +++++--- depends/lua/src/llex.c | 297 ++++---- depends/lua/src/lmathlib.c | 336 ++++++--- depends/lua/src/lmem.c | 23 +- depends/lua/src/loadlib.c | 258 ++++--- depends/lua/src/lobject.c | 382 ++++++++-- depends/lua/src/lopcodes.c | 25 +- depends/lua/src/loslib.c | 260 ++++--- depends/lua/src/lparser.c | 224 +++--- depends/lua/src/lstate.c | 120 +-- depends/lua/src/lstring.c | 217 ++++-- depends/lua/src/lstrlib.c | 921 ++++++++++++++++++----- depends/lua/src/ltable.c | 427 ++++++----- depends/lua/src/ltablib.c | 401 +++++++--- depends/lua/src/ltm.c | 112 ++- depends/lua/src/lua.c | 518 ++++++++----- depends/lua/src/luac.c | 49 +- depends/lua/src/lundump.c | 427 ++++++----- depends/lua/src/lutf8lib.c | 256 +++++++ depends/lua/src/lvm.c | 1271 ++++++++++++++++++++++---------- depends/lua/src/lzio.c | 20 +- 60 files changed, 8743 insertions(+), 4995 deletions(-) create mode 100644 depends/lua/include/lprefix.h create mode 100644 depends/lua/src/lutf8lib.c diff --git a/depends/lua/include/lapi.h b/depends/lua/include/lapi.h index c7d34ad84..6d36dee3f 100644 --- a/depends/lua/include/lapi.h +++ b/depends/lua/include/lapi.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ diff --git a/depends/lua/include/lauxlib.h b/depends/lua/include/lauxlib.h index 0fb023b8e..ddb7c2283 100644 --- a/depends/lua/include/lauxlib.h +++ b/depends/lua/include/lauxlib.h @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.h,v 1.120.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -16,7 +16,7 @@ -/* extra error code for `luaL_load' */ +/* extra error code for 'luaL_load' */ #define LUA_ERRFILE (LUA_ERRERR+1) @@ -26,30 +26,30 @@ typedef struct luaL_Reg { } luaL_Reg; -LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver); -#define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM) +#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) + +LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); +#define luaL_checkversion(L) \ + luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); -LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); -LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, +LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, size_t *l); -LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, const char *def, size_t *l); -LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); -LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); -LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); -LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, lua_Integer def); -LUALIB_API lua_Unsigned (luaL_checkunsigned) (lua_State *L, int numArg); -LUALIB_API lua_Unsigned (luaL_optunsigned) (lua_State *L, int numArg, - lua_Unsigned def); LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); -LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); -LUALIB_API void (luaL_checkany) (lua_State *L, int narg); +LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int arg); LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); @@ -59,13 +59,13 @@ LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); LUALIB_API void (luaL_where) (lua_State *L, int lvl); LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); -LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, +LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, const char *const lst[]); LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); LUALIB_API int (luaL_execresult) (lua_State *L, int stat); -/* pre-defined references */ +/* predefined references */ #define LUA_NOREF (-2) #define LUA_REFNIL (-1) @@ -83,7 +83,7 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); -LUALIB_API int (luaL_len) (lua_State *L, int idx); +LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); @@ -108,16 +108,13 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, #define luaL_newlibtable(L,l) \ lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) -#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) +#define luaL_newlib(L,l) \ + (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) -#define luaL_argcheck(L, cond,numarg,extramsg) \ - ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) +#define luaL_argcheck(L, cond,arg,extramsg) \ + ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) -#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) -#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) -#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) -#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) @@ -207,6 +204,53 @@ LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, #endif +/* +** {================================================================== +** "Abstraction Layer" for basic report of messages and errors +** =================================================================== +*/ + +/* print a string */ +#if !defined(lua_writestring) +#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) +#endif + +/* print a newline and flush the output */ +#if !defined(lua_writeline) +#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) +#endif + +/* print an error message */ +#if !defined(lua_writestringerror) +#define lua_writestringerror(s,p) \ + (fprintf(stderr, (s), (p)), fflush(stderr)) +#endif + +/* }================================================================== */ + + +/* +** {============================================================ +** Compatibility with deprecated conversions +** ============================================================= +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) +#define luaL_optunsigned(L,a,d) \ + ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) + +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) + +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) + +#endif +/* }============================================================ */ + + + #endif diff --git a/depends/lua/include/lcode.h b/depends/lua/include/lcode.h index 6a1424cf5..cd306d573 100644 --- a/depends/lua/include/lcode.h +++ b/depends/lua/include/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.58.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -24,7 +24,11 @@ ** grep "ORDER OPR" if you change these enums (ORDER OP) */ typedef enum BinOpr { - OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, + OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, + OPR_DIV, + OPR_IDIV, + OPR_BAND, OPR_BOR, OPR_BXOR, + OPR_SHL, OPR_SHR, OPR_CONCAT, OPR_EQ, OPR_LT, OPR_LE, OPR_NE, OPR_GT, OPR_GE, @@ -33,10 +37,11 @@ typedef enum BinOpr { } BinOpr; -typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; +typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; -#define getcode(fs,e) ((fs)->f->code[(e)->u.info]) +/* get (pointer to) instruction of given 'expdesc' */ +#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info]) #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) @@ -52,7 +57,7 @@ LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); -LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r); +LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n); LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); diff --git a/depends/lua/include/lctype.h b/depends/lua/include/lctype.h index b09b21a33..99c7d1223 100644 --- a/depends/lua/include/lctype.h +++ b/depends/lua/include/lctype.h @@ -1,5 +1,5 @@ /* -** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ ** 'ctype' functions for Lua ** See Copyright Notice in lua.h */ diff --git a/depends/lua/include/ldebug.h b/depends/lua/include/ldebug.h index 6445c763e..0e31546b1 100644 --- a/depends/lua/include/ldebug.h +++ b/depends/lua/include/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -13,22 +13,27 @@ #define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) -#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) +#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1) #define resethookcount(L) (L->hookcount = L->basehookcount) -/* Active Lua function (given call info) */ -#define ci_func(ci) (clLvalue((ci)->func)) - LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *opname); -LUAI_FUNC l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2); -LUAI_FUNC l_noret luaG_aritherror (lua_State *L, const TValue *p1, +LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, + const TValue *p2); +LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, + const char *msg); +LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); +LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, + TString *src, int line); LUAI_FUNC l_noret luaG_errormsg (lua_State *L); +LUAI_FUNC void luaG_traceexec (lua_State *L); + #endif diff --git a/depends/lua/include/ldo.h b/depends/lua/include/ldo.h index d3d3082c9..4f5d51c3c 100644 --- a/depends/lua/include/ldo.h +++ b/depends/lua/include/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.20.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -13,31 +13,43 @@ #include "lzio.h" -#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \ - luaD_growstack(L, n); else condmovestack(L); +/* +** Macro to check stack size and grow stack if needed. Parameters +** 'pre'/'pos' allow the macro to preserve a pointer into the +** stack across reallocations, doing the work only when needed. +** 'condmovestack' is used in heavy tests to force a stack reallocation +** at every check. +*/ +#define luaD_checkstackaux(L,n,pre,pos) \ + if (L->stack_last - L->top <= (n)) \ + { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } + +/* In general, 'pre'/'pos' are empty (nothing to save) */ +#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) -#define incr_top(L) {L->top++; luaD_checkstack(L,0);} #define savestack(L,p) ((char *)(p) - (char *)L->stack) #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) -/* type of protected functions, to be ran by `runprotected' */ +/* type of protected functions, to be ran by 'runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode); LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); -LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults, - int allowyield); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); -LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); +LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, + int nres); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); LUAI_FUNC void luaD_shrinkstack (lua_State *L); +LUAI_FUNC void luaD_inctop (lua_State *L); LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); diff --git a/depends/lua/include/lfunc.h b/depends/lua/include/lfunc.h index ca0d3a3e0..2eeb0d5a4 100644 --- a/depends/lua/include/lfunc.h +++ b/depends/lua/include/lfunc.h @@ -1,5 +1,5 @@ /* -** $Id: lfunc.h,v 2.8.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -18,14 +18,42 @@ cast(int, sizeof(TValue *)*((n)-1))) +/* test whether thread is in 'twups' list */ +#define isintwups(L) (L->twups != L) + + +/* +** maximum number of upvalues in a closure (both C and Lua). (Value +** must fit in a VM register.) +*/ +#define MAXUPVAL 255 + + +/* +** Upvalues for Lua closures +*/ +struct UpVal { + TValue *v; /* points to stack or to its own value */ + lu_mem refcount; /* reference counter */ + union { + struct { /* (when open) */ + UpVal *next; /* linked list */ + int touched; /* mark to avoid cycles with dead threads */ + } open; + TValue value; /* the value (when closed) */ + } u; +}; + +#define upisopen(up) ((up)->v != &(up)->u.value) + + LUAI_FUNC Proto *luaF_newproto (lua_State *L); -LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); -LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems); -LUAI_FUNC UpVal *luaF_newupval (lua_State *L); +LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); +LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); +LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); -LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, int pc); diff --git a/depends/lua/include/lgc.h b/depends/lua/include/lgc.h index 84bb1cdf9..aed3e18a5 100644 --- a/depends/lua/include/lgc.h +++ b/depends/lua/include/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -38,36 +38,27 @@ */ #define GCSpropagate 0 #define GCSatomic 1 -#define GCSsweepstring 2 -#define GCSsweepudata 3 -#define GCSsweep 4 -#define GCSpause 5 +#define GCSswpallgc 2 +#define GCSswpfinobj 3 +#define GCSswptobefnz 4 +#define GCSswpend 5 +#define GCScallfin 6 +#define GCSpause 7 #define issweepphase(g) \ - (GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) + (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) -#define isgenerational(g) ((g)->gckind == KGC_GEN) /* -** macros to tell when main invariant (white objects cannot point to black -** ones) must be kept. During a non-generational collection, the sweep +** macro to tell when main invariant (white objects cannot point to black +** ones) must be kept. During a collection, the sweep ** phase may break the invariant, as objects turned white may point to ** still-black objects. The invariant is restored when sweep ends and -** all objects are white again. During a generational collection, the -** invariant must be kept all times. +** all objects are white again. */ -#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) +#define keepinvariant(g) ((g)->gcstate <= GCSatomic) /* @@ -83,75 +74,74 @@ #define testbit(x,b) testbits(x, bitmask(b)) -/* Layout for bit use in `marked' field: */ +/* Layout for bit use in 'marked' field: */ #define WHITE0BIT 0 /* object is white (type 0) */ #define WHITE1BIT 1 /* object is white (type 1) */ #define BLACKBIT 2 /* object is black */ -#define FINALIZEDBIT 3 /* object has been separated for finalization */ -#define SEPARATED 4 /* object is in 'finobj' list or in 'tobefnz' */ -#define FIXEDBIT 5 /* object is fixed (should not be collected) */ -#define OLDBIT 6 /* object is old (only in generational mode) */ +#define FINALIZEDBIT 3 /* object has been marked for finalization */ /* bit 7 is currently used by tests (luaL_checkmemory) */ #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) -#define iswhite(x) testbits((x)->gch.marked, WHITEBITS) -#define isblack(x) testbit((x)->gch.marked, BLACKBIT) +#define iswhite(x) testbits((x)->marked, WHITEBITS) +#define isblack(x) testbit((x)->marked, BLACKBIT) #define isgray(x) /* neither white nor black */ \ - (!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT))) - -#define isold(x) testbit((x)->gch.marked, OLDBIT) + (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) -/* MOVE OLD rule: whenever an object is moved to the beginning of - a GC list, its old bit must be cleared */ -#define resetoldbit(o) resetbit((o)->gch.marked, OLDBIT) +#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) -#define otherwhite(g) (g->currentwhite ^ WHITEBITS) +#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) #define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) -#define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked) +#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) -#define changewhite(x) ((x)->gch.marked ^= WHITEBITS) -#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) - -#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) +#define changewhite(x) ((x)->marked ^= WHITEBITS) +#define gray2black(x) l_setbit((x)->marked, BLACKBIT) #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) -#define luaC_condGC(L,c) \ - {if (G(L)->GCdebt > 0) {c;}; condchangemem(L);} -#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);) +/* +** Does one step of collection when debt becomes positive. 'pre'/'pos' +** allows some adjustments to be done only when needed. macro +** 'condchangemem' is used only for heavy tests (forcing a full +** GC cycle on every opportunity) +*/ +#define luaC_condGC(L,pre,pos) \ + { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ + condchangemem(L,pre,pos); } +/* more often than not, 'pre'/'pos' are empty */ +#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) -#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ - luaC_barrier_(L,obj2gco(p),gcvalue(v)); } -#define luaC_barrierback(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ - luaC_barrierback_(L,p); } +#define luaC_barrier(L,p,v) ( \ + (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ + luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0)) -#define luaC_objbarrier(L,p,o) \ - { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ - luaC_barrier_(L,obj2gco(p),obj2gco(o)); } +#define luaC_barrierback(L,p,v) ( \ + (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ + luaC_barrierback_(L,p) : cast_void(0)) -#define luaC_objbarrierback(L,p,o) \ - { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); } +#define luaC_objbarrier(L,p,o) ( \ + (isblack(p) && iswhite(o)) ? \ + luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) -#define luaC_barrierproto(L,p,c) \ - { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); } +#define luaC_upvalbarrier(L,uv) ( \ + (iscollectable((uv)->v) && !upisopen(uv)) ? \ + luaC_upvalbarrier_(L,uv) : cast_void(0)) +LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); -LUAI_FUNC void luaC_forcestep (lua_State *L); LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); -LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, - GCObject **list, int offset); +LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); -LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); -LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c); +LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); +LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); -LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv); -LUAI_FUNC void luaC_changemode (lua_State *L, int mode); +LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); + #endif diff --git a/depends/lua/include/llex.h b/depends/lua/include/llex.h index a4acdd302..2363d87e4 100644 --- a/depends/lua/include/llex.h +++ b/depends/lua/include/llex.h @@ -1,5 +1,5 @@ /* -** $Id: llex.h,v 1.72.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ @@ -14,6 +14,10 @@ #define FIRST_RESERVED 257 +#if !defined(LUA_ENV) +#define LUA_ENV "_ENV" +#endif + /* * WARNING: if you change the order of this enumeration, @@ -26,8 +30,10 @@ enum RESERVED { TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ - TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_DBCOLON, TK_EOS, - TK_NUMBER, TK_NAME, TK_STRING + TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, + TK_SHL, TK_SHR, + TK_DBCOLON, TK_EOS, + TK_FLT, TK_INT, TK_NAME, TK_STRING }; /* number of reserved words */ @@ -36,6 +42,7 @@ enum RESERVED { typedef union { lua_Number r; + lua_Integer i; TString *ts; } SemInfo; /* semantics information */ @@ -51,17 +58,17 @@ typedef struct Token { typedef struct LexState { int current; /* current character (charint) */ int linenumber; /* input line counter */ - int lastline; /* line of last token `consumed' */ + int lastline; /* line of last token 'consumed' */ Token t; /* current token */ Token lookahead; /* look ahead token */ struct FuncState *fs; /* current function (parser) */ struct lua_State *L; ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ + Table *h; /* to avoid collection/reuse strings */ struct Dyndata *dyd; /* dynamic structures used by the parser */ TString *source; /* current source name */ TString *envn; /* environment variable name */ - char decpoint; /* locale decimal point */ } LexState; diff --git a/depends/lua/include/llimits.h b/depends/lua/include/llimits.h index 152dd0551..f21377fef 100644 --- a/depends/lua/include/llimits.h +++ b/depends/lua/include/llimits.h @@ -1,6 +1,6 @@ /* -** $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 +** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $ +** Limits, basic types, and some other 'installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -14,54 +14,77 @@ #include "lua.h" - -typedef unsigned LUA_INT32 lu_int32; - +/* +** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count +** the total memory used by Lua (in bytes). Usually, 'size_t' and +** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. +*/ +#if defined(LUAI_MEM) /* { external definitions? */ typedef LUAI_UMEM lu_mem; - typedef LUAI_MEM l_mem; +#elif LUAI_BITSINT >= 32 /* }{ */ +typedef size_t lu_mem; +typedef ptrdiff_t l_mem; +#else /* 16-bit ints */ /* }{ */ +typedef unsigned long lu_mem; +typedef long l_mem; +#endif /* } */ - -/* chars used as small naturals (so that `char' is reserved for characters) */ +/* chars used as small naturals (so that 'char' is reserved for characters) */ typedef unsigned char lu_byte; -#define MAX_SIZET ((size_t)(~(size_t)0)-2) +/* maximum value for size_t */ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +/* maximum size visible for Lua (must be representable in a lua_Integer */ +#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ + : (size_t)(LUA_MAXINTEGER)) + -#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) -#define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2)) +#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) -#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ +#define MAX_INT INT_MAX /* maximum value of an int */ + /* -** conversion of pointer to integer +** conversion of pointer to unsigned integer: ** this is for hashing only; there is no problem if the integer ** cannot hold the whole pointer value */ -#define IntPoint(p) ((unsigned int)(lu_mem)(p)) +#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) /* type to ensure maximum alignment */ -#if !defined(LUAI_USER_ALIGNMENT_T) -#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } +#if defined(LUAI_USER_ALIGNMENT_T) +typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; +#else +typedef union { + lua_Number n; + double u; + void *s; + lua_Integer i; + long l; +} L_Umaxalign; #endif -typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; -/* result of a `usual argument conversion' over lua_Number */ +/* types of 'usual argument conversions' for lua_Number and lua_Integer */ typedef LUAI_UACNUMBER l_uacNumber; +typedef LUAI_UACINT l_uacInt; /* internal assertions for in-house debugging */ #if defined(lua_assert) #define check_exp(c,e) (lua_assert(c), (e)) /* to avoid problems with conditions too long */ -#define lua_longassert(c) { if (!(c)) lua_assert(0); } +#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0)) #else #define lua_assert(c) ((void)0) #define check_exp(c,e) (e) @@ -72,38 +95,49 @@ typedef LUAI_UACNUMBER l_uacNumber; ** assertion for checking API calls */ #if !defined(luai_apicheck) - -#if defined(LUA_USE_APICHECK) -#include -#define luai_apicheck(L,e) assert(e) -#else -#define luai_apicheck(L,e) lua_assert(e) -#endif - +#define luai_apicheck(l,e) lua_assert(e) #endif #define api_check(l,e,msg) luai_apicheck(l,(e) && msg) +/* macro to avoid warnings about unused variables */ #if !defined(UNUSED) -#define UNUSED(x) ((void)(x)) /* to avoid warnings */ +#define UNUSED(x) ((void)(x)) #endif +/* type casts (a macro highlights casts in the code) */ #define cast(t, exp) ((t)(exp)) +#define cast_void(i) cast(void, (i)) #define cast_byte(i) cast(lu_byte, (i)) #define cast_num(i) cast(lua_Number, (i)) #define cast_int(i) cast(int, (i)) #define cast_uchar(i) cast(unsigned char, (i)) +/* cast a signed lua_Integer to lua_Unsigned */ +#if !defined(l_castS2U) +#define l_castS2U(i) ((lua_Unsigned)(i)) +#endif + +/* +** cast a lua_Unsigned to a signed lua_Integer; this cast is +** not strict ISO C, but two-complement architectures should +** work fine. +*/ +#if !defined(l_castU2S) +#define l_castU2S(i) ((lua_Integer)(i)) +#endif + + /* ** non-return type */ #if defined(__GNUC__) #define l_noret void __attribute__((noreturn)) -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && _MSC_VER >= 1200 #define l_noret void __declspec(noreturn) #else #define l_noret void @@ -119,29 +153,50 @@ typedef LUAI_UACNUMBER l_uacNumber; #define LUAI_MAXCCALLS 200 #endif -/* -** maximum number of upvalues in a closure (both C and Lua). (Value -** must fit in an unsigned char.) -*/ -#define MAXUPVAL UCHAR_MAX /* -** type for virtual-machine instructions +** type for virtual-machine instructions; ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) */ -typedef lu_int32 Instruction; - +#if LUAI_BITSINT >= 32 +typedef unsigned int Instruction; +#else +typedef unsigned long Instruction; +#endif -/* maximum stack for a Lua function */ -#define MAXSTACK 250 +/* +** Maximum length for short strings, that is, strings that are +** internalized. (Cannot be smaller than reserved words or tags for +** metamethods, as these strings must be internalized; +** #("function") = 8, #("__newindex") = 10.) +*/ +#if !defined(LUAI_MAXSHORTLEN) +#define LUAI_MAXSHORTLEN 40 +#endif -/* minimum size for the string table (must be power of 2) */ +/* +** Initial size for the string table (must be power of 2). +** The Lua core alone registers ~50 strings (reserved words + +** metaevent keys + a few others). Libraries would typically add +** a few dozens more. +*/ #if !defined(MINSTRTABSIZE) -#define MINSTRTABSIZE 32 +#define MINSTRTABSIZE 128 +#endif + + +/* +** Size of cache for strings in the API. 'N' is the number of +** sets (better be a prime) and "M" is the size of each set (M == 1 +** makes a direct cache.) +*/ +#if !defined(STRCACHE_N) +#define STRCACHE_N 53 +#define STRCACHE_M 2 #endif @@ -151,13 +206,21 @@ typedef lu_int32 Instruction; #endif +/* +** macros that are executed whenever program enters the Lua core +** ('lua_lock') and leaves the core ('lua_unlock') +*/ #if !defined(lua_lock) -#define lua_lock(L) ((void) 0) -#define lua_unlock(L) ((void) 0) +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) #endif +/* +** macro executed during Lua functions at points where the +** function can yield. +*/ #if !defined(luai_threadyield) -#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} #endif @@ -183,127 +246,78 @@ typedef lu_int32 Instruction; #endif #if !defined(luai_userstateresume) -#define luai_userstateresume(L,n) ((void)L) +#define luai_userstateresume(L,n) ((void)L) #endif #if !defined(luai_userstateyield) -#define luai_userstateyield(L,n) ((void)L) +#define luai_userstateyield(L,n) ((void)L) #endif -/* -** lua_number2int is a macro to convert lua_Number to int. -** lua_number2integer is a macro to convert lua_Number to lua_Integer. -** lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned. -** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number. -** luai_hashnum is a macro to hash a lua_Number value into an integer. -** The hash must be deterministic and give reasonable values for -** both small and large values (outside the range of integers). -*/ - -#if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */ -/* trick with Microsoft assembler for X86 */ - -#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} -#define lua_number2integer(i,n) lua_number2int(i, n) -#define lua_number2unsigned(i,n) \ - {__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;} - - -#elif defined(LUA_IEEE754TRICK) /* }{ */ -/* the next trick should work on any machine using IEEE754 with - a 32-bit int type */ - -union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; - -#if !defined(LUA_IEEEENDIAN) /* { */ -#define LUAI_EXTRAIEEE \ - static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)}; -#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33) -#else -#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN -#define LUAI_EXTRAIEEE /* empty */ -#endif /* } */ -#define lua_number2int32(i,n,t) \ - { LUAI_EXTRAIEEE \ - volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ - (i) = (t)u.l_p[LUA_IEEEENDIANLOC]; } -#define luai_hashnum(i,n) \ - { volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \ - (i) = u.l_p[0]; (i) += u.l_p[1]; } /* add double bits for his hash */ - -#define lua_number2int(i,n) lua_number2int32(i, n, int) -#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned) +/* +** The luai_num* macros define the primitive operations over numbers. +*/ -/* the trick can be expanded to lua_Integer when it is a 32-bit value */ -#if defined(LUA_IEEELL) -#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer) +/* floor division (defined as 'floor(a/b)') */ +#if !defined(luai_numidiv) +#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b))) #endif -#endif /* } */ - - -/* the following definitions always work, but may be slow */ - -#if !defined(lua_number2int) -#define lua_number2int(i,n) ((i)=(int)(n)) +/* float division */ +#if !defined(luai_numdiv) +#define luai_numdiv(L,a,b) ((a)/(b)) #endif -#if !defined(lua_number2integer) -#define lua_number2integer(i,n) ((i)=(lua_Integer)(n)) +/* +** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when +** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of +** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b) +** ~= floor(a/b)'. That happens when the division has a non-integer +** negative result, which is equivalent to the test below. +*/ +#if !defined(luai_nummod) +#define luai_nummod(L,a,b,m) \ + { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); } #endif -#if !defined(lua_number2unsigned) /* { */ -/* the following definition assures proper modulo behavior */ -#if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT) -#include -#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1) -#define lua_number2unsigned(i,n) \ - ((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED)) -#else -#define lua_number2unsigned(i,n) ((i)=(lua_Unsigned)(n)) +/* exponentiation */ +#if !defined(luai_numpow) +#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b)) #endif -#endif /* } */ - -#if !defined(lua_unsigned2number) -/* on several machines, coercion from unsigned to double is slow, - so it may be worth to avoid */ -#define lua_unsigned2number(u) \ - (((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u)) +/* the others are quite standard operations */ +#if !defined(luai_numadd) +#define luai_numadd(L,a,b) ((a)+(b)) +#define luai_numsub(L,a,b) ((a)-(b)) +#define luai_nummul(L,a,b) ((a)*(b)) +#define luai_numunm(L,a) (-(a)) +#define luai_numeq(a,b) ((a)==(b)) +#define luai_numlt(a,b) ((a)<(b)) +#define luai_numle(a,b) ((a)<=(b)) +#define luai_numisnan(a) (!luai_numeq((a), (a))) #endif -#if defined(ltable_c) && !defined(luai_hashnum) - -#include -#include - -#define luai_hashnum(i,n) { int e; \ - n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ - lua_number2int(i, n); i += e; } - -#endif - /* ** macro to control inclusion of some hard tests on stack reallocation */ #if !defined(HARDSTACKTESTS) -#define condmovestack(L) ((void)0) +#define condmovestack(L,pre,pos) ((void)0) #else /* realloc stack keeping its size */ -#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize) +#define condmovestack(L,pre,pos) \ + { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; } #endif #if !defined(HARDMEMTESTS) -#define condchangemem(L) condmovestack(L) +#define condchangemem(L,pre,pos) ((void)0) #else -#define condchangemem(L) \ - ((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1))) +#define condchangemem(L,pre,pos) \ + { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } #endif #endif diff --git a/depends/lua/include/lmem.h b/depends/lua/include/lmem.h index bd4f4e072..30f484895 100644 --- a/depends/lua/include/lmem.h +++ b/depends/lua/include/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lmem.h,v 1.43 2014/12/19 17:26:14 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -15,20 +15,32 @@ /* -** 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". +** This macro reallocs a vector 'b' from 'on' to 'n' elements, where +** each element has size 'e'. In case of arithmetic overflow of the +** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because +** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e). +** +** (The macro is somewhat complex to avoid warnings: The 'sizeof' +** comparison avoids a runtime comparison when overflow cannot occur. +** The compiler should be able to optimize the real test by itself, but +** when it does it, it may give a warning about "comparison is always +** false due to limited range of data type"; the +1 tricks the compiler, +** avoiding this warning but also this optimization.) */ #define luaM_reallocv(L,b,on,n,e) \ - (cast(void, \ - (cast(size_t, (n)+1) > MAX_SIZET/(e)) ? (luaM_toobig(L), 0) : 0), \ + (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \ + ? luaM_toobig(L) : cast_void(0)) , \ luaM_realloc_(L, (b), (on)*(e), (n)*(e))) +/* +** Arrays of chars do not need any test +*/ +#define luaM_reallocvchar(L,b,on,n) \ + cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) + #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) -#define luaM_freearray(L, b, n) luaM_reallocv(L, (b), n, 0, sizeof((b)[0])) +#define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) #define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) #define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) diff --git a/depends/lua/include/lobject.h b/depends/lua/include/lobject.h index 3a630b944..2d52b4159 100644 --- a/depends/lua/include/lobject.h +++ b/depends/lua/include/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.71.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lobject.h,v 2.116 2015/11/03 18:33:10 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -19,14 +19,13 @@ /* ** Extra tags for non-values */ -#define LUA_TPROTO LUA_NUMTAGS -#define LUA_TUPVAL (LUA_NUMTAGS+1) -#define LUA_TDEADKEY (LUA_NUMTAGS+2) +#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */ +#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */ /* ** number of all possible tags (including LUA_TNONE but excluding DEADKEY) */ -#define LUA_TOTALTAGS (LUA_TUPVAL+2) +#define LUA_TOTALTAGS (LUA_TPROTO + 2) /* @@ -36,8 +35,6 @@ ** bit 6: whether value is collectable */ -#define VARBITS (3 << 4) - /* ** LUA_TFUNCTION variants: @@ -57,6 +54,11 @@ #define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ +/* Variant tags for numbers */ +#define LUA_TNUMFLT (LUA_TNUMBER | (0 << 4)) /* float numbers */ +#define LUA_TNUMINT (LUA_TNUMBER | (1 << 4)) /* integer numbers */ + + /* Bit mark for collectable types */ #define BIT_ISCOLLECTABLE (1 << 6) @@ -65,9 +67,9 @@ /* -** Union of all collectable objects +** Common type for all collectable objects */ -typedef union GCObject GCObject; +typedef struct GCObject GCObject; /* @@ -78,21 +80,12 @@ typedef union GCObject GCObject; /* -** Common header in struct form +** Common type has only the common header */ -typedef struct GCheader { +struct GCObject { CommonHeader; -} GCheader; - - - -/* -** Union of all Lua values -*/ -typedef union Value Value; - +}; -#define numfield lua_Number n; /* numbers */ @@ -101,9 +94,26 @@ typedef union Value Value; ** an actual value plus a tag with its type. */ +/* +** Union of all Lua values +*/ +typedef union Value { + GCObject *gc; /* collectable objects */ + void *p; /* light userdata */ + int b; /* booleans */ + lua_CFunction f; /* light C functions */ + lua_Integer i; /* integer numbers */ + lua_Number n; /* float numbers */ +} Value; + + #define TValuefields Value value_; int tt_ -typedef struct lua_TValue TValue; + +typedef struct lua_TValue { + TValuefields; +} TValue; + /* macro defining a nil value */ @@ -111,7 +121,6 @@ typedef struct lua_TValue TValue; #define val_(o) ((o)->value_) -#define num_(o) (val_(o).n) /* raw type tag of a TValue */ @@ -124,13 +133,15 @@ typedef struct lua_TValue TValue; #define ttype(o) (rttype(o) & 0x3F) /* type tag of a TValue with no variants (bits 0-3) */ -#define ttypenv(o) (novariant(rttype(o))) +#define ttnov(o) (novariant(rttype(o))) /* Macros to test type */ #define checktag(o,t) (rttype(o) == (t)) -#define checktype(o,t) (ttypenv(o) == (t)) -#define ttisnumber(o) checktag((o), LUA_TNUMBER) +#define checktype(o,t) (ttnov(o) == (t)) +#define ttisnumber(o) checktype((o), LUA_TNUMBER) +#define ttisfloat(o) checktag((o), LUA_TNUMFLT) +#define ttisinteger(o) checktag((o), LUA_TNUMINT) #define ttisnil(o) checktag((o), LUA_TNIL) #define ttisboolean(o) checktag((o), LUA_TBOOLEAN) #define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA) @@ -143,27 +154,27 @@ typedef struct lua_TValue TValue; #define ttisCclosure(o) checktag((o), ctb(LUA_TCCL)) #define ttisLclosure(o) checktag((o), ctb(LUA_TLCL)) #define ttislcf(o) checktag((o), LUA_TLCF) -#define ttisuserdata(o) checktag((o), ctb(LUA_TUSERDATA)) +#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA)) #define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) #define ttisdeadkey(o) checktag((o), LUA_TDEADKEY) -#define ttisequal(o1,o2) (rttype(o1) == rttype(o2)) /* Macros to access values */ -#define nvalue(o) check_exp(ttisnumber(o), num_(o)) +#define ivalue(o) check_exp(ttisinteger(o), val_(o).i) +#define fltvalue(o) check_exp(ttisfloat(o), val_(o).n) +#define nvalue(o) check_exp(ttisnumber(o), \ + (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o))) #define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) #define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) -#define rawtsvalue(o) check_exp(ttisstring(o), &val_(o).gc->ts) -#define tsvalue(o) (&rawtsvalue(o)->tsv) -#define rawuvalue(o) check_exp(ttisuserdata(o), &val_(o).gc->u) -#define uvalue(o) (&rawuvalue(o)->uv) -#define clvalue(o) check_exp(ttisclosure(o), &val_(o).gc->cl) -#define clLvalue(o) check_exp(ttisLclosure(o), &val_(o).gc->cl.l) -#define clCvalue(o) check_exp(ttisCclosure(o), &val_(o).gc->cl.c) +#define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc)) +#define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc)) +#define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc)) +#define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc)) +#define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc)) #define fvalue(o) check_exp(ttislcf(o), val_(o).f) -#define hvalue(o) check_exp(ttistable(o), &val_(o).gc->h) +#define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) #define bvalue(o) check_exp(ttisboolean(o), val_(o).b) -#define thvalue(o) check_exp(ttisthread(o), &val_(o).gc->th) +#define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) /* a dead value may get the 'gc' field, but cannot access its contents */ #define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc)) @@ -174,18 +185,27 @@ typedef struct lua_TValue TValue; /* Macros for internal tests */ -#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) +#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt) -#define checkliveness(g,obj) \ +#define checkliveness(L,obj) \ lua_longassert(!iscollectable(obj) || \ - (righttt(obj) && !isdead(g,gcvalue(obj)))) + (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))) /* Macros to set values */ #define settt_(o,t) ((o)->tt_=(t)) -#define setnvalue(obj,x) \ - { TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); } +#define setfltvalue(obj,x) \ + { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); } + +#define chgfltvalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); } + +#define setivalue(obj,x) \ + { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); } + +#define chgivalue(obj,x) \ + { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); } #define setnilvalue(obj) settt_(obj, LUA_TNIL) @@ -199,48 +219,46 @@ typedef struct lua_TValue TValue; { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); } #define setgcovalue(L,obj,x) \ - { TValue *io=(obj); GCObject *i_g=(x); \ - val_(io).gc=i_g; settt_(io, ctb(gch(i_g)->tt)); } + { TValue *io = (obj); GCObject *i_g=(x); \ + val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); } #define setsvalue(L,obj,x) \ - { TValue *io=(obj); \ - TString *x_ = (x); \ - val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); TString *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \ + checkliveness(L,io); } #define setuvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TUSERDATA)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); Udata *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \ + checkliveness(L,io); } #define setthvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTHREAD)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); lua_State *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \ + checkliveness(L,io); } #define setclLvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TLCL)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); LClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \ + checkliveness(L,io); } #define setclCvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TCCL)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); CClosure *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \ + checkliveness(L,io); } #define sethvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \ - checkliveness(G(L),io); } + { TValue *io = (obj); Table *x_ = (x); \ + val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \ + checkliveness(L,io); } #define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) #define setobj(L,obj1,obj2) \ - { const TValue *io2=(obj2); TValue *io1=(obj1); \ - io1->value_ = io2->value_; io1->tt_ = io2->tt_; \ - checkliveness(G(L),io1); } + { TValue *io1=(obj1); *io1 = *(obj2); \ + (void)L; checkliveness(L,io1); } /* @@ -256,188 +274,110 @@ typedef struct lua_TValue TValue; #define setptvalue2s setptvalue /* from table to same table */ #define setobjt2t setobj -/* to table */ -#define setobj2t setobj /* to new object */ #define setobj2n setobj #define setsvalue2n setsvalue +/* to table (define it as an expression to be used in macros) */ +#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1))) + -/* check whether a number is valid (useful only for NaN trick) */ -#define luai_checknum(L,o,c) { /* empty */ } /* ** {====================================================== -** NaN Trick +** types and prototypes ** ======================================================= */ -#if defined(LUA_NANTRICK) - -/* -** numbers are represented in the 'd_' field. All other values have the -** value (NNMARK | tag) in 'tt__'. A number with such pattern would be -** a "signaled NaN", which is never generated by regular operations by -** the CPU (nor by 'strtod') -*/ - -/* allows for external implementation for part of the trick */ -#if !defined(NNMARK) /* { */ - - -#if !defined(LUA_IEEEENDIAN) -#error option 'LUA_NANTRICK' needs 'LUA_IEEEENDIAN' -#endif - - -#define NNMARK 0x7FF7A500 -#define NNMASK 0x7FFFFF00 - -#undef TValuefields -#undef NILCONSTANT - -#if (LUA_IEEEENDIAN == 0) /* { */ - -/* little endian */ -#define TValuefields \ - union { struct { Value v__; int tt__; } i; double d__; } u -#define NILCONSTANT {{{NULL}, tag2tt(LUA_TNIL)}} -/* field-access macros */ -#define v_(o) ((o)->u.i.v__) -#define d_(o) ((o)->u.d__) -#define tt_(o) ((o)->u.i.tt__) - -#else /* }{ */ - -/* big endian */ -#define TValuefields \ - union { struct { int tt__; Value v__; } i; double d__; } u -#define NILCONSTANT {{tag2tt(LUA_TNIL), {NULL}}} -/* field-access macros */ -#define v_(o) ((o)->u.i.v__) -#define d_(o) ((o)->u.d__) -#define tt_(o) ((o)->u.i.tt__) - -#endif /* } */ - -#endif /* } */ -/* correspondence with standard representation */ -#undef val_ -#define val_(o) v_(o) -#undef num_ -#define num_(o) d_(o) - - -#undef numfield -#define numfield /* no such field; numbers are the entire struct */ - -/* basic check to distinguish numbers from non-numbers */ -#undef ttisnumber -#define ttisnumber(o) ((tt_(o) & NNMASK) != NNMARK) - -#define tag2tt(t) (NNMARK | (t)) - -#undef rttype -#define rttype(o) (ttisnumber(o) ? LUA_TNUMBER : tt_(o) & 0xff) - -#undef settt_ -#define settt_(o,t) (tt_(o) = tag2tt(t)) +typedef TValue *StkId; /* index to stack elements */ -#undef setnvalue -#define setnvalue(obj,x) \ - { TValue *io_=(obj); num_(io_)=(x); lua_assert(ttisnumber(io_)); } -#undef setobj -#define setobj(L,obj1,obj2) \ - { const TValue *o2_=(obj2); TValue *o1_=(obj1); \ - o1_->u = o2_->u; \ - checkliveness(G(L),o1_); } /* -** these redefinitions are not mandatory, but these forms are more efficient +** Header for string value; string bytes follow the end of this structure +** (aligned according to 'UTString'; see next). */ - -#undef checktag -#undef checktype -#define checktag(o,t) (tt_(o) == tag2tt(t)) -#define checktype(o,t) (ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS)) - -#undef ttisequal -#define ttisequal(o1,o2) \ - (ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2))) - - -#undef luai_checknum -#define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; } - -#endif -/* }====================================================== */ - +typedef struct TString { + CommonHeader; + lu_byte extra; /* reserved words for short strings; "has hash" for longs */ + lu_byte shrlen; /* length for short strings */ + unsigned int hash; + union { + size_t lnglen; /* length for long strings */ + struct TString *hnext; /* linked list for hash table */ + } u; +} TString; /* -** {====================================================== -** types and prototypes -** ======================================================= +** Ensures that address after this type is always fully aligned. */ +typedef union UTString { + L_Umaxalign dummy; /* ensures maximum alignment for strings */ + TString tsv; +} UTString; -union Value { - GCObject *gc; /* collectable objects */ - void *p; /* light userdata */ - int b; /* booleans */ - lua_CFunction f; /* light C functions */ - numfield /* numbers */ -}; - - -struct lua_TValue { - TValuefields; -}; +/* +** Get the actual string (array of bytes) from a 'TString'. +** (Access to 'extra' ensures that value is really a 'TString'.) +*/ +#define getstr(ts) \ + check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString)) -typedef TValue *StkId; /* index to stack elements */ +/* get the actual string (array of bytes) from a Lua value */ +#define svalue(o) getstr(tsvalue(o)) +/* get string length from 'TString *s' */ +#define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen) +/* get string length from 'TValue *o' */ +#define vslen(o) tsslen(tsvalue(o)) /* -** Header for string value; string bytes follow the end of this structure +** Header for userdata; memory area follows the end of this structure +** (aligned according to 'UUdata'; see next). */ -typedef union TString { - L_Umaxalign dummy; /* ensures maximum alignment for strings */ - struct { - CommonHeader; - lu_byte extra; /* reserved words for short strings; "has hash" for longs */ - unsigned int hash; - size_t len; /* number of characters in string */ - } tsv; -} TString; - +typedef struct Udata { + CommonHeader; + lu_byte ttuv_; /* user value's tag */ + struct Table *metatable; + size_t len; /* number of bytes */ + union Value user_; /* user value */ +} Udata; -/* get the actual string (array of bytes) from a TString */ -#define getstr(ts) cast(const char *, (ts) + 1) -/* get the actual string (array of bytes) from a Lua value */ -#define svalue(o) getstr(rawtsvalue(o)) +/* +** Ensures that address after this type is always fully aligned. +*/ +typedef union UUdata { + L_Umaxalign dummy; /* ensures maximum alignment for 'local' udata */ + Udata uv; +} UUdata; /* -** Header for userdata; memory area follows the end of this structure +** Get the address of memory block inside 'Udata'. +** (Access to 'ttuv_' ensures that value is really a 'Udata'.) */ -typedef union Udata { - L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ - struct { - CommonHeader; - struct Table *metatable; - struct Table *env; - size_t len; /* number of bytes */ - } uv; -} Udata; +#define getudatamem(u) \ + check_exp(sizeof((u)->ttuv_), (cast(char*, (u)) + sizeof(UUdata))) + +#define setuservalue(L,u,o) \ + { const TValue *io=(o); Udata *iu = (u); \ + iu->user_ = io->value_; iu->ttuv_ = rttype(io); \ + checkliveness(L,io); } + +#define getuservalue(L,u,o) \ + { TValue *io=(o); const Udata *iu = (u); \ + io->value_ = iu->user_; settt_(io, iu->ttuv_); \ + checkliveness(L,io); } /* @@ -445,7 +385,7 @@ typedef union Udata { */ typedef struct Upvaldesc { TString *name; /* upvalue name (for debug information) */ - lu_byte instack; /* whether it is in stack */ + lu_byte instack; /* whether it is in stack (register) */ lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ } Upvaldesc; @@ -466,26 +406,26 @@ typedef struct LocVar { */ typedef struct Proto { CommonHeader; + lu_byte numparams; /* number of fixed parameters */ + lu_byte is_vararg; /* 2: declared vararg; 1: uses vararg */ + lu_byte maxstacksize; /* number of registers needed by this function */ + int sizeupvalues; /* size of 'upvalues' */ + int sizek; /* size of 'k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of 'p' */ + int sizelocvars; + int linedefined; /* debug information */ + int lastlinedefined; /* debug information */ TValue *k; /* constants used by the function */ - Instruction *code; + Instruction *code; /* opcodes */ struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines (debug information) */ LocVar *locvars; /* information about local variables (debug information) */ Upvaldesc *upvalues; /* upvalue information */ - union Closure *cache; /* last created closure with this prototype */ + struct LClosure *cache; /* last-created closure with this prototype */ TString *source; /* used for debug information */ - int sizeupvalues; /* size of 'upvalues' */ - int sizek; /* size of `k' */ - int sizecode; - int sizelineinfo; - int sizep; /* size of `p' */ - int sizelocvars; - int linedefined; - int lastlinedefined; GCObject *gclist; - lu_byte numparams; /* number of fixed parameters */ - lu_byte is_vararg; - lu_byte maxstacksize; /* maximum stack used by this function */ } Proto; @@ -493,17 +433,7 @@ typedef struct Proto { /* ** Lua Upvalues */ -typedef struct UpVal { - CommonHeader; - TValue *v; /* points to stack or to its own value */ - union { - TValue value; /* the value (when closed) */ - struct { /* double linked list (when open) */ - struct UpVal *prev; - struct UpVal *next; - } l; - } u; -} UpVal; +typedef struct UpVal UpVal; /* @@ -545,12 +475,19 @@ typedef union Closure { typedef union TKey { struct { TValuefields; - struct Node *next; /* for chaining */ + int next; /* for chaining (offset for next node) */ } nk; TValue tvk; } TKey; +/* copy a value into a key without messing up field 'next' */ +#define setnodekey(L,key,obj) \ + { TKey *k_=(key); const TValue *io_=(obj); \ + k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \ + (void)L; checkliveness(L,io_); } + + typedef struct Node { TValue i_val; TKey i_key; @@ -560,19 +497,19 @@ typedef struct Node { typedef struct Table { CommonHeader; lu_byte flags; /* 1<

>1) /* `sBx' is signed */ +#define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */ #else #define MAXARG_Bx MAX_INT #define MAXARG_sBx MAX_INT @@ -76,10 +76,10 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ #define MAXARG_C ((1<> RK(C) */ OP_UNM,/* A B R(A) := -R(B) */ +OP_BNOT,/* A B R(A) := ~R(B) */ OP_NOT,/* A B R(A) := not R(B) */ OP_LEN,/* A B R(A) := length of R(B) */ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ -OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A) + 1 */ +OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ @@ -231,16 +238,16 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ /*=========================================================================== Notes: - (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then `top' is + (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then 'top' is set to last_result+1, so next open instruction (OP_CALL, OP_RETURN, - OP_SETLIST) may use `top'. + OP_SETLIST) may use 'top'. (*) In OP_VARARG, if (B == 0) then use actual number of varargs and set top (like in OP_CALL with C == 0). - (*) In OP_RETURN, if (B == 0) then return up to `top'. + (*) In OP_RETURN, if (B == 0) then return up to 'top'. - (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next + (*) In OP_SETLIST, if (B == 0) then B = 'top'; if (C == 0) then next 'instruction' is EXTRAARG(real C). (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG. @@ -248,7 +255,7 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ (*) For comparisons, A specifies what condition the test should accept (true or false). - (*) All `skips' (pc++) assume that next instruction is a jump. + (*) All 'skips' (pc++) assume that next instruction is a jump. ===========================================================================*/ diff --git a/depends/lua/include/lparser.h b/depends/lua/include/lparser.h index 0346e3c41..02e9b03ae 100644 --- a/depends/lua/include/lparser.h +++ b/depends/lua/include/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.70.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -13,24 +13,38 @@ /* -** Expression descriptor +** Expression and variable descriptor. +** Code generation for variables and expressions can be delayed to allow +** optimizations; An 'expdesc' structure describes a potentially-delayed +** variable/expression. It has a description of its "main" value plus a +** list of conditional jumps that can also produce its value (generated +** by short-circuit operators 'and'/'or'). */ +/* kinds of variables/expressions */ typedef enum { - VVOID, /* no value */ - VNIL, - VTRUE, - VFALSE, - VK, /* info = index of constant in `k' */ - VKNUM, /* nval = numerical value */ - VNONRELOC, /* info = result register */ - VLOCAL, /* info = local register */ - VUPVAL, /* info = index of upvalue in 'upvalues' */ - VINDEXED, /* t = table register/upvalue; idx = index R/K */ - VJMP, /* info = instruction pc */ - VRELOCABLE, /* info = instruction pc */ - VCALL, /* info = instruction pc */ - VVARARG /* info = instruction pc */ + VVOID, /* when 'expdesc' describes the last expression a list, + this kind means an empty list (so, no expression) */ + VNIL, /* constant nil */ + VTRUE, /* constant true */ + VFALSE, /* constant false */ + VK, /* constant in 'k'; info = index of constant in 'k' */ + VKFLT, /* floating constant; nval = numerical float value */ + VKINT, /* integer constant; nval = numerical integer value */ + VNONRELOC, /* expression has its value in a fixed register; + info = result register */ + VLOCAL, /* local variable; info = local register */ + VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ + VINDEXED, /* indexed variable; + ind.vt = whether 't' is register or upvalue; + ind.t = table register or upvalue; + ind.idx = key's R/K index */ + VJMP, /* expression is a test/comparison; + info = pc of corresponding jump instruction */ + VRELOCABLE, /* expression can put result in any register; + info = instruction pc */ + VCALL, /* expression is a function call; info = instruction pc */ + VVARARG /* vararg expression; info = instruction pc */ } expkind; @@ -40,16 +54,17 @@ typedef enum { typedef struct expdesc { expkind k; union { + lua_Integer ival; /* for VKINT */ + lua_Number nval; /* for VKFLT */ + int info; /* for generic use */ struct { /* for indexed variables (VINDEXED) */ short idx; /* index (R/K) */ lu_byte t; /* table (register or upvalue) */ lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ } ind; - int info; /* for generic use */ - lua_Number nval; /* for VKNUM */ } u; - int t; /* patch list of `exit when true' */ - int f; /* patch list of `exit when false' */ + int t; /* patch list of 'exit when true' */ + int f; /* patch list of 'exit when false' */ } expdesc; @@ -95,15 +110,14 @@ struct BlockCnt; /* defined in lparser.c */ /* state needed to generate code for a given function */ typedef struct FuncState { Proto *f; /* current function header */ - Table *h; /* table to find (and reuse) elements in `k' */ struct FuncState *prev; /* enclosing function */ struct LexState *ls; /* lexical state */ struct BlockCnt *bl; /* chain of current blocks */ - int pc; /* next position to code (equivalent to `ncode') */ + int pc; /* next position to code (equivalent to 'ncode') */ int lasttarget; /* 'label' of last 'jump label' */ - int jpc; /* list of pending jumps to `pc' */ - int nk; /* number of elements in `k' */ - int np; /* number of elements in `p' */ + int jpc; /* list of pending jumps to 'pc' */ + int nk; /* number of elements in 'k' */ + int np; /* number of elements in 'p' */ int firstlocal; /* index of first local var (in Dyndata array) */ short nlocvars; /* number of elements in 'f->locvars' */ lu_byte nactvar; /* number of active local variables */ @@ -112,8 +126,8 @@ typedef struct FuncState { } FuncState; -LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar); +LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar); #endif diff --git a/depends/lua/include/lprefix.h b/depends/lua/include/lprefix.h new file mode 100644 index 000000000..02daa837f --- /dev/null +++ b/depends/lua/include/lprefix.h @@ -0,0 +1,45 @@ +/* +** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $ +** Definitions for Lua code that must come before any other header file +** See Copyright Notice in lua.h +*/ + +#ifndef lprefix_h +#define lprefix_h + + +/* +** Allows POSIX/XSI stuff +*/ +#if !defined(LUA_USE_C89) /* { */ + +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE 600 +#elif _XOPEN_SOURCE == 0 +#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ +#endif + +/* +** Allows manipulation of large files in gcc and some other compilers +*/ +#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) +#define _LARGEFILE_SOURCE 1 +#define _FILE_OFFSET_BITS 64 +#endif + +#endif /* } */ + + +/* +** Windows stuff +*/ +#if defined(_WIN32) /* { */ + +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ +#endif + +#endif /* } */ + +#endif + diff --git a/depends/lua/include/lstate.h b/depends/lua/include/lstate.h index daffd9aac..b3033bee5 100644 --- a/depends/lua/include/lstate.h +++ b/depends/lua/include/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.82.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lstate.h,v 2.130 2015/12/16 16:39:38 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -16,25 +16,16 @@ /* -** Some notes about garbage-collected objects: All objects in Lua must -** be kept somehow accessible until being freed. +** Some notes about garbage-collected objects: All objects in Lua must +** be kept somehow accessible until being freed, so all objects always +** belong to one (and only one) of these lists, using field 'next' of +** the 'CommonHeader' for the link: ** -** Lua keeps most objects linked in list g->allgc. The link uses field -** 'next' of the CommonHeader. -** -** Strings are kept in several lists headed by the array g->strt.hash. -** -** Open upvalues are not subject to independent garbage collection. They -** are collected together with their respective threads. Lua keeps a -** double-linked list with all open upvalues (g->uvhead) so that it can -** mark objects referred by them. (They are always gray, so they must -** be remarked in the atomic step. Usually their contents would be marked -** when traversing the respective threads, but the thread may already be -** dead, while the upvalue is still accessible through closures.) -** -** Objects with finalizers are kept in the list g->finobj. -** -** The list g->tobefnz links all objects being finalized. +** 'allgc': all objects not marked for finalization; +** 'finobj': all objects marked for finalization; +** 'tobefnz': all objects ready to be finalized; +** 'fixedgc': all objects that are not to be collected (currently +** only small strings, such as reserved words). */ @@ -42,6 +33,15 @@ struct lua_longjmp; /* defined in ldo.c */ +/* +** Atomic type (relative to signals) to better ensure that 'lua_sethook' +** is thread safe +*/ +#if !defined(l_signalT) +#include +#define l_signalT sig_atomic_t +#endif + /* extra stack space to handle TM calls and some other extras */ #define EXTRA_STACK 5 @@ -53,66 +53,72 @@ struct lua_longjmp; /* defined in ldo.c */ /* kinds of Garbage Collection */ #define KGC_NORMAL 0 #define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ -#define KGC_GEN 2 /* generational collection */ typedef struct stringtable { - GCObject **hash; - lu_int32 nuse; /* number of elements */ + TString **hash; + int nuse; /* number of elements */ int size; } stringtable; /* -** information about a call +** Information about a call. +** When a thread yields, 'func' is adjusted to pretend that the +** top function has only the yielded values in its stack; in that +** case, the actual 'func' value is saved in field 'extra'. +** When a function calls another with a continuation, 'extra' keeps +** the function index so that, in case of errors, the continuation +** function can be called with the correct top. */ typedef struct CallInfo { StkId func; /* function index in the stack */ StkId top; /* top for this function */ struct CallInfo *previous, *next; /* dynamic call link */ - short nresults; /* expected number of results from this function */ - lu_byte callstatus; - ptrdiff_t extra; union { struct { /* only for Lua functions */ StkId base; /* base for this function */ const Instruction *savedpc; } l; struct { /* only for C functions */ - int ctx; /* context info. in case of yields */ - lua_CFunction k; /* continuation in case of yields */ + lua_KFunction k; /* continuation in case of yields */ ptrdiff_t old_errfunc; - lu_byte old_allowhook; - lu_byte status; + lua_KContext ctx; /* context info. in case of yields */ } c; } u; + ptrdiff_t extra; + short nresults; /* expected number of results from this function */ + lu_byte callstatus; } CallInfo; /* ** Bits in CallInfo status */ -#define CIST_LUA (1<<0) /* call is running a Lua function */ -#define CIST_HOOKED (1<<1) /* call is running a debug hook */ -#define CIST_REENTRY (1<<2) /* call is running on same invocation of - luaV_execute of previous call */ -#define CIST_YIELDED (1<<3) /* call reentered after suspension */ +#define CIST_OAH (1<<0) /* original value of 'allowhook' */ +#define CIST_LUA (1<<1) /* call is running a Lua function */ +#define CIST_HOOKED (1<<2) /* call is running a debug hook */ +#define CIST_FRESH (1<<3) /* call is running on a fresh invocation + of luaV_execute */ #define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ -#define CIST_STAT (1<<5) /* call has an error status (pcall) */ -#define CIST_TAIL (1<<6) /* call was tail called */ -#define CIST_HOOKYIELD (1<<7) /* last hook called yielded */ - +#define CIST_TAIL (1<<5) /* call was tail called */ +#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ +#define CIST_LEQ (1<<7) /* using __lt for __le */ #define isLua(ci) ((ci)->callstatus & CIST_LUA) +/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ +#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) +#define getoah(st) ((st) & CIST_OAH) + /* -** `global state', shared by all threads of this state +** 'global state', shared by all threads of this state */ typedef struct global_State { lua_Alloc frealloc; /* function to reallocate memory */ - void *ud; /* auxiliary data to `frealloc' */ - lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */ + void *ud; /* auxiliary data to 'frealloc' */ + l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ lu_mem GCmemtrav; /* memory traversed by the GC */ lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ @@ -123,36 +129,36 @@ typedef struct global_State { lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ lu_byte gcrunning; /* true if GC is running */ - int sweepstrgc; /* position of sweep in `strt' */ GCObject *allgc; /* list of all collectable objects */ + GCObject **sweepgc; /* current position of sweep in list */ GCObject *finobj; /* list of collectable objects with finalizers */ - GCObject **sweepgc; /* current position of sweep in list 'allgc' */ - GCObject **sweepfin; /* current position of sweep in list 'finobj' */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of tables with weak values */ GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ GCObject *allweak; /* list of all-weak tables */ GCObject *tobefnz; /* list of userdata to be GC */ - UpVal uvhead; /* head of double-linked list of all open upvalues */ - Mbuffer buff; /* temporary buffer for string concatenation */ + GCObject *fixedgc; /* list of objects not to be collected */ + struct lua_State *twups; /* list of threads with open upvalues */ + unsigned int gcfinnum; /* number of finalizers to call in each GC step */ int gcpause; /* size of pause between successive GCs */ - 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 */ struct lua_State *mainthread; const lua_Number *version; /* pointer to version number */ TString *memerrmsg; /* memory-error message */ TString *tmname[TM_N]; /* array with tag-method names */ struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ + TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ } global_State; /* -** `per thread' state +** 'per thread' state */ struct lua_State { CommonHeader; + unsigned short nci; /* number of items in 'ci' list */ lu_byte status; StkId top; /* first free slot in the stack */ global_State *l_G; @@ -160,19 +166,20 @@ struct lua_State { const Instruction *oldpc; /* last pc traced */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ + UpVal *openupval; /* list of open upvalues in this stack */ + GCObject *gclist; + struct lua_State *twups; /* list of threads with open upvalues */ + struct lua_longjmp *errorJmp; /* current error recover point */ + CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ + volatile lua_Hook hook; + ptrdiff_t errfunc; /* current error handling function (stack index) */ int stacksize; + int basehookcount; + int hookcount; unsigned short nny; /* number of non-yieldable calls in stack */ unsigned short nCcalls; /* number of nested C calls */ - lu_byte hookmask; + l_signalT hookmask; lu_byte allowhook; - int basehookcount; - int hookcount; - lua_Hook hook; - GCObject *openupval; /* list of open upvalues in this stack */ - GCObject *gclist; - struct lua_longjmp *errorJmp; /* current error recover point */ - ptrdiff_t errfunc; /* current error handling function (stack index) */ - CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ }; @@ -180,48 +187,47 @@ struct lua_State { /* -** Union of all collectable objects +** Union of all collectable objects (only for conversions) */ -union GCObject { - GCheader gch; /* common header */ - union TString ts; - union Udata u; +union GCUnion { + GCObject gc; /* common header */ + struct TString ts; + struct Udata u; union Closure cl; struct Table h; struct Proto p; - struct UpVal uv; struct lua_State th; /* thread */ }; -#define gch(o) (&(o)->gch) +#define cast_u(o) cast(union GCUnion *, (o)) /* macros to convert a GCObject into a specific value */ -#define rawgco2ts(o) \ - check_exp(novariant((o)->gch.tt) == LUA_TSTRING, &((o)->ts)) -#define gco2ts(o) (&rawgco2ts(o)->tsv) -#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) -#define gco2u(o) (&rawgco2u(o)->uv) -#define gco2lcl(o) check_exp((o)->gch.tt == LUA_TLCL, &((o)->cl.l)) -#define gco2ccl(o) check_exp((o)->gch.tt == LUA_TCCL, &((o)->cl.c)) +#define gco2ts(o) \ + check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) +#define gco2u(o) check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u)) +#define gco2lcl(o) check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l)) +#define gco2ccl(o) check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c)) #define gco2cl(o) \ - check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl)) -#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) -#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) -#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) -#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) + check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) +#define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) +#define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) +#define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) + -/* macro to convert any Lua object into a GCObject */ -#define obj2gco(v) (cast(GCObject *, (v))) +/* macro to convert a Lua object into a GCObject */ +#define obj2gco(v) \ + check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc))) /* actual number of total bytes allocated */ -#define gettotalbytes(g) ((g)->totalbytes + (g)->GCdebt) +#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); LUAI_FUNC void luaE_freeCI (lua_State *L); +LUAI_FUNC void luaE_shrinkCI (lua_State *L); #endif diff --git a/depends/lua/include/lstring.h b/depends/lua/include/lstring.h index 260e7f169..27efd2077 100644 --- a/depends/lua/include/lstring.h +++ b/depends/lua/include/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -12,35 +12,38 @@ #include "lstate.h" -#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) +#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) -#define sizeudata(u) (sizeof(union Udata)+(u)->len) +#define sizeludata(l) (sizeof(union UUdata) + (l)) +#define sizeudata(u) sizeludata((u)->len) #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) -#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) - /* ** test whether a string is a reserved word */ -#define isreserved(s) ((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0) +#define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0) /* ** equality for short strings, which are always internalized */ -#define eqshrstr(a,b) check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b)) +#define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); +LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); -LUAI_FUNC int luaS_eqstr (TString *a, TString *b); LUAI_FUNC void luaS_resize (lua_State *L, int newsize); -LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); +LUAI_FUNC void luaS_clearcache (global_State *g); +LUAI_FUNC void luaS_init (lua_State *L); +LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); +LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); +LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); #endif diff --git a/depends/lua/include/ltable.h b/depends/lua/include/ltable.h index d69449b2b..213cc1398 100644 --- a/depends/lua/include/ltable.h +++ b/depends/lua/include/ltable.h @@ -1,5 +1,5 @@ /* -** $Id: ltable.h,v 2.16.1.2 2013/08/30 15:49:41 roberto Exp $ +** $Id: ltable.h,v 2.21 2015/11/03 15:47:30 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -11,26 +11,39 @@ #define gnode(t,i) (&(t)->node[i]) -#define gkey(n) (&(n)->i_key.tvk) #define gval(n) (&(n)->i_val) #define gnext(n) ((n)->i_key.nk.next) + +/* 'const' to avoid wrong writings that can mess up field 'next' */ +#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) + +/* +** writable version of 'gkey'; allows updates to individual fields, +** but not to the whole (which has incompatible type) +*/ +#define wgkey(n) (&(n)->i_key.nk) + #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 void luaH_setint (lua_State *L, Table *t, int key, TValue *value); +LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); +LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, + TValue *value); +LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); LUAI_FUNC Table *luaH_new (lua_State *L); -LUAI_FUNC void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize); -LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize); +LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, + unsigned int nhsize); +LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); LUAI_FUNC int luaH_getn (Table *t); diff --git a/depends/lua/include/ltm.h b/depends/lua/include/ltm.h index 7f89c841f..63db7269b 100644 --- a/depends/lua/include/ltm.h +++ b/depends/lua/include/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.11.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -13,7 +13,7 @@ /* * WARNING: if you change the order of this enumeration, -* grep "ORDER TM" +* grep "ORDER TM" and "ORDER OP" */ typedef enum { TM_INDEX, @@ -21,14 +21,21 @@ typedef enum { TM_GC, TM_MODE, TM_LEN, - TM_EQ, /* last tag method with `fast' access */ + TM_EQ, /* last tag method with fast access */ TM_ADD, TM_SUB, TM_MUL, - TM_DIV, TM_MOD, TM_POW, + TM_DIV, + TM_IDIV, + TM_BAND, + TM_BOR, + TM_BXOR, + TM_SHL, + TM_SHR, TM_UNM, + TM_BNOT, TM_LT, TM_LE, TM_CONCAT, @@ -44,14 +51,26 @@ typedef enum { #define fasttm(l,et,e) gfasttm(G(l), et, e) #define ttypename(x) luaT_typenames_[(x) + 1] -#define objtypename(x) ttypename(ttypenv(x)) LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; +LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o); + LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event); LUAI_FUNC void luaT_init (lua_State *L); +LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, TValue *p3, int hasres); +LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event); +LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event); +LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, + const TValue *p2, TMS event); + + + #endif diff --git a/depends/lua/include/lua.h b/depends/lua/include/lua.h index 149a2c37b..f78899fc5 100644 --- a/depends/lua/include/lua.h +++ b/depends/lua/include/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.285.1.2 2013/11/11 12:09:16 roberto Exp $ +** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -17,27 +17,29 @@ #define LUA_VERSION_MAJOR "5" -#define LUA_VERSION_MINOR "2" -#define LUA_VERSION_NUM 502 +#define LUA_VERSION_MINOR "3" +#define LUA_VERSION_NUM 503 #define LUA_VERSION_RELEASE "3" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2013 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" /* mark for precompiled code ('Lua') */ -#define LUA_SIGNATURE "\033Lua" +#define LUA_SIGNATURE "\x1bLua" /* option for multiple returns in 'lua_pcall' and 'lua_call' */ #define LUA_MULTRET (-1) /* -** pseudo-indices +** Pseudo-indices +** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty +** space after that to help overflow detection) */ -#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX +#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) #define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) @@ -53,22 +55,6 @@ typedef struct lua_State lua_State; -typedef int (*lua_CFunction) (lua_State *L); - - -/* -** functions that read/write blocks when loading/dumping Lua chunks -*/ -typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); - -typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); - - -/* -** prototype for memory-allocation functions -*/ -typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); - /* ** basic types @@ -109,6 +95,34 @@ typedef LUA_INTEGER lua_Integer; /* unsigned integer type */ typedef LUA_UNSIGNED lua_Unsigned; +/* type for continuation-function contexts */ +typedef LUA_KCONTEXT lua_KContext; + + +/* +** Type for C functions registered with Lua +*/ +typedef int (*lua_CFunction) (lua_State *L); + +/* +** Type for continuation functions +*/ +typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); + + +/* +** Type for functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); + + +/* +** Type for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + /* @@ -145,11 +159,9 @@ LUA_API int (lua_absindex) (lua_State *L, int idx); LUA_API int (lua_gettop) (lua_State *L); LUA_API void (lua_settop) (lua_State *L, int idx); LUA_API void (lua_pushvalue) (lua_State *L, int idx); -LUA_API void (lua_remove) (lua_State *L, int idx); -LUA_API void (lua_insert) (lua_State *L, int idx); -LUA_API void (lua_replace) (lua_State *L, int idx); +LUA_API void (lua_rotate) (lua_State *L, int idx, int n); LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); -LUA_API int (lua_checkstack) (lua_State *L, int sz); +LUA_API int (lua_checkstack) (lua_State *L, int n); LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); @@ -161,13 +173,13 @@ LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); LUA_API int (lua_isnumber) (lua_State *L, int idx); LUA_API int (lua_isstring) (lua_State *L, int idx); LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isinteger) (lua_State *L, int idx); LUA_API int (lua_isuserdata) (lua_State *L, int idx); LUA_API int (lua_type) (lua_State *L, int idx); LUA_API const char *(lua_typename) (lua_State *L, int tp); LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); -LUA_API lua_Unsigned (lua_tounsignedx) (lua_State *L, int idx, int *isnum); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); LUA_API size_t (lua_rawlen) (lua_State *L, int idx); @@ -181,13 +193,20 @@ LUA_API const void *(lua_topointer) (lua_State *L, int idx); ** Comparison and arithmetic functions */ -#define LUA_OPADD 0 /* ORDER TM */ +#define LUA_OPADD 0 /* ORDER TM, ORDER OP */ #define LUA_OPSUB 1 #define LUA_OPMUL 2 -#define LUA_OPDIV 3 -#define LUA_OPMOD 4 -#define LUA_OPPOW 5 -#define LUA_OPUNM 6 +#define LUA_OPMOD 3 +#define LUA_OPPOW 4 +#define LUA_OPDIV 5 +#define LUA_OPIDIV 6 +#define LUA_OPBAND 7 +#define LUA_OPBOR 8 +#define LUA_OPBXOR 9 +#define LUA_OPSHL 10 +#define LUA_OPSHR 11 +#define LUA_OPUNM 12 +#define LUA_OPBNOT 13 LUA_API void (lua_arith) (lua_State *L, int op); @@ -205,8 +224,7 @@ LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); LUA_API void (lua_pushnil) (lua_State *L); LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); -LUA_API void (lua_pushunsigned) (lua_State *L, lua_Unsigned n); -LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t l); +LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp); @@ -220,26 +238,29 @@ LUA_API int (lua_pushthread) (lua_State *L); /* ** get functions (Lua -> stack) */ -LUA_API void (lua_getglobal) (lua_State *L, const char *var); -LUA_API void (lua_gettable) (lua_State *L, int idx); -LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); -LUA_API void (lua_rawget) (lua_State *L, int idx); -LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); -LUA_API void (lua_rawgetp) (lua_State *L, int idx, const void *p); +LUA_API int (lua_getglobal) (lua_State *L, const char *name); +LUA_API int (lua_gettable) (lua_State *L, int idx); +LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawget) (lua_State *L, int idx); +LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); +LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); + LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); -LUA_API void (lua_getuservalue) (lua_State *L, int idx); +LUA_API int (lua_getuservalue) (lua_State *L, int idx); /* ** set functions (stack -> Lua) */ -LUA_API void (lua_setglobal) (lua_State *L, const char *var); +LUA_API void (lua_setglobal) (lua_State *L, const char *name); LUA_API void (lua_settable) (lua_State *L, int idx); LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); LUA_API void (lua_rawset) (lua_State *L, int idx); -LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); +LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); LUA_API void (lua_setuservalue) (lua_State *L, int idx); @@ -248,31 +269,31 @@ LUA_API void (lua_setuservalue) (lua_State *L, int idx); /* ** 'load' and 'call' functions (load and run Lua code) */ -LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, int ctx, - lua_CFunction k); +LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k); #define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) -LUA_API int (lua_getctx) (lua_State *L, int *ctx); - LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, - int ctx, lua_CFunction k); + lua_KContext ctx, lua_KFunction k); #define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, - const char *chunkname, - const char *mode); + const char *chunkname, const char *mode); -LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); /* ** coroutine functions */ -LUA_API int (lua_yieldk) (lua_State *L, int nresults, int ctx, - lua_CFunction k); +LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k); +LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); +LUA_API int (lua_status) (lua_State *L); +LUA_API int (lua_isyieldable) (lua_State *L); + #define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) -LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); -LUA_API int (lua_status) (lua_State *L); + /* ** garbage-collection function and options @@ -286,10 +307,7 @@ LUA_API int (lua_status) (lua_State *L); #define LUA_GCSTEP 5 #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 -#define LUA_GCSETMAJORINC 8 #define LUA_GCISRUNNING 9 -#define LUA_GCGEN 10 -#define LUA_GCINC 11 LUA_API int (lua_gc) (lua_State *L, int what, int data); @@ -305,20 +323,23 @@ LUA_API int (lua_next) (lua_State *L, int idx); LUA_API void (lua_concat) (lua_State *L, int n); LUA_API void (lua_len) (lua_State *L, int idx); +LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); + LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); /* -** =============================================================== +** {============================================================== ** some useful macros ** =============================================================== */ -#define lua_tonumber(L,i) lua_tonumberx(L,i,NULL) -#define lua_tointeger(L,i) lua_tointegerx(L,i,NULL) -#define lua_tounsigned(L,i) lua_tounsignedx(L,i,NULL) +#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) + +#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL) +#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL) #define lua_pop(L,n) lua_settop(L, -(n)-1) @@ -337,15 +358,36 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); #define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) #define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) -#define lua_pushliteral(L, s) \ - lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) +#define lua_pushliteral(L, s) lua_pushstring(L, "" s) #define lua_pushglobaltable(L) \ - lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) + ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)) #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) +#define lua_insert(L,idx) lua_rotate(L, (idx), 1) + +#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) + +#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) + +/* }============================================================== */ + + +/* +** {============================================================== +** compatibility macros for unsigned conversions +** =============================================================== +*/ +#if defined(LUA_COMPAT_APIINTCASTS) + +#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) +#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) + +#endif +/* }============================================================== */ /* ** {====================================================================== @@ -390,7 +432,7 @@ LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, int fidx2, int n2); -LUA_API int (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); +LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); LUA_API lua_Hook (lua_gethook) (lua_State *L); LUA_API int (lua_gethookmask) (lua_State *L); LUA_API int (lua_gethookcount) (lua_State *L); @@ -418,7 +460,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2013 Lua.org, PUC-Rio. +* Copyright (C) 1994-2016 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/depends/lua/include/luaconf.h b/depends/lua/include/luaconf.h index af09ffb94..fd447ccb9 100644 --- a/depends/lua/include/luaconf.h +++ b/depends/lua/include/luaconf.h @@ -1,113 +1,204 @@ /* -** $Id: luaconf.h,v 1.176.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ -#ifndef lconfig_h -#define lconfig_h +#ifndef luaconf_h +#define luaconf_h #include #include /* -** ================================================================== +** =================================================================== ** Search for "@@" to find all configurable definitions. ** =================================================================== */ /* -@@ LUA_ANSI controls the use of non-ansi features. -** CHANGE it (define it) if you want Lua to avoid the use of any -** non-ansi feature or library. +** {==================================================================== +** System Configuration: macros to adapt (if needed) Lua to some +** particular platform, for instance compiling it with 32-bit numbers or +** restricting it to C89. +** ===================================================================== */ -#if !defined(LUA_ANSI) && defined(__STRICT_ANSI__) -#define LUA_ANSI -#endif + +/* +@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You +** can also define LUA_32BITS in the make file, but changing here you +** ensure that all software connected to Lua will be compiled with the +** same configuration. +*/ +/* #define LUA_32BITS */ -#if !defined(LUA_ANSI) && defined(_WIN32) && !defined(_WIN32_WCE) -#define LUA_WIN /* enable goodies for regular Windows platforms */ -#endif +/* +@@ LUA_USE_C89 controls the use of non-ISO-C89 features. +** Define it if you want Lua to avoid the use of a few C99 features +** or Windows-specific features on Windows. +*/ +/* #define LUA_USE_C89 */ -#if defined(LUA_WIN) -#define LUA_DL_DLL -#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ + +/* +** By default, Lua on Windows use (some) specific Windows features +*/ +#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) +#define LUA_USE_WINDOWS /* enable goodies for regular Windows */ #endif +#if defined(LUA_USE_WINDOWS) +#define LUA_DL_DLL /* enable support for DLL */ +#define LUA_USE_C89 /* broadly, Windows is C89 */ +#endif + #if defined(LUA_USE_LINUX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ #define LUA_USE_READLINE /* needs some extra libraries */ -#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */ -#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ -#define LUA_USE_LONGLONG /* assume support for long long */ #endif + #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX -#define LUA_USE_DLOPEN /* does not need -ldl */ +#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ #define LUA_USE_READLINE /* needs an extra library: -lreadline */ -#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */ -#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ -#define LUA_USE_LONGLONG /* assume support for long long */ +#endif + + +/* +@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for +** C89 ('long' and 'double'); Windows always has '__int64', so it does +** not need to use this case. +*/ +#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) +#define LUA_C89_NUMBERS #endif /* -@@ LUA_USE_POSIX includes all functionality listed as X/Open System -@* Interfaces Extension (XSI). -** CHANGE it (define it) if your system is XSI compatible. +@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'. */ -#if defined(LUA_USE_POSIX) -#define LUA_USE_MKSTEMP -#define LUA_USE_ISATTY -#define LUA_USE_POPEN -#define LUA_USE_ULONGJMP -#define LUA_USE_GMTIME_R +/* avoid undefined shifts */ +#if ((INT_MAX >> 15) >> 15) >= 1 +#define LUAI_BITSINT 32 +#else +/* 'int' always must have at least 16 bits */ +#define LUAI_BITSINT 16 #endif +/* +@@ LUA_INT_TYPE defines the type for Lua integers. +@@ LUA_FLOAT_TYPE defines the type for Lua floats. +** Lua should work fine with any mix of these options (if supported +** by your C compiler). The usual configurations are 64-bit integers +** and 'double' (the default), 32-bit integers and 'float' (for +** restricted platforms), and 'long'/'double' (for C compilers not +** compliant with C99, which may not have support for 'long long'). +*/ + +/* predefined options for LUA_INT_TYPE */ +#define LUA_INT_INT 1 +#define LUA_INT_LONG 2 +#define LUA_INT_LONGLONG 3 + +/* predefined options for LUA_FLOAT_TYPE */ +#define LUA_FLOAT_FLOAT 1 +#define LUA_FLOAT_DOUBLE 2 +#define LUA_FLOAT_LONGDOUBLE 3 + +#if defined(LUA_32BITS) /* { */ +/* +** 32-bit integers and 'float' +*/ +#if LUAI_BITSINT >= 32 /* use 'int' if big enough */ +#define LUA_INT_TYPE LUA_INT_INT +#else /* otherwise use 'long' */ +#define LUA_INT_TYPE LUA_INT_LONG +#endif +#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT + +#elif defined(LUA_C89_NUMBERS) /* }{ */ +/* +** largest types available for C89 ('long' and 'double') +*/ +#define LUA_INT_TYPE LUA_INT_LONG +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE + +#endif /* } */ + + +/* +** default configuration for 64-bit Lua ('long long' and 'double') +*/ +#if !defined(LUA_INT_TYPE) +#define LUA_INT_TYPE LUA_INT_LONGLONG +#endif + +#if !defined(LUA_FLOAT_TYPE) +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE +#endif + +/* }================================================================== */ + + + + +/* +** {================================================================== +** Configuration for Paths. +** =================================================================== +*/ /* @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for -@* Lua libraries. +** Lua libraries. @@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for -@* C libraries. +** C libraries. ** CHANGE them if your machine has a non-conventional directory ** hierarchy or if you want to install your libraries in ** non-conventional directories. */ +#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #if defined(_WIN32) /* { */ /* ** In Windows, any exclamation mark ('!') in the path is replaced by the ** path of the directory of the executable file of the current process. */ -#define LUA_LDIR "!\\hack\\lua\\" +#define LUA_LDIR "!\\lua\\" #define LUA_CDIR "!\\" +#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" #define LUA_PATH_DEFAULT \ - LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" ".\\?.lua" + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ + LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ + ".\\?.lua;" ".\\?\\init.lua" #define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.dll;" ".\\?.dll" + LUA_CDIR"?.dll;" \ + LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ + LUA_CDIR"loadall.dll;" ".\\?.dll" #else /* }{ */ -#define LUA_LDIR "./hack/lua/" -#define LUA_CDIR "./hack/" +#define LUA_ROOT "/usr/local/" +#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" +#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" #define LUA_PATH_DEFAULT \ - LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" "./?.lua" + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ + "./?.lua;" "./?/init.lua" #define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.so;" "./?.so" + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" #endif /* } */ -#define LUA_PATH "DFHACK_LUA_PATH" -#define LUA_CPATH "DFHACK_LUA_CPATH" /* @@ LUA_DIRSEP is the directory separator (for submodules). @@ -120,14 +211,14 @@ #define LUA_DIRSEP "/" #endif +/* }================================================================== */ + /* -@@ LUA_ENV is the name of the variable that holds the current -@@ environment, used to access global names. -** CHANGE it if you do not like this name. +** {================================================================== +** Marks for exported symbols in the C code +** =================================================================== */ -#define LUA_ENV "_ENV" - /* @@ LUA_API is a mark for all core API functions. @@ -140,15 +231,11 @@ */ #if defined(LUA_BUILD_AS_DLL) /* { */ -#if defined(_MSC_VER) #if defined(LUA_CORE) || defined(LUA_LIB) /* { */ #define LUA_API __declspec(dllexport) #else /* }{ */ #define LUA_API __declspec(dllimport) #endif /* } */ -#else -#define LUA_API __attribute__ ((visibility("default"))) -#endif #else /* }{ */ @@ -164,10 +251,10 @@ /* @@ LUAI_FUNC is a mark for all extern functions that are not to be -@* exported to outside modules. +** exported to outside modules. @@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables -@* that are not to be exported to outside modules (LUAI_DDEF for -@* definitions and LUAI_DDEC for declarations). +** that are not to be exported to outside modules (LUAI_DDEF for +** definitions and LUAI_DDEC for declarations). ** CHANGE them if you need to mark them in some special way. Elf/gcc ** (versions 3.2 and later) mark them as "hidden" to optimize access ** when Lua is compiled as a shared library. Not all elf targets support @@ -179,74 +266,61 @@ #if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ defined(__ELF__) /* { */ #define LUAI_FUNC __attribute__((visibility("hidden"))) extern -#define LUAI_DDEC LUAI_FUNC -#define LUAI_DDEF /* empty */ - #else /* }{ */ #define LUAI_FUNC extern -#define LUAI_DDEC extern -#define LUAI_DDEF /* empty */ #endif /* } */ +#define LUAI_DDEC LUAI_FUNC +#define LUAI_DDEF /* empty */ + +/* }================================================================== */ /* -@@ LUA_QL describes how error messages quote program elements. -** CHANGE it if you want a different appearance. +** {================================================================== +** Compatibility with previous versions +** =================================================================== */ -#define LUA_QL(x) "'" x "'" -#define LUA_QS LUA_QL("%s") - /* -@@ LUA_IDSIZE gives the maximum size for the description of the source -@* of a function in debug information. -** CHANGE it if you want a different size. +@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2. +@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1. +** You can define it to get all options, or change specific options +** to fit your specific needs. */ -#define LUA_IDSIZE 60 - +#if defined(LUA_COMPAT_5_2) /* { */ /* -@@ luai_writestring/luai_writeline define how 'print' prints its results. -** They are only used in libraries and the stand-alone program. (The #if -** avoids including 'stdio.h' everywhere.) +@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated +** functions in the mathematical library. */ -#if defined(LUA_LIB) || defined(lua_c) -#include -#define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) -#define luai_writeline() (luai_writestring("\n", 1), fflush(stdout)) -#endif +#define LUA_COMPAT_MATHLIB /* -@@ luai_writestringerror defines how to print error messages. -** (A format string with one argument is enough for Lua...) +@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'. */ -#define luai_writestringerror(s,p) \ - (fprintf(stderr, (s), (p)), fflush(stderr)) +#define LUA_COMPAT_BITLIB +/* +@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod. +*/ +#define LUA_COMPAT_IPAIRS /* -@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is, -** strings that are internalized. (Cannot be smaller than reserved words -** or tags for metamethods, as these strings must be internalized; -** #("function") = 8, #("__newindex") = 10.) +@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for +** manipulating other integer types (lua_pushunsigned, lua_tounsigned, +** luaL_checkint, luaL_checklong, etc.) */ -#define LUAI_MAXSHORTLEN 40 +#define LUA_COMPAT_APIINTCASTS +#endif /* } */ -/* -** {================================================================== -** Compatibility with previous versions -** =================================================================== -*/ +#if defined(LUA_COMPAT_5_1) /* { */ -/* -@@ LUA_COMPAT_ALL controls all compatibility options. -** You can define it to get all options, or change specific options -** to fit your specific needs. -*/ -#if defined(LUA_COMPAT_ALL) /* { */ +/* Incompatibilities from 5.2 -> 5.3 */ +#define LUA_COMPAT_MATHLIB +#define LUA_COMPAT_APIINTCASTS /* @@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. @@ -307,237 +381,375 @@ #endif /* } */ + +/* +@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a +@@ a float mark ('.0'). +** This macro is not on by default even in compatibility mode, +** because this is not really an incompatibility. +*/ +/* #define LUA_COMPAT_FLOATSTRING */ + /* }================================================================== */ /* -@@ LUAI_BITSINT defines the number of bits in an int. -** CHANGE here if Lua cannot automatically detect the number of bits of -** your machine. Probably you do not need to change this. +** {================================================================== +** Configuration for Numbers. +** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* +** satisfy your needs. +** =================================================================== */ -/* avoid overflows in comparison */ -#if INT_MAX-20 < 32760 /* { */ -#define LUAI_BITSINT 16 -#elif INT_MAX > 2147483640L /* }{ */ -/* int has at least 32 bits */ -#define LUAI_BITSINT 32 -#else /* }{ */ -#error "you must define LUA_BITSINT with number of bits in an integer" -#endif /* } */ +/* +@@ LUA_NUMBER is the floating-point type used by Lua. +@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' +@@ over a floating number. +@@ l_mathlim(x) corrects limit name 'x' to the proper float type +** by prefixing it with one of FLT/DBL/LDBL. +@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. +@@ LUA_NUMBER_FMT is the format for writing floats. +@@ lua_number2str converts a float to a string. +@@ l_mathop allows the addition of an 'l' or 'f' to all math operations. +@@ l_floor takes the floor of a float. +@@ lua_str2number converts a decimal numeric string to a number. +*/ + + +/* The following definitions are good for most cases here */ + +#define l_floor(x) (l_mathop(floor)(x)) + +#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n)) /* -@@ LUA_INT32 is an signed integer with exactly 32 bits. -@@ LUAI_UMEM is an unsigned integer big enough to count the total -@* memory used by Lua. -@@ LUAI_MEM is a signed integer big enough to count the total memory -@* used by Lua. -** CHANGE here if for some weird reason the default definitions are not -** good enough for your machine. Probably you do not need to change -** this. +@@ lua_numbertointeger converts a float number to an integer, or +** returns 0 if float is not within the range of a lua_Integer. +** (The range comparisons are tricky because of rounding. The tests +** here assume a two-complement representation, where MININTEGER always +** has an exact representation as a float; MAXINTEGER may not have one, +** and therefore its conversion to float may have an ill-defined value.) */ -#if LUAI_BITSINT >= 32 /* { */ -#define LUA_INT32 int -#define LUAI_UMEM size_t -#define LUAI_MEM ptrdiff_t -#else /* }{ */ -/* 16-bit ints */ -#define LUA_INT32 long -#define LUAI_UMEM unsigned long -#define LUAI_MEM long -#endif /* } */ +#define lua_numbertointeger(n,p) \ + ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ + (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ + (*(p) = (LUA_INTEGER)(n), 1)) + + +/* now the variable definitions */ + +#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ + +#define LUA_NUMBER float + +#define l_mathlim(n) (FLT_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.7g" + +#define l_mathop(op) op##f + +#define lua_str2number(s,p) strtof((s), (p)) + + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ + +#define LUA_NUMBER long double + +#define l_mathlim(n) (LDBL_##n) + +#define LUAI_UACNUMBER long double + +#define LUA_NUMBER_FRMLEN "L" +#define LUA_NUMBER_FMT "%.19Lg" + +#define l_mathop(op) op##l + +#define lua_str2number(s,p) strtold((s), (p)) + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */ + +#define LUA_NUMBER double + +#define l_mathlim(n) (DBL_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.14g" + +#define l_mathop(op) op + +#define lua_str2number(s,p) strtod((s), (p)) + +#else /* }{ */ + +#error "numeric float type not defined" + +#endif /* } */ + /* -@@ LUAI_MAXSTACK limits the size of the Lua stack. -** CHANGE it if you need a different limit. This limit is arbitrary; -** its only purpose is to stop Lua to consume unlimited stack -** space (and to reserve some numbers for pseudo-indices). +@@ LUA_INTEGER is the integer type used by Lua. +** +@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. +** +@@ LUAI_UACINT is the result of an 'usual argument conversion' +@@ over a lUA_INTEGER. +@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. +@@ LUA_INTEGER_FMT is the format for writing integers. +@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. +@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. +@@ lua_integer2str converts an integer to a string. */ -#if LUAI_BITSINT >= 32 -#define LUAI_MAXSTACK 1000000 -#else -#define LUAI_MAXSTACK 15000 -#endif -/* reserve some space for error handling */ -#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000) +/* The following definitions are good for most cases here */ +#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" +#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n)) +#define LUAI_UACINT LUA_INTEGER /* -@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. -** CHANGE it if it uses too much C-stack space. +** use LUAI_UACINT here to avoid problems with promotions (which +** can turn a comparison between unsigneds into a signed comparison) */ -#define LUAL_BUFFERSIZE BUFSIZ +#define LUA_UNSIGNED unsigned LUAI_UACINT +/* now the variable definitions */ + +#if LUA_INT_TYPE == LUA_INT_INT /* { int */ + +#define LUA_INTEGER int +#define LUA_INTEGER_FRMLEN "" + +#define LUA_MAXINTEGER INT_MAX +#define LUA_MININTEGER INT_MIN + +#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ + +#define LUA_INTEGER long +#define LUA_INTEGER_FRMLEN "l" + +#define LUA_MAXINTEGER LONG_MAX +#define LUA_MININTEGER LONG_MIN + +#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ + +/* use presence of macro LLONG_MAX as proxy for C99 compliance */ +#if defined(LLONG_MAX) /* { */ +/* use ISO C99 stuff */ + +#define LUA_INTEGER long long +#define LUA_INTEGER_FRMLEN "ll" + +#define LUA_MAXINTEGER LLONG_MAX +#define LUA_MININTEGER LLONG_MIN + +#elif defined(LUA_USE_WINDOWS) /* }{ */ +/* in Windows, can use specific Windows types */ + +#define LUA_INTEGER __int64 +#define LUA_INTEGER_FRMLEN "I64" + +#define LUA_MAXINTEGER _I64_MAX +#define LUA_MININTEGER _I64_MIN + +#else /* }{ */ + +#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ + or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" + +#endif /* } */ + +#else /* }{ */ + +#error "numeric integer type not defined" + +#endif /* } */ + +/* }================================================================== */ /* ** {================================================================== -@@ LUA_NUMBER is the type of numbers in Lua. -** CHANGE the following definitions only if you want to build Lua -** with a number type different from double. You may also need to -** change lua_number2int & lua_number2integer. +** Dependencies with C99 and other C details ** =================================================================== */ -#define LUA_NUMBER_DOUBLE -#define LUA_NUMBER double - /* -@@ LUAI_UACNUMBER is the result of an 'usual argument conversion' -@* over a number. +@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89. +** (All uses in Lua have only one format item.) */ -#define LUAI_UACNUMBER double +#if !defined(LUA_USE_C89) +#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i) +#else +#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i)) +#endif /* -@@ LUA_NUMBER_SCAN is the format for reading numbers. -@@ LUA_NUMBER_FMT is the format for writing numbers. -@@ lua_number2str converts a number to a string. -@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. +@@ lua_strx2number converts an hexadecimal numeric string to a number. +** In C99, 'strtod' does that conversion. Otherwise, you can +** leave 'lua_strx2number' undefined and Lua will provide its own +** implementation. */ -#define LUA_NUMBER_SCAN "%lf" -#define LUA_NUMBER_FMT "%.14g" -#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) -#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */ +#if !defined(LUA_USE_C89) +#define lua_strx2number(s,p) lua_str2number(s,p) +#endif /* -@@ l_mathop allows the addition of an 'l' or 'f' to all math operations +@@ lua_number2strx converts a float to an hexadecimal numeric string. +** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. +** Otherwise, you can leave 'lua_number2strx' undefined and Lua will +** provide its own implementation. */ -#define l_mathop(x) (x) +#if !defined(LUA_USE_C89) +#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n)) +#endif /* -@@ lua_str2number converts a decimal numeric string to a number. -@@ lua_strx2number converts an hexadecimal numeric string to a number. -** In C99, 'strtod' does both conversions. C89, however, has no function -** to convert floating hexadecimal strings to numbers. For these -** systems, you can leave 'lua_strx2number' undefined and Lua will -** provide its own implementation. +** 'strtof' and 'opf' variants for math functions are not valid in +** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the +** availability of these variants. ('math.h' is already included in +** all files that use these macros.) */ -#define lua_str2number(s,p) strtod((s), (p)) - -#if defined(LUA_USE_STRTODHEX) -#define lua_strx2number(s,p) strtod((s), (p)) +#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) +#undef l_mathop /* variants not available */ +#undef lua_str2number +#define l_mathop(op) (lua_Number)op /* no variant */ +#define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) #endif /* -@@ The luai_num* macros define the primitive operations over numbers. +@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation +** functions. It must be a numerical type; Lua will use 'intptr_t' if +** available, otherwise it will use 'ptrdiff_t' (the nearest thing to +** 'intptr_t' in C89) */ +#define LUA_KCONTEXT ptrdiff_t -/* the following operations need the math library */ -#if defined(lobject_c) || defined(lvm_c) -#include -#define luai_nummod(L,a,b) ((a) - l_mathop(floor)((a)/(b))*(b)) -#define luai_numpow(L,a,b) (l_mathop(pow)(a,b)) +#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 199901L +#include +#if defined(INTPTR_MAX) /* even in C99 this type is optional */ +#undef LUA_KCONTEXT +#define LUA_KCONTEXT intptr_t #endif - -/* these are quite standard operations */ -#if defined(LUA_CORE) -#define luai_numadd(L,a,b) ((a)+(b)) -#define luai_numsub(L,a,b) ((a)-(b)) -#define luai_nummul(L,a,b) ((a)*(b)) -#define luai_numdiv(L,a,b) ((a)/(b)) -#define luai_numunm(L,a) (-(a)) -#define luai_numeq(a,b) ((a)==(b)) -#define luai_numlt(L,a,b) ((a)<(b)) -#define luai_numle(L,a,b) ((a)<=(b)) -#define luai_numisnan(L,a) (!luai_numeq((a), (a))) #endif - /* -@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. -** CHANGE that if ptrdiff_t is not adequate on your machine. (On most -** machines, ptrdiff_t gives a good choice between int or long.) +@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). +** Change that if you do not want to use C locales. (Code using this +** macro must include header 'locale.h'.) */ -#define LUA_INTEGER ptrdiff_t - -/* -@@ LUA_UNSIGNED is the integral type used by lua_pushunsigned/lua_tounsigned. -** It must have at least 32 bits. -*/ -#define LUA_UNSIGNED unsigned LUA_INT32 +#if !defined(lua_getlocaledecpoint) +#define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif +/* }================================================================== */ /* -** Some tricks with doubles +** {================================================================== +** Language Variations +** ===================================================================== */ -#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ /* -** The next definitions activate some tricks to speed up the -** conversion from doubles to integer types, mainly to LUA_UNSIGNED. -** -@@ LUA_MSASMTRICK uses Microsoft assembler to avoid clashes with a -** DirectX idiosyncrasy. -** -@@ LUA_IEEE754TRICK uses a trick that should work on any machine -** using IEEE754 with a 32-bit integer type. -** -@@ LUA_IEEELL extends the trick to LUA_INTEGER; should only be -** defined when LUA_INTEGER is a 32-bit integer. -** -@@ LUA_IEEEENDIAN is the endianness of doubles in your machine -** (0 for little endian, 1 for big endian); if not defined, Lua will -** check it dynamically for LUA_IEEE754TRICK (but not for LUA_NANTRICK). -** -@@ LUA_NANTRICK controls the use of a trick to pack all types into -** a single double value, using NaN values to represent non-number -** values. The trick only works on 32-bit machines (ints and pointers -** are 32-bit values) with numbers represented as IEEE 754-2008 doubles -** with conventional endianess (12345678 or 87654321), in CPUs that do -** not produce signaling NaN values (all NaNs are quiet). +@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some +** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from +** numbers to strings. Define LUA_NOCVTS2N to turn off automatic +** coercion from strings to numbers. */ +/* #define LUA_NOCVTN2S */ +/* #define LUA_NOCVTS2N */ -/* Microsoft compiler on a Pentium (32 bit) ? */ -#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */ - -#define LUA_MSASMTRICK -#define LUA_IEEEENDIAN 0 -#define LUA_NANTRICK +/* +@@ LUA_USE_APICHECK turns on several consistency checks on the C API. +** Define it as a help when debugging C code. +*/ +#if defined(LUA_USE_APICHECK) +#include +#define luai_apicheck(l,e) assert(e) +#endif -/* pentium 32 bits? */ -#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */ +/* }================================================================== */ -#define LUA_IEEE754TRICK -#define LUA_IEEELL -#define LUA_IEEEENDIAN 0 -#define LUA_NANTRICK -/* pentium 64 bits? */ -#elif defined(__x86_64) /* }{ */ +/* +** {================================================================== +** Macros that affect the API and must be stable (that is, must be the +** same when you compile Lua and when you compile code that links to +** Lua). You probably do not want/need to change them. +** ===================================================================== +*/ -#define LUA_IEEE754TRICK -#define LUA_IEEEENDIAN 0 +/* +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua from consuming unlimited stack +** space (and to reserve some numbers for pseudo-indices). +*/ +#if LUAI_BITSINT >= 32 +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif -#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */ -#define LUA_IEEE754TRICK -#define LUA_IEEEENDIAN 1 +/* +@@ LUA_EXTRASPACE defines the size of a raw memory area associated with +** a Lua state with very fast access. +** CHANGE it if you need a different size. +*/ +#define LUA_EXTRASPACE (sizeof(void *)) -#else /* }{ */ -/* assume IEEE754 and a 32-bit integer type */ -#define LUA_IEEE754TRICK +/* +@@ LUA_IDSIZE gives the maximum size for the description of the source +@@ of a function in debug information. +** CHANGE it if you want a different size. +*/ +#define LUA_IDSIZE 60 -#endif /* } */ -#endif /* } */ +/* +@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. +** CHANGE it if it uses too much C-stack space. (For long double, +** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a +** smaller buffer would force a memory allocation for each call to +** 'string.format'.) +*/ +#if defined(LUA_FLOAT_LONGDOUBLE) +#define LUAL_BUFFERSIZE 8192 +#else +#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer))) +#endif /* }================================================================== */ +/* +@@ LUA_QL describes how error messages quote program elements. +** Lua does not use these macros anymore; they are here for +** compatibility only. +*/ +#define LUA_QL(x) "'" x "'" +#define LUA_QS LUA_QL("%s") + + /* =================================================================== */ @@ -549,5 +761,7 @@ + + #endif diff --git a/depends/lua/include/lualib.h b/depends/lua/include/lualib.h index da82005c9..5165c0fb3 100644 --- a/depends/lua/include/lualib.h +++ b/depends/lua/include/lualib.h @@ -1,5 +1,5 @@ /* -** $Id: lualib.h,v 1.43.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ @@ -29,6 +29,9 @@ LUAMOD_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" LUAMOD_API int (luaopen_string) (lua_State *L); +#define LUA_UTF8LIBNAME "utf8" +LUAMOD_API int (luaopen_utf8) (lua_State *L); + #define LUA_BITLIBNAME "bit32" LUAMOD_API int (luaopen_bit32) (lua_State *L); diff --git a/depends/lua/include/lundump.h b/depends/lua/include/lundump.h index 5255db259..aa5cc82f1 100644 --- a/depends/lua/include/lundump.h +++ b/depends/lua/include/lundump.h @@ -1,5 +1,5 @@ /* -** $Id: lundump.h,v 1.39.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -7,22 +7,26 @@ #ifndef lundump_h #define lundump_h +#include "llimits.h" #include "lobject.h" #include "lzio.h" -/* load one chunk; from lundump.c */ -LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); -/* make header; from lundump.c */ -LUAI_FUNC void luaU_header (lu_byte* h); +/* data to catch conversion errors */ +#define LUAC_DATA "\x19\x93\r\n\x1a\n" -/* dump one chunk; from ldump.c */ -LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); +#define LUAC_INT 0x5678 +#define LUAC_NUM cast_num(370.5) -/* data to catch conversion errors */ -#define LUAC_TAIL "\x19\x93\r\n\x1a\n" +#define MYINT(s) (s[0]-'0') +#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) +#define LUAC_FORMAT 0 /* this is the official format */ -/* size in bytes of header of binary files */ -#define LUAC_HEADERSIZE (sizeof(LUA_SIGNATURE)-sizeof(char)+2+6+sizeof(LUAC_TAIL)-sizeof(char)) +/* load one chunk; from lundump.c */ +LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); + +/* dump one chunk; from ldump.c */ +LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, + void* data, int strip); #endif diff --git a/depends/lua/include/lvm.h b/depends/lua/include/lvm.h index 5380270da..bcf52d20a 100644 --- a/depends/lua/include/lvm.h +++ b/depends/lua/include/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.18.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -13,32 +13,101 @@ #include "ltm.h" -#define tostring(L,o) (ttisstring(o) || (luaV_tostring(L, o))) +#if !defined(LUA_NOCVTN2S) +#define cvt2str(o) ttisnumber(o) +#else +#define cvt2str(o) 0 /* no conversion from numbers to strings */ +#endif + + +#if !defined(LUA_NOCVTS2N) +#define cvt2num(o) ttisstring(o) +#else +#define cvt2num(o) 0 /* no conversion from strings to numbers */ +#endif + + +/* +** You can define LUA_FLOORN2I if you want to convert floats to integers +** by flooring them (instead of raising an error if they are not +** integral values) +*/ +#if !defined(LUA_FLOORN2I) +#define LUA_FLOORN2I 0 +#endif + + +#define tonumber(o,n) \ + (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) -#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL)) +#define tointeger(o,i) \ + (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) -#define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2)) +#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) -#define luaV_rawequalobj(o1,o2) equalobj(NULL,o1,o2) +#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) + + +/* +** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, +** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise, +** return 0 (meaning it will have to check metamethod) with 'slot' +** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise). +** 'f' is the raw get function to use. +*/ +#define luaV_fastget(L,t,k,slot,f) \ + (!ttistable(t) \ + ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ + : (slot = f(hvalue(t), k), /* else, do raw access */ \ + !ttisnil(slot))) /* result not nil? */ + +/* +** standard implementation for 'gettable' +*/ +#define luaV_gettable(L,t,k,v) { const TValue *slot; \ + if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ + else luaV_finishget(L,t,k,v,slot); } + + +/* +** Fast track for set table. If 't' is a table and 't[k]' is not nil, +** call GC barrier, do a raw 't[k]=v', and return true; otherwise, +** return false with 'slot' equal to NULL (if 't' is not a table) or +** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro +** returns true, there is no need to 'invalidateTMcache', because the +** call is not creating a new entry. +*/ +#define luaV_fastset(L,t,k,slot,f,v) \ + (!ttistable(t) \ + ? (slot = NULL, 0) \ + : (slot = f(hvalue(t), k), \ + ttisnil(slot) ? 0 \ + : (luaC_barrierback(L, hvalue(t), v), \ + setobj2t(L, cast(TValue *,slot), v), \ + 1))) -/* not to called directly */ -LUAI_FUNC int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2); +#define luaV_settable(L,t,k,v) { const TValue *slot; \ + if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ + luaV_finishset(L,t,k,v,slot); } + +LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); -LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); -LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); -LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, - StkId val); -LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, - StkId val); +LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); +LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); +LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot); +LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot); LUAI_FUNC void luaV_finishOp (lua_State *L); LUAI_FUNC void luaV_execute (lua_State *L); LUAI_FUNC void luaV_concat (lua_State *L, int total); -LUAI_FUNC void luaV_arith (lua_State *L, StkId ra, const TValue *rb, - const TValue *rc, TMS op); +LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); +LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); #endif diff --git a/depends/lua/include/lzio.h b/depends/lua/include/lzio.h index 441f7479c..e7b6f34b1 100644 --- a/depends/lua/include/lzio.h +++ b/depends/lua/include/lzio.h @@ -1,5 +1,5 @@ /* -** $Id: lzio.h,v 1.26.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ @@ -32,20 +32,21 @@ typedef struct Mbuffer { #define luaZ_sizebuffer(buff) ((buff)->buffsize) #define luaZ_bufflen(buff) ((buff)->n) +#define luaZ_buffremove(buff,i) ((buff)->n -= (i)) #define luaZ_resetbuffer(buff) ((buff)->n = 0) #define luaZ_resizebuffer(L, buff, size) \ - (luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ + ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ + (buff)->buffsize, size), \ (buff)->buffsize = size) #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) -LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n); LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data); -LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */ +LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ @@ -55,7 +56,7 @@ struct Zio { size_t n; /* bytes still unread */ const char *p; /* current position in buffer */ lua_Reader reader; /* reader function */ - void* data; /* additional data */ + void *data; /* additional data */ lua_State *L; /* Lua state (for reader) */ }; diff --git a/depends/lua/src/lapi.c b/depends/lua/src/lapi.c index d011431ea..c9455a5d8 100644 --- a/depends/lua/src/lapi.c +++ b/depends/lua/src/lapi.c @@ -1,16 +1,18 @@ /* -** $Id: lapi.c,v 2.171.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ +#define lapi_c +#define LUA_CORE + +#include "lprefix.h" + #include #include -#define lapi_c -#define LUA_CORE - #include "lua.h" #include "lapi.h" @@ -43,13 +45,16 @@ const char lua_ident[] = /* test for pseudo index */ #define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) +/* test for upvalue */ +#define isupvalue(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_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") +#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) { @@ -89,21 +94,22 @@ static void growstack (lua_State *L, void *ud) { } -LUA_API int lua_checkstack (lua_State *L, int size) { +LUA_API int lua_checkstack (lua_State *L, int n) { int res; CallInfo *ci = L->ci; lua_lock(L); - if (L->stack_last - L->top > size) /* stack large enough? */ + api_check(L, n >= 0, "negative 'n'"); + if (L->stack_last - L->top > n) /* stack large enough? */ res = 1; /* yes; check is OK */ else { /* no; need to grow stack */ int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; - if (inuse > LUAI_MAXSTACK - size) /* can grow without overflow? */ + if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ res = 0; /* no */ else /* try to grow stack */ - res = (luaD_rawrunprotected(L, &growstack, &size) == LUA_OK); + res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); } - if (res && ci->top < L->top + size) - ci->top = L->top + size; /* adjust frame top */ + if (res && ci->top < L->top + n) + ci->top = L->top + n; /* adjust frame top */ lua_unlock(L); return res; } @@ -115,10 +121,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { lua_lock(to); api_checknelems(from, n); api_check(from, G(from) == G(to), "moving among independent states"); - api_check(from, to->ci->top - to->top >= n, "not enough elements to move"); + api_check(from, to->ci->top - to->top >= n, "stack overflow"); from->top -= n; for (i = 0; i < n; i++) { - setobj2s(to, to->top++, from->top + i); + setobj2s(to, to->top, from->top + i); + to->top++; /* stack already checked by previous 'api_check' */ } lua_unlock(to); } @@ -153,7 +160,7 @@ LUA_API const lua_Number *lua_version (lua_State *L) { LUA_API int lua_absindex (lua_State *L, int idx) { return (idx > 0 || ispseudo(idx)) ? idx - : cast_int(L->top - L->ci->func + idx); + : cast_int(L->top - L->ci->func) + idx; } @@ -173,61 +180,56 @@ LUA_API void lua_settop (lua_State *L, int idx) { } else { api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); - L->top += idx+1; /* `subtract' index (index is negative) */ + L->top += idx+1; /* 'subtract' index (index is negative) */ } lua_unlock(L); } -LUA_API void lua_remove (lua_State *L, int idx) { - StkId p; - lua_lock(L); - p = index2addr(L, idx); - api_checkstackindex(L, idx, p); - while (++p < L->top) setobjs2s(L, p-1, p); - L->top--; - lua_unlock(L); +/* +** Reverse the stack segment from 'from' to 'to' +** (auxiliary to 'lua_rotate') +*/ +static void reverse (lua_State *L, StkId from, StkId to) { + for (; from < to; from++, to--) { + TValue temp; + setobj(L, &temp, from); + setobjs2s(L, from, to); + setobj2s(L, to, &temp); + } } -LUA_API void lua_insert (lua_State *L, int idx) { - StkId p; - StkId q; +/* +** Let x = AB, where A is a prefix of length 'n'. Then, +** rotate x n == BA. But BA == (A^r . B^r)^r. +*/ +LUA_API void lua_rotate (lua_State *L, int idx, int n) { + StkId p, t, m; lua_lock(L); - p = index2addr(L, idx); + t = L->top - 1; /* end of stack segment being rotated */ + p = index2addr(L, idx); /* start of segment */ api_checkstackindex(L, idx, p); - for (q = L->top; q > p; q--) /* use L->top as a temporary */ - setobjs2s(L, q, q - 1); - setobjs2s(L, p, L->top); + api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); + m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ + reverse(L, p, m); /* reverse the prefix with length 'n' */ + reverse(L, m + 1, t); /* reverse the suffix */ + reverse(L, p, t); /* reverse the entire segment */ lua_unlock(L); } -static void moveto (lua_State *L, TValue *fr, int idx) { - TValue *to = index2addr(L, idx); +LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { + TValue *fr, *to; + lua_lock(L); + fr = index2addr(L, fromidx); + to = index2addr(L, toidx); api_checkvalidindex(L, to); setobj(L, to, fr); - if (idx < LUA_REGISTRYINDEX) /* function upvalue? */ + if (isupvalue(toidx)) /* function upvalue? */ luaC_barrier(L, clCvalue(L->ci->func), fr); /* LUA_REGISTRYINDEX does not need gc barrier (collector revisits it before finishing collection) */ -} - - -LUA_API void lua_replace (lua_State *L, int idx) { - lua_lock(L); - api_checknelems(L, 1); - moveto(L, L->top - 1, idx); - L->top--; - lua_unlock(L); -} - - -LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { - TValue *fr; - lua_lock(L); - fr = index2addr(L, fromidx); - moveto(L, fr, toidx); lua_unlock(L); } @@ -248,12 +250,13 @@ LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API int lua_type (lua_State *L, int idx) { StkId o = index2addr(L, idx); - return (isvalid(o) ? ttypenv(o) : LUA_TNONE); + return (isvalid(o) ? ttnov(o) : LUA_TNONE); } LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); + api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag"); return ttypename(t); } @@ -264,22 +267,28 @@ LUA_API int lua_iscfunction (lua_State *L, int idx) { } +LUA_API int lua_isinteger (lua_State *L, int idx) { + StkId o = index2addr(L, idx); + return ttisinteger(o); +} + + LUA_API int lua_isnumber (lua_State *L, int idx) { - TValue n; + lua_Number n; const TValue *o = index2addr(L, idx); return tonumber(o, &n); } LUA_API int lua_isstring (lua_State *L, int idx) { - int t = lua_type(L, idx); - return (t == LUA_TSTRING || t == LUA_TNUMBER); + const TValue *o = index2addr(L, idx); + return (ttisstring(o) || cvt2str(o)); } LUA_API int lua_isuserdata (lua_State *L, int idx) { const TValue *o = index2addr(L, idx); - return (ttisuserdata(o) || ttislightuserdata(o)); + return (ttisfulluserdata(o) || ttislightuserdata(o)); } @@ -291,24 +300,17 @@ LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { LUA_API void lua_arith (lua_State *L, int op) { - StkId o1; /* 1st operand */ - StkId o2; /* 2nd operand */ lua_lock(L); - if (op != LUA_OPUNM) /* all other operations expect two operands */ - api_checknelems(L, 2); - else { /* for unary minus, add fake 2nd operand */ + if (op != LUA_OPUNM && op != LUA_OPBNOT) + api_checknelems(L, 2); /* all other operations expect two operands */ + else { /* for unary operations, add fake 2nd operand */ api_checknelems(L, 1); setobjs2s(L, L->top, L->top - 1); - L->top++; - } - o1 = L->top - 2; - o2 = L->top - 1; - if (ttisnumber(o1) && ttisnumber(o2)) { - setnvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2))); + api_incr_top(L); } - else - luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD)); - L->top--; + /* first operand at top - 2, second at top - 1; result go to top - 2 */ + luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2); + L->top--; /* remove second operand */ lua_unlock(L); } @@ -321,7 +323,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { o2 = index2addr(L, index2); if (isvalid(o1) && isvalid(o2)) { switch (op) { - case LUA_OPEQ: i = equalobj(L, o1, o2); break; + case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break; case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; default: api_check(L, 0, "invalid option"); @@ -332,51 +334,33 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { } -LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *isnum) { - TValue n; - const TValue *o = index2addr(L, idx); - if (tonumber(o, &n)) { - if (isnum) *isnum = 1; - return nvalue(o); - } - else { - if (isnum) *isnum = 0; - return 0; - } +LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { + size_t sz = luaO_str2num(s, L->top); + if (sz != 0) + api_incr_top(L); + return sz; } -LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum) { - TValue n; +LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) { + lua_Number n; const TValue *o = index2addr(L, idx); - if (tonumber(o, &n)) { - lua_Integer res; - lua_Number num = nvalue(o); - lua_number2integer(res, num); - if (isnum) *isnum = 1; - return res; - } - else { - if (isnum) *isnum = 0; - return 0; - } + int isnum = tonumber(o, &n); + if (!isnum) + n = 0; /* call to 'tonumber' may change 'n' even if it fails */ + if (pisnum) *pisnum = isnum; + return n; } -LUA_API lua_Unsigned lua_tounsignedx (lua_State *L, int idx, int *isnum) { - TValue n; +LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) { + lua_Integer res; const TValue *o = index2addr(L, idx); - if (tonumber(o, &n)) { - lua_Unsigned res; - lua_Number num = nvalue(o); - lua_number2unsigned(res, num); - if (isnum) *isnum = 1; - return res; - } - else { - if (isnum) *isnum = 0; - return 0; - } + int isnum = tointeger(o, &res); + if (!isnum) + res = 0; /* call to 'tointeger' may change 'n' even if it fails */ + if (pisnum) *pisnum = isnum; + return res; } @@ -389,25 +373,27 @@ LUA_API int lua_toboolean (lua_State *L, int idx) { LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { StkId o = index2addr(L, idx); if (!ttisstring(o)) { - lua_lock(L); /* `luaV_tostring' may create a new string */ - if (!luaV_tostring(L, o)) { /* conversion failed? */ + if (!cvt2str(o)) { /* not convertible? */ if (len != NULL) *len = 0; - lua_unlock(L); return NULL; } + lua_lock(L); /* 'luaO_tostring' may create a new string */ + luaO_tostring(L, o); luaC_checkGC(L); o = index2addr(L, idx); /* previous call may reallocate the stack */ lua_unlock(L); } - if (len != NULL) *len = tsvalue(o)->len; + if (len != NULL) + *len = vslen(o); return svalue(o); } LUA_API size_t lua_rawlen (lua_State *L, int idx) { StkId o = index2addr(L, idx); - switch (ttypenv(o)) { - case LUA_TSTRING: return tsvalue(o)->len; + switch (ttype(o)) { + case LUA_TSHRSTR: return tsvalue(o)->shrlen; + case LUA_TLNGSTR: return tsvalue(o)->u.lnglen; case LUA_TUSERDATA: return uvalue(o)->len; case LUA_TTABLE: return luaH_getn(hvalue(o)); default: return 0; @@ -426,8 +412,8 @@ LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { LUA_API void *lua_touserdata (lua_State *L, int idx) { StkId o = index2addr(L, idx); - switch (ttypenv(o)) { - case LUA_TUSERDATA: return (rawuvalue(o) + 1); + switch (ttnov(o)) { + case LUA_TUSERDATA: return getudatamem(uvalue(o)); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } @@ -448,9 +434,8 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) { case LUA_TCCL: return clCvalue(o); case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); case LUA_TTHREAD: return thvalue(o); - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - return lua_touserdata(L, idx); + case LUA_TUSERDATA: return getudatamem(uvalue(o)); + case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } } @@ -472,9 +457,7 @@ LUA_API void lua_pushnil (lua_State *L) { LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { lua_lock(L); - setnvalue(L->top, n); - luai_checknum(L, L->top, - luaG_runerror(L, "C API - attempt to push a signaling NaN")); + setfltvalue(L->top, n); api_incr_top(L); lua_unlock(L); } @@ -482,49 +465,43 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { lua_lock(L); - setnvalue(L->top, cast_num(n)); - api_incr_top(L); - lua_unlock(L); -} - - -LUA_API void lua_pushunsigned (lua_State *L, lua_Unsigned u) { - lua_Number n; - lua_lock(L); - n = lua_unsigned2number(u); - setnvalue(L->top, n); + setivalue(L->top, n); api_incr_top(L); lua_unlock(L); } +/* +** Pushes on the stack a string with given length. Avoid using 's' when +** 'len' == 0 (as 's' can be NULL in that case), due to later use of +** 'memcmp' and 'memcpy'. +*/ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { TString *ts; lua_lock(L); - luaC_checkGC(L); - ts = luaS_newlstr(L, s, len); + ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); setsvalue2s(L, L->top, ts); api_incr_top(L); + luaC_checkGC(L); lua_unlock(L); return getstr(ts); } LUA_API const char *lua_pushstring (lua_State *L, const char *s) { - if (s == NULL) { - lua_pushnil(L); - return NULL; - } + lua_lock(L); + if (s == NULL) + setnilvalue(L->top); else { TString *ts; - lua_lock(L); - luaC_checkGC(L); ts = luaS_new(L, s); setsvalue2s(L, L->top, ts); - api_incr_top(L); - lua_unlock(L); - return getstr(ts); + s = getstr(ts); /* internal copy's address */ } + api_incr_top(L); + luaC_checkGC(L); + lua_unlock(L); + return s; } @@ -532,8 +509,8 @@ LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp) { const char *ret; lua_lock(L); - luaC_checkGC(L); ret = luaO_pushvfstring(L, fmt, argp); + luaC_checkGC(L); lua_unlock(L); return ret; } @@ -543,10 +520,10 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { const char *ret; va_list argp; lua_lock(L); - luaC_checkGC(L); va_start(argp, fmt); ret = luaO_pushvfstring(L, fmt, argp); va_end(argp); + luaC_checkGC(L); lua_unlock(L); return ret; } @@ -558,18 +535,20 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { setfvalue(L->top, fn); } else { - Closure *cl; + CClosure *cl; api_checknelems(L, n); api_check(L, n <= MAXUPVAL, "upvalue index too large"); - luaC_checkGC(L); cl = luaF_newCclosure(L, n); - cl->c.f = fn; + cl->f = fn; L->top -= n; - while (n--) - setobj2n(L, &cl->c.upvalue[n], L->top + n); + while (n--) { + setobj2n(L, &cl->upvalue[n], L->top + n); + /* does not need barrier because closure is white */ + } setclCvalue(L, L->top, cl); } api_incr_top(L); + luaC_checkGC(L); lua_unlock(L); } @@ -605,48 +584,77 @@ LUA_API int lua_pushthread (lua_State *L) { */ -LUA_API void lua_getglobal (lua_State *L, const char *var) { +static int auxgetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TString *str = luaS_new(L, k); + if (luaV_fastget(L, t, str, slot, luaH_getstr)) { + setobj2s(L, L->top, slot); + api_incr_top(L); + } + else { + setsvalue2s(L, L->top, str); + api_incr_top(L); + luaV_finishget(L, t, L->top - 1, L->top - 1, slot); + } + lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_getglobal (lua_State *L, const char *name) { Table *reg = hvalue(&G(L)->l_registry); - const TValue *gt; /* global table */ lua_lock(L); - gt = luaH_getint(reg, LUA_RIDX_GLOBALS); - setsvalue2s(L, L->top++, luaS_new(L, var)); - luaV_gettable(L, gt, L->top - 1, L->top - 1); - lua_unlock(L); + return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); } -LUA_API void lua_gettable (lua_State *L, int idx) { +LUA_API int lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); + return ttnov(L->top - 1); +} + + +LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { + lua_lock(L); + return auxgetstr(L, index2addr(L, idx), k); } -LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { +LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { StkId t; + const TValue *slot; lua_lock(L); t = index2addr(L, idx); - setsvalue2s(L, L->top, luaS_new(L, k)); - api_incr_top(L); - luaV_gettable(L, t, L->top - 1, L->top - 1); + if (luaV_fastget(L, t, n, slot, luaH_getint)) { + setobj2s(L, L->top, slot); + api_incr_top(L); + } + else { + setivalue(L->top, n); + api_incr_top(L); + luaV_finishget(L, t, L->top - 1, L->top - 1, slot); + } lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API void lua_rawget (lua_State *L, int idx) { +LUA_API int lua_rawget (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { +LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { StkId t; lua_lock(L); t = index2addr(L, idx); @@ -654,10 +662,11 @@ LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { setobj2s(L, L->top, luaH_getint(hvalue(t), n)); api_incr_top(L); lua_unlock(L); + return ttnov(L->top - 1); } -LUA_API void lua_rawgetp (lua_State *L, int idx, const void *p) { +LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { StkId t; TValue k; lua_lock(L); @@ -667,29 +676,30 @@ LUA_API void lua_rawgetp (lua_State *L, int idx, const void *p) { setobj2s(L, L->top, luaH_get(hvalue(t), &k)); api_incr_top(L); lua_unlock(L); + return ttnov(L->top - 1); } LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { Table *t; lua_lock(L); - luaC_checkGC(L); t = luaH_new(L); sethvalue(L, L->top, t); api_incr_top(L); if (narray > 0 || nrec > 0) luaH_resize(L, t, narray, nrec); + luaC_checkGC(L); lua_unlock(L); } LUA_API int lua_getmetatable (lua_State *L, int objindex) { const TValue *obj; - Table *mt = NULL; - int res; + Table *mt; + int res = 0; lua_lock(L); obj = index2addr(L, objindex); - switch (ttypenv(obj)) { + switch (ttnov(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; break; @@ -697,12 +707,10 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { mt = uvalue(obj)->metatable; break; default: - mt = G(L)->mt[ttypenv(obj)]; + mt = G(L)->mt[ttnov(obj)]; break; } - if (mt == NULL) - res = 0; - else { + if (mt != NULL) { sethvalue(L, L->top, mt); api_incr_top(L); res = 1; @@ -712,17 +720,15 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) { } -LUA_API void lua_getuservalue (lua_State *L, int idx) { +LUA_API int lua_getuservalue (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2addr(L, idx); - api_check(L, ttisuserdata(o), "userdata expected"); - if (uvalue(o)->env) { - sethvalue(L, L->top, uvalue(o)->env); - } else - setnilvalue(L->top); + api_check(L, ttisfulluserdata(o), "full userdata expected"); + getuservalue(L, uvalue(o), L->top); api_incr_top(L); lua_unlock(L); + return ttnov(L->top - 1); } @@ -730,17 +736,29 @@ LUA_API void lua_getuservalue (lua_State *L, int idx) { ** set functions (stack -> Lua) */ +/* +** t[k] = value at the top of the stack (where 'k' is a string) +*/ +static void auxsetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TString *str = luaS_new(L, k); + api_checknelems(L, 1); + if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1)) + L->top--; /* pop value */ + else { + setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ + api_incr_top(L); + luaV_finishset(L, t, L->top - 1, L->top - 2, slot); + L->top -= 2; /* pop value and key */ + } + lua_unlock(L); /* lock done by caller */ +} + -LUA_API void lua_setglobal (lua_State *L, const char *var) { +LUA_API void lua_setglobal (lua_State *L, const char *name) { Table *reg = hvalue(&G(L)->l_registry); - const TValue *gt; /* global table */ - lua_lock(L); - api_checknelems(L, 1); - gt = luaH_getint(reg, LUA_RIDX_GLOBALS); - setsvalue2s(L, L->top++, luaS_new(L, var)); - luaV_settable(L, gt, L->top - 1, L->top - 2); - L->top -= 2; /* pop value and key */ - lua_unlock(L); + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); } @@ -756,54 +774,69 @@ LUA_API void lua_settable (lua_State *L, int idx) { LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { + lua_lock(L); /* unlock done in 'auxsetstr' */ + auxsetstr(L, index2addr(L, idx), k); +} + + +LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { StkId t; + const TValue *slot; lua_lock(L); api_checknelems(L, 1); t = index2addr(L, idx); - setsvalue2s(L, L->top++, luaS_new(L, k)); - luaV_settable(L, t, L->top - 1, L->top - 2); - L->top -= 2; /* pop value and key */ + if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1)) + L->top--; /* pop value */ + else { + setivalue(L->top, n); + api_incr_top(L); + luaV_finishset(L, t, L->top - 1, L->top - 2, slot); + L->top -= 2; /* pop value and key */ + } lua_unlock(L); } LUA_API void lua_rawset (lua_State *L, int idx) { - StkId t; + StkId o; + TValue *slot; lua_lock(L); api_checknelems(L, 2); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - setobj2t(L, luaH_set(L, hvalue(t), L->top-2), L->top-1); - invalidateTMcache(hvalue(t)); - luaC_barrierback(L, gcvalue(t), L->top-1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + slot = luaH_set(L, hvalue(o), L->top - 2); + setobj2t(L, slot, L->top - 1); + invalidateTMcache(hvalue(o)); + luaC_barrierback(L, hvalue(o), L->top-1); L->top -= 2; lua_unlock(L); } -LUA_API void lua_rawseti (lua_State *L, int idx, int n) { - StkId t; +LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) { + StkId o; lua_lock(L); api_checknelems(L, 1); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); - luaH_setint(L, hvalue(t), n, L->top - 1); - luaC_barrierback(L, gcvalue(t), L->top-1); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); + luaH_setint(L, hvalue(o), n, L->top - 1); + luaC_barrierback(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); } LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { - StkId t; - TValue k; + StkId o; + TValue k, *slot; lua_lock(L); api_checknelems(L, 1); - t = index2addr(L, idx); - api_check(L, ttistable(t), "table expected"); + o = index2addr(L, idx); + api_check(L, ttistable(o), "table expected"); setpvalue(&k, cast(void *, p)); - setobj2t(L, luaH_set(L, hvalue(t), &k), L->top - 1); - luaC_barrierback(L, gcvalue(t), L->top - 1); + slot = luaH_set(L, hvalue(o), &k); + setobj2t(L, slot, L->top - 1); + luaC_barrierback(L, hvalue(o), L->top - 1); L->top--; lua_unlock(L); } @@ -821,11 +854,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { api_check(L, ttistable(L->top - 1), "table expected"); mt = hvalue(L->top - 1); } - switch (ttypenv(obj)) { + switch (ttnov(obj)) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) { - luaC_objbarrierback(L, gcvalue(obj), mt); + luaC_objbarrier(L, gcvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt); } break; @@ -833,13 +866,13 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { case LUA_TUSERDATA: { uvalue(obj)->metatable = mt; if (mt) { - luaC_objbarrier(L, rawuvalue(obj), mt); + luaC_objbarrier(L, uvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt); } break; } default: { - G(L)->mt[ttypenv(obj)] = mt; + G(L)->mt[ttnov(obj)] = mt; break; } } @@ -854,21 +887,16 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 1); o = index2addr(L, idx); - api_check(L, ttisuserdata(o), "userdata expected"); - if (ttisnil(L->top - 1)) - uvalue(o)->env = NULL; - else { - api_check(L, ttistable(L->top - 1), "table expected"); - uvalue(o)->env = hvalue(L->top - 1); - luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1)); - } + api_check(L, ttisfulluserdata(o), "full userdata expected"); + setuservalue(L, uvalue(o), L->top - 1); + luaC_barrier(L, gcvalue(o), L->top - 1); L->top--; lua_unlock(L); } /* -** `load' and `call' functions (run Lua code) +** 'load' and 'call' functions (run Lua code) */ @@ -877,17 +905,8 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) { "results from function overflow current stack size") -LUA_API int lua_getctx (lua_State *L, int *ctx) { - if (L->ci->callstatus & CIST_YIELDED) { - if (ctx) *ctx = L->ci->u.c.ctx; - return L->ci->u.c.status; - } - else return LUA_OK; -} - - -LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, - lua_CFunction k) { +LUA_API void lua_callk (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k) { StkId func; lua_lock(L); api_check(L, k == NULL || !isLua(L->ci), @@ -899,10 +918,10 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ L->ci->u.c.k = k; /* save continuation */ L->ci->u.c.ctx = ctx; /* save context */ - luaD_call(L, func, nresults, 1); /* do the call */ + luaD_call(L, func, nresults); /* do the call */ } else /* no continuation or no yieldable */ - luaD_call(L, func, nresults, 0); /* just do the call */ + luaD_callnoyield(L, func, nresults); /* just do the call */ adjustresults(L, nresults); lua_unlock(L); } @@ -912,7 +931,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, /* ** Execute a protected call. */ -struct CallS { /* data to `f_call' */ +struct CallS { /* data to 'f_call' */ StkId func; int nresults; }; @@ -920,13 +939,13 @@ struct CallS { /* data to `f_call' */ static void f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); - luaD_call(L, c->func, c->nresults, 0); + luaD_callnoyield(L, c->func, c->nresults); } LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, - int ctx, lua_CFunction k) { + lua_KContext ctx, lua_KFunction k) { struct CallS c; int status; ptrdiff_t func; @@ -954,12 +973,11 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, ci->u.c.ctx = ctx; /* save context */ /* save information for error recovery */ ci->extra = savestack(L, c.func); - ci->u.c.old_allowhook = L->allowhook; ci->u.c.old_errfunc = L->errfunc; L->errfunc = func; - /* mark that function may do error recovery */ - ci->callstatus |= CIST_YPCALL; - luaD_call(L, c.func, nresults, 1); /* do the call */ + setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ + ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ + luaD_call(L, c.func, nresults); /* do the call */ ci->callstatus &= ~CIST_YPCALL; L->errfunc = ci->u.c.old_errfunc; status = LUA_OK; /* if it is here, there were no errors */ @@ -980,13 +998,13 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, status = luaD_protectedparser(L, &z, chunkname, mode); if (status == LUA_OK) { /* no errors? */ LClosure *f = clLvalue(L->top - 1); /* get newly created function */ - if (f->nupvalues == 1) { /* does it have one upvalue? */ + if (f->nupvalues >= 1) { /* does it have an upvalue? */ /* get global table from registry */ Table *reg = hvalue(&G(L)->l_registry); const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ setobj(L, f->upvals[0]->v, gt); - luaC_barrier(L, f->upvals[0], gt); + luaC_upvalbarrier(L, f->upvals[0]); } } lua_unlock(L); @@ -994,14 +1012,14 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, } -LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { +LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { int status; TValue *o; lua_lock(L); api_checknelems(L, 1); o = L->top - 1; if (isLfunction(o)) - status = luaU_dump(L, getproto(o), writer, data, 0); + status = luaU_dump(L, getproto(o), writer, data, strip); else status = 1; lua_unlock(L); @@ -1047,19 +1065,21 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { break; } case LUA_GCSTEP: { - if (g->gckind == KGC_GEN) { /* generational mode? */ - res = (g->GCestimate == 0); /* true if it will do major collection */ - luaC_forcestep(L); /* do a single step */ + l_mem debt = 1; /* =1 to signal that it did an actual step */ + lu_byte oldrunning = g->gcrunning; + g->gcrunning = 1; /* allow GC to run */ + if (data == 0) { + luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ + luaC_step(L); } - else { - lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE; - if (g->gcrunning) - debt += g->GCdebt; /* include current debt */ - luaE_setdebt(g, debt); - luaC_forcestep(L); - if (g->gcstate == GCSpause) /* end of cycle? */ - res = 1; /* signal it */ + else { /* add 'data' to total debt */ + debt = cast(l_mem, data) * 1024 + g->GCdebt; + luaE_setdebt(g, debt); + luaC_checkGC(L); } + g->gcrunning = oldrunning; /* restore previous state */ + if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ break; } case LUA_GCSETPAUSE: { @@ -1067,13 +1087,9 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { g->gcpause = data; break; } - case LUA_GCSETMAJORINC: { - res = g->gcmajorinc; - g->gcmajorinc = data; - break; - } case LUA_GCSETSTEPMUL: { res = g->gcstepmul; + if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ g->gcstepmul = data; break; } @@ -1081,14 +1097,6 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { res = g->gcrunning; break; } - case LUA_GCGEN: { /* change collector to generational mode */ - luaC_changemode(L, KGC_GEN); - break; - } - case LUA_GCINC: { /* change collector to incremental mode */ - luaC_changemode(L, KGC_NORMAL); - break; - } default: res = -1; /* invalid option */ } lua_unlock(L); @@ -1132,7 +1140,6 @@ LUA_API void lua_concat (lua_State *L, int n) { lua_lock(L); api_checknelems(L, n); if (n >= 2) { - luaC_checkGC(L); luaV_concat(L, n); } else if (n == 0) { /* push empty string */ @@ -1140,6 +1147,7 @@ LUA_API void lua_concat (lua_State *L, int n) { api_incr_top(L); } /* else n == 1; nothing to do */ + luaC_checkGC(L); lua_unlock(L); } @@ -1175,24 +1183,24 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); - luaC_checkGC(L); - u = luaS_newudata(L, size, NULL); + u = luaS_newudata(L, size); setuvalue(L, L->top, u); api_incr_top(L); + luaC_checkGC(L); lua_unlock(L); - return u + 1; + return getudatamem(u); } static const char *aux_upvalue (StkId fi, int n, TValue **val, - GCObject **owner) { + CClosure **owner, UpVal **uv) { switch (ttype(fi)) { case LUA_TCCL: { /* C closure */ CClosure *f = clCvalue(fi); if (!(1 <= n && n <= f->nupvalues)) return NULL; *val = &f->upvalue[n-1]; - if (owner) *owner = obj2gco(f); + if (owner) *owner = f; return ""; } case LUA_TLCL: { /* Lua closure */ @@ -1201,9 +1209,9 @@ static const char *aux_upvalue (StkId fi, int n, TValue **val, Proto *p = f->p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->upvals[n-1]->v; - if (owner) *owner = obj2gco(f->upvals[n - 1]); + if (uv) *uv = f->upvals[n - 1]; name = p->upvalues[n-1].name; - return (name == NULL) ? "" : getstr(name); + return (name == NULL) ? "(*no name)" : getstr(name); } default: return NULL; /* not a closure */ } @@ -1214,7 +1222,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val = NULL; /* to avoid warnings */ lua_lock(L); - name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL); + name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); if (name) { setobj2s(L, L->top, val); api_incr_top(L); @@ -1227,16 +1235,18 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val = NULL; /* to avoid warnings */ - GCObject *owner = NULL; /* to avoid warnings */ + CClosure *owner = NULL; + UpVal *uv = NULL; StkId fi; lua_lock(L); fi = index2addr(L, funcindex); api_checknelems(L, 1); - name = aux_upvalue(fi, n, &val, &owner); + name = aux_upvalue(fi, n, &val, &owner, &uv); if (name) { L->top--; setobj(L, val, L->top); - luaC_barrier(L, owner, L->top); + if (owner) { luaC_barrier(L, owner, L->top); } + else if (uv) { luaC_upvalbarrier(L, uv); } } lua_unlock(L); return name; @@ -1278,7 +1288,11 @@ LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, LClosure *f1; UpVal **up1 = getupvalref(L, fidx1, n1, &f1); UpVal **up2 = getupvalref(L, fidx2, n2, NULL); + luaC_upvdeccount(L, *up1); *up1 = *up2; - luaC_objbarrier(L, f1, *up2); + (*up1)->refcount++; + if (upisopen(*up1)) (*up1)->u.open.touched = 1; + luaC_upvalbarrier(L, *up1); } + diff --git a/depends/lua/src/lauxlib.c b/depends/lua/src/lauxlib.c index b00f8c709..bacf43b3e 100644 --- a/depends/lua/src/lauxlib.c +++ b/depends/lua/src/lauxlib.c @@ -1,9 +1,14 @@ /* -** $Id: lauxlib.c,v 1.248.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lauxlib.c,v 1.286 2016/01/08 15:33:09 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ +#define lauxlib_c +#define LUA_LIB + +#include "lprefix.h" + #include #include @@ -12,13 +17,11 @@ #include -/* This file uses only the official API of Lua. +/* +** This file uses only the official API of Lua. ** Any function declared here could be written as an application function. */ -#define lauxlib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -31,8 +34,8 @@ */ -#define LEVELS1 12 /* size of the first part of the stack */ -#define LEVELS2 10 /* size of the second part of the stack */ +#define LEVELS1 10 /* size of the first part of the stack */ +#define LEVELS2 11 /* size of the second part of the stack */ @@ -64,11 +67,20 @@ static int findfield (lua_State *L, int objidx, int level) { } +/* +** Search for a name for a function in all loaded modules +** (registry._LOADED). +*/ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { int top = lua_gettop(L); lua_getinfo(L, "f", ar); /* push function */ - lua_pushglobaltable(L); + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); if (findfield(L, top + 1, 2)) { + const char *name = lua_tostring(L, -1); + if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */ + lua_pushstring(L, name + 3); /* push name without prefix */ + lua_remove(L, -2); /* remove original name */ + } lua_copy(L, -1, top + 1); /* move name to proper place */ lua_pop(L, 2); /* remove pushed values */ return 1; @@ -81,24 +93,22 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { static void pushfuncname (lua_State *L, lua_Debug *ar) { - if (*ar->namewhat != '\0') /* is there a name? */ - lua_pushfstring(L, "function " LUA_QS, ar->name); + if (pushglobalfuncname(L, ar)) { /* try first a global name */ + lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); + lua_remove(L, -2); /* remove name */ + } + else if (*ar->namewhat != '\0') /* is there a name from code? */ + lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ else if (*ar->what == 'm') /* main? */ lua_pushliteral(L, "main chunk"); - else if (*ar->what == 'C') { - if (pushglobalfuncname(L, ar)) { - lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); - lua_remove(L, -2); /* remove name */ - } - else - lua_pushliteral(L, "?"); - } - else + else if (*ar->what != 'C') /* for Lua functions, use */ lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); + else /* nothing left... */ + lua_pushliteral(L, "?"); } -static int countlevels (lua_State *L) { +static int lastlevel (lua_State *L) { lua_Debug ar; int li = 1, le = 1; /* find an upper bound */ @@ -117,14 +127,16 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level) { lua_Debug ar; int top = lua_gettop(L); - int numlevels = countlevels(L1); - int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0; - if (msg) lua_pushfstring(L, "%s\n", msg); + int last = lastlevel(L1); + int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; + if (msg) + lua_pushfstring(L, "%s\n", msg); + luaL_checkstack(L, 10, NULL); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { - if (level == mark) { /* too many levels? */ + if (n1-- == 0) { /* too many levels? */ lua_pushliteral(L, "\n\t..."); /* add a '...' */ - level = numlevels - LEVELS2; /* and skip to last ones */ + level = last - LEVELS2 + 1; /* and skip to last ones */ } else { lua_getinfo(L1, "Slnt", &ar); @@ -150,36 +162,47 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, ** ======================================================= */ -LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { +LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { lua_Debug ar; if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ - return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); + return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); lua_getinfo(L, "n", &ar); if (strcmp(ar.namewhat, "method") == 0) { - narg--; /* do not count `self' */ - if (narg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling " LUA_QS " on bad self (%s)", + arg--; /* do not count 'self' */ + if (arg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling '%s' on bad self (%s)", ar.name, extramsg); } if (ar.name == NULL) ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; - return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)", - narg, ar.name, extramsg); + return luaL_error(L, "bad argument #%d to '%s' (%s)", + arg, ar.name, extramsg); } -static int typeerror (lua_State *L, int narg, const char *tname) { - const char *msg = lua_pushfstring(L, "%s expected, got %s", - tname, luaL_typename(L, narg)); - return luaL_argerror(L, narg, msg); +static int typeerror (lua_State *L, int arg, const char *tname) { + const char *msg; + const char *typearg; /* name for the type of the actual argument */ + if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) + typearg = lua_tostring(L, -1); /* use the given type name */ + else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) + typearg = "light userdata"; /* special name for messages */ + else + typearg = luaL_typename(L, arg); /* standard name */ + msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); + return luaL_argerror(L, arg, msg); } -static void tag_error (lua_State *L, int narg, int tag) { - typeerror(L, narg, lua_typename(L, tag)); +static void tag_error (lua_State *L, int arg, int tag) { + typeerror(L, arg, lua_typename(L, tag)); } +/* +** The use of 'lua_pushfstring' ensures this function does not +** need reserved stack space when called. +*/ LUALIB_API void luaL_where (lua_State *L, int level) { lua_Debug ar; if (lua_getstack(L, level, &ar)) { /* check function at level */ @@ -189,10 +212,15 @@ LUALIB_API void luaL_where (lua_State *L, int level) { return; } } - lua_pushliteral(L, ""); /* else, no information available... */ + lua_pushfstring(L, ""); /* else, no information available... */ } +/* +** Again, the use of 'lua_pushvfstring' ensures this function does +** not need reserved stack space when called. (At worst, it generates +** an error with "stack overflow" instead of the given message.) +*/ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); @@ -222,7 +250,7 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { } -#if !defined(inspectstat) /* { */ +#if !defined(l_inspectstat) /* { */ #if defined(LUA_USE_POSIX) @@ -231,13 +259,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { /* ** use appropriate macros to interpret 'pclose' return status */ -#define inspectstat(stat,what) \ +#define l_inspectstat(stat,what) \ if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } #else -#define inspectstat(stat,what) /* no op */ +#define l_inspectstat(stat,what) /* no op */ #endif @@ -249,7 +277,7 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) { if (stat == -1) /* error? */ return luaL_fileresult(L, 0, NULL); else { - inspectstat(stat, what); /* interpret result */ + l_inspectstat(stat, what); /* interpret result */ if (*what == 'e' && stat == 0) /* successful termination? */ lua_pushboolean(L, 1); else @@ -270,11 +298,12 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) { */ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { - luaL_getmetatable(L, tname); /* try to get metatable */ - if (!lua_isnil(L, -1)) /* name already in use? */ + if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); - lua_newtable(L); /* create metatable */ + lua_createtable(L, 0, 2); /* create metatable */ + lua_pushstring(L, tname); + lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ return 1; @@ -317,23 +346,28 @@ LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { ** ======================================================= */ -LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, +LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, const char *const lst[]) { - const char *name = (def) ? luaL_optstring(L, narg, def) : - luaL_checkstring(L, narg); + const char *name = (def) ? luaL_optstring(L, arg, def) : + luaL_checkstring(L, arg); int i; for (i=0; lst[i]; i++) if (strcmp(lst[i], name) == 0) return i; - return luaL_argerror(L, narg, - lua_pushfstring(L, "invalid option " LUA_QS, name)); + return luaL_argerror(L, arg, + lua_pushfstring(L, "invalid option '%s'", name)); } +/* +** Ensures the stack has at least 'space' extra slots, raising an error +** if it cannot fulfill the request. (The error handling needs a few +** extra slots to format the error message. In case of an error without +** this extra space, Lua will generate the same 'stack overflow' error, +** but without 'msg'.) +*/ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { - /* keep some extra space to run error routines, if needed */ - const int extra = LUA_MINSTACK; - if (!lua_checkstack(L, space + extra)) { + if (!lua_checkstack(L, space)) { if (msg) luaL_error(L, "stack overflow (%s)", msg); else @@ -342,77 +376,71 @@ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { } -LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) { - if (lua_type(L, narg) != t) - tag_error(L, narg, t); +LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { + if (lua_type(L, arg) != t) + tag_error(L, arg, t); } -LUALIB_API void luaL_checkany (lua_State *L, int narg) { - if (lua_type(L, narg) == LUA_TNONE) - luaL_argerror(L, narg, "value expected"); +LUALIB_API void luaL_checkany (lua_State *L, int arg) { + if (lua_type(L, arg) == LUA_TNONE) + luaL_argerror(L, arg, "value expected"); } -LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) { - const char *s = lua_tolstring(L, narg, len); - if (!s) tag_error(L, narg, LUA_TSTRING); +LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { + const char *s = lua_tolstring(L, arg, len); + if (!s) tag_error(L, arg, LUA_TSTRING); return s; } -LUALIB_API const char *luaL_optlstring (lua_State *L, int narg, +LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, const char *def, size_t *len) { - if (lua_isnoneornil(L, narg)) { + if (lua_isnoneornil(L, arg)) { if (len) *len = (def ? strlen(def) : 0); return def; } - else return luaL_checklstring(L, narg, len); + else return luaL_checklstring(L, arg, len); } -LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) { +LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { int isnum; - lua_Number d = lua_tonumberx(L, narg, &isnum); + lua_Number d = lua_tonumberx(L, arg, &isnum); if (!isnum) - tag_error(L, narg, LUA_TNUMBER); + tag_error(L, arg, LUA_TNUMBER); return d; } -LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) { - return luaL_opt(L, luaL_checknumber, narg, def); +LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { + return luaL_opt(L, luaL_checknumber, arg, def); } -LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) { - int isnum; - lua_Integer d = lua_tointegerx(L, narg, &isnum); - if (!isnum) - tag_error(L, narg, LUA_TNUMBER); - return d; +static void interror (lua_State *L, int arg) { + if (lua_isnumber(L, arg)) + luaL_argerror(L, arg, "number has no integer representation"); + else + tag_error(L, arg, LUA_TNUMBER); } -LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) { +LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { int isnum; - lua_Unsigned d = lua_tounsignedx(L, narg, &isnum); - if (!isnum) - tag_error(L, narg, LUA_TNUMBER); + lua_Integer d = lua_tointegerx(L, arg, &isnum); + if (!isnum) { + interror(L, arg); + } return d; } -LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, +LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, lua_Integer def) { - return luaL_opt(L, luaL_checkinteger, narg, def); -} - - -LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg, - lua_Unsigned def) { - return luaL_opt(L, luaL_checkunsigned, narg, def); + return luaL_opt(L, luaL_checkinteger, arg, def); } /* }====================================================== */ @@ -424,6 +452,47 @@ LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg, ** ======================================================= */ +/* userdata to box arbitrary data */ +typedef struct UBox { + void *box; + size_t bsize; +} UBox; + + +static void *resizebox (lua_State *L, int idx, size_t newsize) { + void *ud; + lua_Alloc allocf = lua_getallocf(L, &ud); + UBox *box = (UBox *)lua_touserdata(L, idx); + void *temp = allocf(ud, box->box, box->bsize, newsize); + if (temp == NULL && newsize > 0) { /* allocation error? */ + resizebox(L, idx, 0); /* free buffer */ + luaL_error(L, "not enough memory for buffer allocation"); + } + box->box = temp; + box->bsize = newsize; + return temp; +} + + +static int boxgc (lua_State *L) { + resizebox(L, 1, 0); + return 0; +} + + +static void *newbox (lua_State *L, size_t newsize) { + UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox)); + box->box = NULL; + box->bsize = 0; + if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */ + lua_pushcfunction(L, boxgc); + lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */ + } + lua_setmetatable(L, -2); + return resizebox(L, -1, newsize); +} + + /* ** check whether buffer is using a userdata on the stack as a temporary ** buffer @@ -444,11 +513,12 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { if (newsize < B->n || newsize - B->n < sz) luaL_error(L, "buffer too large"); /* create larger buffer */ - newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char)); - /* move content to new buffer */ - memcpy(newbuff, B->b, B->n * sizeof(char)); if (buffonstack(B)) - lua_remove(L, -2); /* remove old buffer */ + newbuff = (char *)resizebox(L, -1, newsize); + else { /* no buffer yet */ + newbuff = (char *)newbox(L, newsize); + memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ + } B->b = newbuff; B->size = newsize; } @@ -457,9 +527,11 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - char *b = luaL_prepbuffsize(B, l); - memcpy(b, s, l * sizeof(char)); - luaL_addsize(B, l); + if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ + char *b = luaL_prepbuffsize(B, l); + memcpy(b, s, l * sizeof(char)); + luaL_addsize(B, l); + } } @@ -471,8 +543,10 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { LUALIB_API void luaL_pushresult (luaL_Buffer *B) { lua_State *L = B->L; lua_pushlstring(L, B->b, B->n); - if (buffonstack(B)) - lua_remove(L, -2); /* remove old buffer */ + if (buffonstack(B)) { + resizebox(L, -2, 0); /* delete old buffer */ + lua_remove(L, -2); /* remove its header from the stack */ + } } @@ -523,7 +597,7 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; if (lua_isnil(L, -1)) { lua_pop(L, 1); /* remove from stack */ - return LUA_REFNIL; /* `nil' has a unique fixed reference */ + return LUA_REFNIL; /* 'nil' has a unique fixed reference */ } t = lua_absindex(L, t); lua_rawgeti(L, t, freelist); /* get first free element */ @@ -562,7 +636,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { typedef struct LoadF { int n; /* number of pre-read characters */ FILE *f; /* file being read */ - char buff[LUAL_BUFFERSIZE]; /* area for reading file */ + char buff[BUFSIZ]; /* area for reading file */ } LoadF; @@ -594,7 +668,7 @@ static int errfile (lua_State *L, const char *what, int fnameindex) { static int skipBOM (LoadF *lf) { - const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */ + const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ int c; lf->n = 0; do { @@ -619,7 +693,7 @@ static int skipcomment (LoadF *lf, int *cp) { if (c == '#') { /* first line is a comment (Unix exec. file)? */ do { /* skip first line */ c = getc(lf->f); - } while (c != EOF && c != '\n') ; + } while (c != EOF && c != '\n'); *cp = getc(lf->f); /* skip end-of-line, if present */ return 1; /* there was a comment */ } @@ -655,7 +729,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { - lua_settop(L, fnameindex); /* ignore results from `lua_load' */ + lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ return errfile(L, "read", fnameindex); } lua_remove(L, fnameindex); @@ -698,23 +772,23 @@ LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ - return 0; - lua_pushstring(L, event); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { - lua_pop(L, 2); /* remove metatable and metafield */ - return 0; - } + return LUA_TNIL; else { - lua_remove(L, -2); /* remove only metatable */ - return 1; + int tt; + lua_pushstring(L, event); + tt = lua_rawget(L, -2); + if (tt == LUA_TNIL) /* is metafield nil? */ + lua_pop(L, 2); /* remove metatable and metafield */ + else + lua_remove(L, -2); /* remove only metatable */ + return tt; /* return metafield type */ } } LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { obj = lua_absindex(L, obj); - if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ + if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ return 0; lua_pushvalue(L, obj); lua_call(L, 1, 1); @@ -722,13 +796,13 @@ LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { } -LUALIB_API int luaL_len (lua_State *L, int idx) { - int l; +LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { + lua_Integer l; int isnum; lua_len(L, idx); - l = (int)lua_tointegerx(L, -1, &isnum); + l = lua_tointegerx(L, -1, &isnum); if (!isnum) - luaL_error(L, "object length is not a number"); + luaL_error(L, "object length is not an integer"); lua_pop(L, 1); /* remove object */ return l; } @@ -737,7 +811,13 @@ LUALIB_API int luaL_len (lua_State *L, int idx) { LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ switch (lua_type(L, idx)) { - case LUA_TNUMBER: + case LUA_TNUMBER: { + if (lua_isinteger(L, idx)) + lua_pushfstring(L, "%I", lua_tointeger(L, idx)); + else + lua_pushfstring(L, "%f", lua_tonumber(L, idx)); + break; + } case LUA_TSTRING: lua_pushvalue(L, idx); break; @@ -772,8 +852,7 @@ static const char *luaL_findtable (lua_State *L, int idx, e = strchr(fname, '.'); if (e == NULL) e = fname + strlen(fname); lua_pushlstring(L, fname, e - fname); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { /* no such field? */ + if (lua_rawget(L, -2) == LUA_TNIL) { /* no such field? */ lua_pop(L, 1); /* remove this nil */ lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ lua_pushlstring(L, fname, e - fname); @@ -810,13 +889,12 @@ static int libsize (const luaL_Reg *l) { LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname, int sizehint) { luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */ - lua_getfield(L, -1, modname); /* get _LOADED[modname] */ - if (!lua_istable(L, -1)) { /* not found? */ + if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ lua_pushglobaltable(L); if (luaL_findtable(L, 0, modname, sizehint) != NULL) - luaL_error(L, "name conflict for module " LUA_QS, modname); + luaL_error(L, "name conflict for module '%s'", modname); lua_pushvalue(L, -1); lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */ } @@ -846,7 +924,6 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, ** Returns with only the table at the stack. */ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { - luaL_checkversion(L); luaL_checkstack(L, nup, "too many upvalues"); for (; l->name != NULL; l++) { /* fill the table with given functions */ int i; @@ -864,8 +941,8 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { ** into the stack */ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { - lua_getfield(L, idx, fname); - if (lua_istable(L, -1)) return 1; /* table already there */ + if (lua_getfield(L, idx, fname) == LUA_TTABLE) + return 1; /* table already there */ else { lua_pop(L, 1); /* remove previous result */ idx = lua_absindex(L, idx); @@ -878,22 +955,26 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { /* -** stripped-down 'require'. Calls 'openf' to open a module, -** registers the result in 'package.loaded' table and, if 'glb' -** is true, also registers the result in the global table. +** Stripped-down 'require': After checking "loaded" table, calls 'openf' +** to open a module, registers the result in 'package.loaded' table and, +** if 'glb' is true, also registers the result in the global table. ** Leaves resulting module on the top. */ LUALIB_API void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb) { - lua_pushcfunction(L, openf); - lua_pushstring(L, modname); /* argument to open function */ - lua_call(L, 1, 1); /* open module */ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_pushvalue(L, -2); /* make copy of module (call result) */ - lua_setfield(L, -2, modname); /* _LOADED[modname] = module */ - lua_pop(L, 1); /* remove _LOADED table */ + lua_getfield(L, -1, modname); /* _LOADED[modname] */ + if (!lua_toboolean(L, -1)) { /* package not already loaded? */ + lua_pop(L, 1); /* remove field */ + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); /* argument to open function */ + lua_call(L, 1, 1); /* call 'openf' to open module */ + lua_pushvalue(L, -1); /* make copy of module (call result) */ + lua_setfield(L, -3, modname); /* _LOADED[modname] = module */ + } + lua_remove(L, -2); /* remove _LOADED table */ if (glb) { - lua_pushvalue(L, -1); /* copy of 'mod' */ + lua_pushvalue(L, -1); /* copy of module */ lua_setglobal(L, modname); /* _G[modname] = module */ } } @@ -908,7 +989,7 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, while ((wild = strstr(s, p)) != NULL) { luaL_addlstring(&b, s, wild - s); /* push prefix */ luaL_addstring(&b, r); /* push replacement in place of pattern */ - s = wild + l; /* continue after `p' */ + s = wild + l; /* continue after 'p' */ } luaL_addstring(&b, s); /* push last suffix */ luaL_pushresult(&b); @@ -928,8 +1009,8 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { static int panic (lua_State *L) { - luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", - lua_tostring(L, -1)); + lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); return 0; /* return to Lua to abort */ } @@ -941,19 +1022,14 @@ LUALIB_API lua_State *luaL_newstate (void) { } -LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) { +LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { const lua_Number *v = lua_version(L); + if (sz != LUAL_NUMSIZES) /* check numeric types */ + luaL_error(L, "core and library have incompatible numeric types"); if (v != lua_version(NULL)) luaL_error(L, "multiple Lua VMs detected"); else if (*v != ver) luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", ver, *v); - /* check conversions number -> integer types */ - lua_pushnumber(L, -(lua_Number)0x1234); - if (lua_tointeger(L, -1) != -0x1234 || - lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234) - luaL_error(L, "bad conversion number->int;" - " must recompile Lua with proper settings"); - lua_pop(L, 1); } diff --git a/depends/lua/src/lbaselib.c b/depends/lua/src/lbaselib.c index 5255b3cd9..d481c4e1e 100644 --- a/depends/lua/src/lbaselib.c +++ b/depends/lua/src/lbaselib.c @@ -1,9 +1,13 @@ /* -** $Id: lbaselib.c,v 1.276.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lbaselib.c,v 1.313 2016/04/11 19:18:40 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ +#define lbaselib_c +#define LUA_LIB + +#include "lprefix.h" #include @@ -11,9 +15,6 @@ #include #include -#define lbaselib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -32,65 +33,77 @@ static int luaB_print (lua_State *L) { lua_call(L, 1, 1); s = lua_tolstring(L, -1, &l); /* get result */ if (s == NULL) - return luaL_error(L, - LUA_QL("tostring") " must return a string to " LUA_QL("print")); - if (i>1) luai_writestring("\t", 1); - luai_writestring(s, l); + return luaL_error(L, "'tostring' must return a string to 'print'"); + if (i>1) lua_writestring("\t", 1); + lua_writestring(s, l); lua_pop(L, 1); /* pop result */ } - luai_writeline(); + lua_writeline(); return 0; } #define SPACECHARS " \f\n\r\t\v" +static const char *b_str2int (const char *s, int base, lua_Integer *pn) { + lua_Unsigned n = 0; + int neg = 0; + s += strspn(s, SPACECHARS); /* skip initial spaces */ + if (*s == '-') { s++; neg = 1; } /* handle signal */ + else if (*s == '+') s++; + if (!isalnum((unsigned char)*s)) /* no digit? */ + return NULL; + do { + int digit = (isdigit((unsigned char)*s)) ? *s - '0' + : (toupper((unsigned char)*s) - 'A') + 10; + if (digit >= base) return NULL; /* invalid numeral */ + n = n * base + digit; + s++; + } while (isalnum((unsigned char)*s)); + s += strspn(s, SPACECHARS); /* skip trailing spaces */ + *pn = (lua_Integer)((neg) ? (0u - n) : n); + return s; +} + + static int luaB_tonumber (lua_State *L) { - if (lua_isnoneornil(L, 2)) { /* standard conversion */ - int isnum; - lua_Number n = lua_tonumberx(L, 1, &isnum); - if (isnum) { - lua_pushnumber(L, n); - return 1; - } /* else not a number; must be something */ + if (lua_isnoneornil(L, 2)) { /* standard conversion? */ luaL_checkany(L, 1); + if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ + lua_settop(L, 1); /* yes; return it */ + return 1; + } + else { + size_t l; + const char *s = lua_tolstring(L, 1, &l); + if (s != NULL && lua_stringtonumber(L, s) == l + 1) + return 1; /* successful conversion to number */ + /* else not a number */ + } } else { size_t l; - const char *s = luaL_checklstring(L, 1, &l); - const char *e = s + l; /* end point for 's' */ - int base = luaL_checkint(L, 2); - int neg = 0; + const char *s; + lua_Integer n = 0; /* to avoid warnings */ + lua_Integer base = luaL_checkinteger(L, 2); + luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ + s = lua_tolstring(L, 1, &l); luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); - s += strspn(s, SPACECHARS); /* skip initial spaces */ - if (*s == '-') { s++; neg = 1; } /* handle signal */ - else if (*s == '+') s++; - if (isalnum((unsigned char)*s)) { - lua_Number n = 0; - do { - int digit = (isdigit((unsigned char)*s)) ? *s - '0' - : toupper((unsigned char)*s) - 'A' + 10; - if (digit >= base) break; /* invalid numeral; force a fail */ - n = n * (lua_Number)base + (lua_Number)digit; - s++; - } while (isalnum((unsigned char)*s)); - s += strspn(s, SPACECHARS); /* skip trailing spaces */ - if (s == e) { /* no invalid trailing characters? */ - lua_pushnumber(L, (neg) ? -n : n); - return 1; - } /* else not a number */ + if (b_str2int(s, (int)base, &n) == s + l) { + lua_pushinteger(L, n); + return 1; } /* else not a number */ - } + } /* else not a number */ lua_pushnil(L); /* not a number */ return 1; } static int luaB_error (lua_State *L) { - int level = luaL_optint(L, 2, 1); + int level = (int)luaL_optinteger(L, 2, 1); lua_settop(L, 1); - if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ - luaL_where(L, level); + if (lua_type(L, 1) == LUA_TSTRING && level > 0) { + luaL_where(L, level); /* add extra information */ lua_pushvalue(L, 1); lua_concat(L, 2); } @@ -114,7 +127,7 @@ static int luaB_setmetatable (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); - if (luaL_getmetafield(L, 1, "__metatable")) + if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) return luaL_error(L, "cannot change a protected metatable"); lua_settop(L, 2); lua_setmetatable(L, 1); @@ -160,19 +173,18 @@ static int luaB_rawset (lua_State *L) { static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", "count", "step", "setpause", "setstepmul", - "setmajorinc", "isrunning", "generational", "incremental", NULL}; + "isrunning", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, - LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC}; + LUA_GCISRUNNING}; int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; - int ex = luaL_optint(L, 2, 0); + int ex = (int)luaL_optinteger(L, 2, 0); int res = lua_gc(L, o, ex); switch (o) { case LUA_GCCOUNT: { int b = lua_gc(L, LUA_GCCOUNTB, 0); - lua_pushnumber(L, res + ((lua_Number)b/1024)); - lua_pushinteger(L, b); - return 2; + lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); + return 1; } case LUA_GCSTEP: case LUA_GCISRUNNING: { lua_pushboolean(L, res); @@ -187,15 +199,16 @@ static int luaB_collectgarbage (lua_State *L) { static int luaB_type (lua_State *L) { - luaL_checkany(L, 1); - lua_pushstring(L, luaL_typename(L, 1)); + int t = lua_type(L, 1); + luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); + lua_pushstring(L, lua_typename(L, t)); return 1; } static int pairsmeta (lua_State *L, const char *method, int iszero, lua_CFunction iter) { - if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */ + if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */ luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ lua_pushcfunction(L, iter); /* will return generator, */ lua_pushvalue(L, 1); /* state, */ @@ -227,18 +240,30 @@ static int luaB_pairs (lua_State *L) { } +/* +** Traversal function for 'ipairs' +*/ static int ipairsaux (lua_State *L) { - int i = luaL_checkint(L, 2); - luaL_checktype(L, 1, LUA_TTABLE); - i++; /* next value */ + lua_Integer i = luaL_checkinteger(L, 2) + 1; lua_pushinteger(L, i); - lua_rawgeti(L, 1, i); - return (lua_isnil(L, -1)) ? 1 : 2; + return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; } +/* +** 'ipairs' function. Returns 'ipairsaux', given "table", 0. +** (The given "table" may not be a table.) +*/ static int luaB_ipairs (lua_State *L) { +#if defined(LUA_COMPAT_IPAIRS) return pairsmeta(L, "__ipairs", 1, ipairsaux); +#else + luaL_checkany(L, 1); + lua_pushcfunction(L, ipairsaux); /* iteration function */ + lua_pushvalue(L, 1); /* state */ + lua_pushinteger(L, 0); /* initial value */ + return 3; +#endif } @@ -284,7 +309,7 @@ static int luaB_loadfile (lua_State *L) { /* -** Reader for generic `load' function: `lua_load' uses the +** Reader for generic 'load' function: 'lua_load' uses the ** stack for internal stuff, so the reader cannot change the ** stack top. Instead, it keeps its resulting string in a ** reserved slot inside the stack. @@ -328,7 +353,8 @@ static int luaB_load (lua_State *L) { /* }====================================================== */ -static int dofilecont (lua_State *L) { +static int dofilecont (lua_State *L, int d1, lua_KContext d2) { + (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ return lua_gettop(L) - 1; } @@ -339,14 +365,20 @@ static int luaB_dofile (lua_State *L) { if (luaL_loadfile(L, fname) != LUA_OK) return lua_error(L); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); - return dofilecont(L); + return dofilecont(L, 0, 0); } static int luaB_assert (lua_State *L) { - if (!lua_toboolean(L, 1)) - return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); - return lua_gettop(L); + if (lua_toboolean(L, 1)) /* condition is true? */ + return lua_gettop(L); /* return all arguments */ + else { /* error */ + luaL_checkany(L, 1); /* there must be a condition */ + lua_remove(L, 1); /* remove it */ + lua_pushliteral(L, "assertion failed!"); /* default message */ + lua_settop(L, 1); /* leave only message (default if no other one) */ + return luaB_error(L); /* call 'error' */ + } } @@ -357,53 +389,57 @@ static int luaB_select (lua_State *L) { return 1; } else { - int i = luaL_checkint(L, 1); + lua_Integer i = luaL_checkinteger(L, 1); if (i < 0) i = n + i; else if (i > n) i = n; luaL_argcheck(L, 1 <= i, 1, "index out of range"); - return n - i; + return n - (int)i; } } -static int finishpcall (lua_State *L, int status) { - if (!lua_checkstack(L, 1)) { /* no space for extra boolean? */ - lua_settop(L, 0); /* create space for return values */ - lua_pushboolean(L, 0); - lua_pushstring(L, "stack overflow"); +/* +** Continuation function for 'pcall' and 'xpcall'. Both functions +** already pushed a 'true' before doing the call, so in case of success +** 'finishpcall' only has to return everything in the stack minus +** 'extra' values (where 'extra' is exactly the number of items to be +** ignored). +*/ +static int finishpcall (lua_State *L, int status, lua_KContext extra) { + if (status != LUA_OK && status != LUA_YIELD) { /* error? */ + lua_pushboolean(L, 0); /* first result (false) */ + lua_pushvalue(L, -2); /* error message */ return 2; /* return false, msg */ } - lua_pushboolean(L, status); /* first result (status) */ - lua_replace(L, 1); /* put first result in first slot */ - return lua_gettop(L); -} - - -static int pcallcont (lua_State *L) { - int status = lua_getctx(L, NULL); - return finishpcall(L, (status == LUA_YIELD)); + else + return lua_gettop(L) - (int)extra; /* return all results */ } static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); - lua_pushnil(L); - lua_insert(L, 1); /* create space for status result */ - status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont); - return finishpcall(L, (status == LUA_OK)); + lua_pushboolean(L, 1); /* first result if no errors */ + lua_insert(L, 1); /* put it in place */ + status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); + return finishpcall(L, status, 0); } +/* +** Do a protected call with error handling. After 'lua_rotate', the +** stack will have ; so, the function passes +** 2 to 'finishpcall' to skip the 2 first values when returning results. +*/ static int luaB_xpcall (lua_State *L) { int status; int n = lua_gettop(L); - luaL_argcheck(L, n >= 2, 2, "value expected"); - lua_pushvalue(L, 1); /* exchange function... */ - lua_copy(L, 2, 1); /* ...and error handler */ - lua_replace(L, 2); - status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont); - return finishpcall(L, (status == LUA_OK)); + luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ + lua_pushboolean(L, 1); /* first result */ + lua_pushvalue(L, 1); /* function */ + lua_rotate(L, 3, 2); /* move them below function's arguments */ + status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); + return finishpcall(L, status, 2); } @@ -440,19 +476,23 @@ static const luaL_Reg base_funcs[] = { {"tostring", luaB_tostring}, {"type", luaB_type}, {"xpcall", luaB_xpcall}, + /* placeholders */ + {"_G", NULL}, + {"_VERSION", NULL}, {NULL, NULL} }; LUAMOD_API int luaopen_base (lua_State *L) { - /* set global _G */ - lua_pushglobaltable(L); - lua_pushglobaltable(L); - lua_setfield(L, -2, "_G"); /* open lib into global table */ + lua_pushglobaltable(L); luaL_setfuncs(L, base_funcs, 0); + /* set global _G */ + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_G"); + /* set global _VERSION */ lua_pushliteral(L, LUA_VERSION); - lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */ + lua_setfield(L, -2, "_VERSION"); return 1; } diff --git a/depends/lua/src/lbitlib.c b/depends/lua/src/lbitlib.c index 31c7b66f1..1cb1d5b93 100644 --- a/depends/lua/src/lbitlib.c +++ b/depends/lua/src/lbitlib.c @@ -1,5 +1,5 @@ /* -** $Id: lbitlib.c,v 1.18.1.2 2013/07/09 18:01:41 roberto Exp $ +** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ @@ -7,20 +7,36 @@ #define lbitlib_c #define LUA_LIB +#include "lprefix.h" + + #include "lua.h" #include "lauxlib.h" #include "lualib.h" +#if defined(LUA_COMPAT_BITLIB) /* { */ + + +#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) +#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i)) + + /* number of bits to consider in a number */ #if !defined(LUA_NBITS) #define LUA_NBITS 32 #endif +/* +** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must +** be made in two parts to avoid problems when LUA_NBITS is equal to the +** number of bits in a lua_Unsigned.) +*/ #define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) + /* macro to trim extra bits */ #define trim(x) ((x) & ALLONES) @@ -29,28 +45,25 @@ #define mask(n) (~((ALLONES << 1) << ((n) - 1))) -typedef lua_Unsigned b_uint; - - -static b_uint andaux (lua_State *L) { +static lua_Unsigned andaux (lua_State *L) { int i, n = lua_gettop(L); - b_uint r = ~(b_uint)0; + lua_Unsigned r = ~(lua_Unsigned)0; for (i = 1; i <= n; i++) - r &= luaL_checkunsigned(L, i); + r &= checkunsigned(L, i); return trim(r); } static int b_and (lua_State *L) { - b_uint r = andaux(L); - lua_pushunsigned(L, r); + lua_Unsigned r = andaux(L); + pushunsigned(L, r); return 1; } static int b_test (lua_State *L) { - b_uint r = andaux(L); + lua_Unsigned r = andaux(L); lua_pushboolean(L, r != 0); return 1; } @@ -58,32 +71,32 @@ static int b_test (lua_State *L) { static int b_or (lua_State *L) { int i, n = lua_gettop(L); - b_uint r = 0; + lua_Unsigned r = 0; for (i = 1; i <= n; i++) - r |= luaL_checkunsigned(L, i); - lua_pushunsigned(L, trim(r)); + r |= checkunsigned(L, i); + pushunsigned(L, trim(r)); return 1; } static int b_xor (lua_State *L) { int i, n = lua_gettop(L); - b_uint r = 0; + lua_Unsigned r = 0; for (i = 1; i <= n; i++) - r ^= luaL_checkunsigned(L, i); - lua_pushunsigned(L, trim(r)); + r ^= checkunsigned(L, i); + pushunsigned(L, trim(r)); return 1; } static int b_not (lua_State *L) { - b_uint r = ~luaL_checkunsigned(L, 1); - lua_pushunsigned(L, trim(r)); + lua_Unsigned r = ~checkunsigned(L, 1); + pushunsigned(L, trim(r)); return 1; } -static int b_shift (lua_State *L, b_uint r, int i) { +static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { if (i < 0) { /* shift right? */ i = -i; r = trim(r); @@ -95,54 +108,54 @@ static int b_shift (lua_State *L, b_uint r, int i) { else r <<= i; r = trim(r); } - lua_pushunsigned(L, r); + pushunsigned(L, r); return 1; } static int b_lshift (lua_State *L) { - return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2)); + return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); } static int b_rshift (lua_State *L) { - return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2)); + return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); } static int b_arshift (lua_State *L) { - b_uint r = luaL_checkunsigned(L, 1); - int i = luaL_checkint(L, 2); - if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1)))) + lua_Unsigned r = checkunsigned(L, 1); + lua_Integer i = luaL_checkinteger(L, 2); + if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) return b_shift(L, r, -i); else { /* arithmetic shift for 'negative' number */ if (i >= LUA_NBITS) r = ALLONES; else - r = trim((r >> i) | ~(~(b_uint)0 >> i)); /* add signal bit */ - lua_pushunsigned(L, r); + r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ + pushunsigned(L, r); return 1; } } -static int b_rot (lua_State *L, int i) { - b_uint r = luaL_checkunsigned(L, 1); - i &= (LUA_NBITS - 1); /* i = i % NBITS */ +static int b_rot (lua_State *L, lua_Integer d) { + lua_Unsigned r = checkunsigned(L, 1); + int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ r = trim(r); if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ r = (r << i) | (r >> (LUA_NBITS - i)); - lua_pushunsigned(L, trim(r)); + pushunsigned(L, trim(r)); return 1; } static int b_lrot (lua_State *L) { - return b_rot(L, luaL_checkint(L, 2)); + return b_rot(L, luaL_checkinteger(L, 2)); } static int b_rrot (lua_State *L) { - return b_rot(L, -luaL_checkint(L, 2)); + return b_rot(L, -luaL_checkinteger(L, 2)); } @@ -153,36 +166,35 @@ static int b_rrot (lua_State *L) { ** 'width' being used uninitialized.) */ static int fieldargs (lua_State *L, int farg, int *width) { - int f = luaL_checkint(L, farg); - int w = luaL_optint(L, farg + 1, 1); + lua_Integer f = luaL_checkinteger(L, farg); + lua_Integer w = luaL_optinteger(L, farg + 1, 1); luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); if (f + w > LUA_NBITS) luaL_error(L, "trying to access non-existent bits"); - *width = w; - return f; + *width = (int)w; + return (int)f; } static int b_extract (lua_State *L) { int w; - b_uint r = luaL_checkunsigned(L, 1); + lua_Unsigned r = trim(checkunsigned(L, 1)); int f = fieldargs(L, 2, &w); r = (r >> f) & mask(w); - lua_pushunsigned(L, r); + pushunsigned(L, r); return 1; } static int b_replace (lua_State *L) { int w; - b_uint r = luaL_checkunsigned(L, 1); - b_uint v = luaL_checkunsigned(L, 2); + lua_Unsigned r = trim(checkunsigned(L, 1)); + lua_Unsigned v = trim(checkunsigned(L, 2)); int f = fieldargs(L, 3, &w); - int m = mask(w); - v &= m; /* erase bits outside given width */ - r = (r & ~(m << f)) | (v << f); - lua_pushunsigned(L, r); + lua_Unsigned m = mask(w); + r = (r & ~(m << f)) | ((v & m) << f); + pushunsigned(L, r); return 1; } @@ -210,3 +222,12 @@ LUAMOD_API int luaopen_bit32 (lua_State *L) { return 1; } + +#else /* }{ */ + + +LUAMOD_API int luaopen_bit32 (lua_State *L) { + return luaL_error(L, "library 'bit32' has been deprecated"); +} + +#endif /* } */ diff --git a/depends/lua/src/lcode.c b/depends/lua/src/lcode.c index 820b95c0e..2cd0dd2d5 100644 --- a/depends/lua/src/lcode.c +++ b/depends/lua/src/lcode.c @@ -1,15 +1,18 @@ /* -** $Id: lcode.c,v 2.62.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lcode.c,v 2.109 2016/05/13 19:09:21 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ - -#include - #define lcode_c #define LUA_CORE +#include "lprefix.h" + + +#include +#include + #include "lua.h" #include "lcode.h" @@ -26,21 +29,45 @@ #include "lvm.h" +/* Maximum number of registers in a Lua function (must fit in 8 bits) */ +#define MAXREGS 255 + + #define hasjumps(e) ((e)->t != (e)->f) -static int isnumeral(expdesc *e) { - return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); +/* +** If expression is a numeric constant, fills 'v' with its value +** and returns 1. Otherwise, returns 0. +*/ +static int tonumeral(expdesc *e, TValue *v) { + if (hasjumps(e)) + return 0; /* not a numeral */ + switch (e->k) { + case VKINT: + if (v) setivalue(v, e->u.ival); + return 1; + case VKFLT: + if (v) setfltvalue(v, e->u.nval); + return 1; + default: return 0; + } } +/* +** Create a OP_LOADNIL instruction, but try to optimize: if the previous +** instruction is also OP_LOADNIL and ranges are compatible, adjust +** range of previous instruction instead of emitting a new one. (For +** instance, 'local a; local b' will generate a single opcode.) +*/ void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; int l = from + n - 1; /* last register to set nil */ if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ previous = &fs->f->code[fs->pc-1]; - if (GET_OPCODE(*previous) == OP_LOADNIL) { - int pfrom = GETARG_A(*previous); + if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ + int pfrom = GETARG_A(*previous); /* get previous range */ int pl = pfrom + GETARG_B(*previous); if ((pfrom <= from && from <= pl + 1) || (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ @@ -56,39 +83,86 @@ void luaK_nil (FuncState *fs, int from, int n) { } +/* +** Gets the destination address of a jump instruction. Used to traverse +** a list of jumps. +*/ +static int getjump (FuncState *fs, int pc) { + int offset = GETARG_sBx(fs->f->code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ +} + + +/* +** Fix jump instruction at position 'pc' to jump to 'dest'. +** (Jump addresses are relative in Lua) +*/ +static void fixjump (FuncState *fs, int pc, int dest) { + Instruction *jmp = &fs->f->code[pc]; + int offset = dest - (pc + 1); + lua_assert(dest != NO_JUMP); + if (abs(offset) > MAXARG_sBx) + luaX_syntaxerror(fs->ls, "control structure too long"); + SETARG_sBx(*jmp, offset); +} + + +/* +** Concatenate jump-list 'l2' into jump-list 'l1' +*/ +void luaK_concat (FuncState *fs, int *l1, int l2) { + if (l2 == NO_JUMP) return; /* nothing to concatenate? */ + else if (*l1 == NO_JUMP) /* no original list? */ + *l1 = l2; /* 'l1' points to 'l2' */ + else { + int list = *l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); /* last element links to 'l2' */ + } +} + + +/* +** Create a jump instruction and return its position, so its destination +** can be fixed later (with 'fixjump'). If there are jumps to +** this position (kept in 'jpc'), link them all together so that +** 'patchlistaux' will fix all them directly to the final destination. +*/ int luaK_jump (FuncState *fs) { int jpc = fs->jpc; /* save list of jumps to here */ int j; - fs->jpc = NO_JUMP; + fs->jpc = NO_JUMP; /* no more jumps to here */ j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); luaK_concat(fs, &j, jpc); /* keep them on hold */ return j; } +/* +** Code a 'return' instruction +*/ void luaK_ret (FuncState *fs, int first, int nret) { luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); } +/* +** Code a "conditional jump", that is, a test or comparison opcode +** followed by a jump. Return jump position. +*/ static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); } -static void fixjump (FuncState *fs, int pc, int dest) { - Instruction *jmp = &fs->f->code[pc]; - int offset = dest-(pc+1); - lua_assert(dest != NO_JUMP); - if (abs(offset) > MAXARG_sBx) - luaX_syntaxerror(fs->ls, "control structure too long"); - SETARG_sBx(*jmp, offset); -} - - /* -** returns current `pc' and marks it as a jump target (to avoid wrong +** returns current 'pc' and marks it as a jump target (to avoid wrong ** optimizations with consecutive instructions not in the same basic block). */ int luaK_getlabel (FuncState *fs) { @@ -97,15 +171,11 @@ int luaK_getlabel (FuncState *fs) { } -static int getjump (FuncState *fs, int pc) { - int offset = GETARG_sBx(fs->f->code[pc]); - if (offset == NO_JUMP) /* point to itself represents end of list */ - return NO_JUMP; /* end of list */ - else - return (pc+1)+offset; /* turn offset into absolute position */ -} - - +/* +** Returns the position of the instruction "controlling" a given +** jump (that is, its condition), or the jump itself if it is +** unconditional. +*/ static Instruction *getjumpcontrol (FuncState *fs, int pc) { Instruction *pi = &fs->f->code[pc]; if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) @@ -116,37 +186,41 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) { /* -** check whether list has any jump that do not produce a value -** (or produce an inverted value) +** Patch destination register for a TESTSET instruction. +** If instruction in position 'node' is not a TESTSET, return 0 ("fails"). +** Otherwise, if 'reg' is not 'NO_REG', set it as the destination +** register. Otherwise, change instruction to a simple 'TEST' (produces +** no register value) */ -static int need_value (FuncState *fs, int list) { - for (; list != NO_JUMP; list = getjump(fs, list)) { - Instruction i = *getjumpcontrol(fs, list); - if (GET_OPCODE(i) != OP_TESTSET) return 1; - } - return 0; /* not found */ -} - - static int patchtestreg (FuncState *fs, int node, int reg) { Instruction *i = getjumpcontrol(fs, node); if (GET_OPCODE(*i) != OP_TESTSET) return 0; /* cannot patch other instructions */ if (reg != NO_REG && reg != GETARG_B(*i)) SETARG_A(*i, reg); - else /* no register to put value or register already has the value */ + else { + /* no register to put value or register already has the value; + change instruction to simple test */ *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); - + } return 1; } +/* +** Traverse a list of tests ensuring no one produces a value +*/ static void removevalues (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) patchtestreg(fs, list, NO_REG); } +/* +** Traverse a list of tests, patching their destination address and +** registers: tests producing values jump to 'vtarget' (and put their +** values in 'reg'), other tests jump to 'dtarget'. +*/ static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, int dtarget) { while (list != NO_JUMP) { @@ -160,15 +234,35 @@ static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, } +/* +** Ensure all pending jumps to current position are fixed (jumping +** to current position with no values) and reset list of pending +** jumps +*/ static void dischargejpc (FuncState *fs) { patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } +/* +** Add elements in 'list' to list of pending jumps to "here" +** (current position) +*/ +void luaK_patchtohere (FuncState *fs, int list) { + luaK_getlabel(fs); /* mark "here" as a jump target */ + luaK_concat(fs, &fs->jpc, list); +} + + +/* +** Path all jumps in 'list' to jump to 'target'. +** (The assert means that we cannot fix a jump to a forward address +** because we only know addresses once code is generated.) +*/ void luaK_patchlist (FuncState *fs, int list, int target) { - if (target == fs->pc) - luaK_patchtohere(fs, list); + if (target == fs->pc) /* 'target' is current position? */ + luaK_patchtohere(fs, list); /* add list to pending jumps */ else { lua_assert(target < fs->pc); patchlistaux(fs, list, target, NO_REG, target); @@ -176,42 +270,29 @@ void luaK_patchlist (FuncState *fs, int list, int target) { } -LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level) { +/* +** Path all jumps in 'list' to close upvalues up to given 'level' +** (The assertion checks that jumps either were closing nothing +** or were closing higher levels, from inner blocks.) +*/ +void luaK_patchclose (FuncState *fs, int list, int level) { level++; /* argument is +1 to reserve 0 as non-op */ - while (list != NO_JUMP) { - int next = getjump(fs, list); + for (; list != NO_JUMP; list = getjump(fs, list)) { lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && (GETARG_A(fs->f->code[list]) == 0 || GETARG_A(fs->f->code[list]) >= level)); SETARG_A(fs->f->code[list], level); - list = next; - } -} - - -void luaK_patchtohere (FuncState *fs, int list) { - luaK_getlabel(fs); - luaK_concat(fs, &fs->jpc, list); -} - - -void luaK_concat (FuncState *fs, int *l1, int l2) { - if (l2 == NO_JUMP) return; - else if (*l1 == NO_JUMP) - *l1 = l2; - else { - int list = *l1; - int next; - while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ - list = next; - fixjump(fs, list, l2); } } +/* +** Emit instruction 'i', checking for array sizes and saving also its +** line information. Return 'i' position. +*/ static int luaK_code (FuncState *fs, Instruction i) { Proto *f = fs->f; - dischargejpc(fs); /* `pc' will change */ + dischargejpc(fs); /* 'pc' will change */ /* put new instruction in code array */ luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, MAX_INT, "opcodes"); @@ -224,6 +305,10 @@ static int luaK_code (FuncState *fs, Instruction i) { } +/* +** Format and emit an 'iABC' instruction. (Assertions check consistency +** of parameters versus opcode.) +*/ int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { lua_assert(getOpMode(o) == iABC); lua_assert(getBMode(o) != OpArgN || b == 0); @@ -233,6 +318,9 @@ int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { } +/* +** Format and emit an 'iABx' instruction. +*/ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); lua_assert(getCMode(o) == OpArgN); @@ -241,12 +329,20 @@ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { } +/* +** Emit an "extra argument" instruction (format 'iAx') +*/ static int codeextraarg (FuncState *fs, int a) { lua_assert(a <= MAXARG_Ax); return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); } +/* +** Emit a "load constant" instruction, using either 'OP_LOADK' +** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX' +** instruction with "extra argument". +*/ int luaK_codek (FuncState *fs, int reg, int k) { if (k <= MAXARG_Bx) return luaK_codeABx(fs, OP_LOADK, reg, k); @@ -258,22 +354,35 @@ int luaK_codek (FuncState *fs, int reg, int k) { } +/* +** Check register-stack level, keeping track of its maximum size +** in field 'maxstacksize' +*/ void luaK_checkstack (FuncState *fs, int n) { int newstack = fs->freereg + n; if (newstack > fs->f->maxstacksize) { - if (newstack >= MAXSTACK) - luaX_syntaxerror(fs->ls, "function or expression too complex"); + if (newstack >= MAXREGS) + luaX_syntaxerror(fs->ls, + "function or expression needs too many registers"); fs->f->maxstacksize = cast_byte(newstack); } } +/* +** Reserve 'n' registers in register stack +*/ void luaK_reserveregs (FuncState *fs, int n) { luaK_checkstack(fs, n); fs->freereg += n; } +/* +** Free register 'reg', if it is neither a constant index nor +** a local variable. +) +*/ static void freereg (FuncState *fs, int reg) { if (!ISK(reg) && reg >= fs->nactvar) { fs->freereg--; @@ -282,31 +391,58 @@ static void freereg (FuncState *fs, int reg) { } +/* +** Free register used by expression 'e' (if any) +*/ static void freeexp (FuncState *fs, expdesc *e) { if (e->k == VNONRELOC) freereg(fs, e->u.info); } +/* +** Free registers used by expressions 'e1' and 'e2' (if any) in proper +** order. +*/ +static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { + int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; + int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; + if (r1 > r2) { + freereg(fs, r1); + freereg(fs, r2); + } + else { + freereg(fs, r2); + freereg(fs, r1); + } +} + + +/* +** Add constant 'v' to prototype's list of constants (field 'k'). +** Use scanner's table to cache position of constants in constant list +** and try to reuse constants. Because some values should not be used +** as keys (nil cannot be a key, integer keys can collapse with float +** keys), the caller must provide a useful 'key' for indexing the cache. +*/ static int addk (FuncState *fs, TValue *key, TValue *v) { lua_State *L = fs->ls->L; - TValue *idx = luaH_set(L, fs->h, key); Proto *f = fs->f; + TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ int k, oldsize; - if (ttisnumber(idx)) { - lua_Number n = nvalue(idx); - lua_number2int(k, n); - if (luaV_rawequalobj(&f->k[k], v)) - return k; - /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0"); - go through and create a new entry for this value */ + if (ttisinteger(idx)) { /* is there an index there? */ + k = cast_int(ivalue(idx)); + /* correct value? (warning: must distinguish floats from integers!) */ + if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && + luaV_rawequalobj(&f->k[k], v)) + return k; /* reuse index */ } /* constant not found; create a new entry */ oldsize = f->sizek; k = fs->nk; /* numerical value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ - setnvalue(idx, cast_num(k)); + setivalue(idx, k); luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[k], v); @@ -316,94 +452,134 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { } +/* +** Add a string to list of constants and return its index. +*/ int luaK_stringK (FuncState *fs, TString *s) { TValue o; setsvalue(fs->ls->L, &o, s); - return addk(fs, &o, &o); + return addk(fs, &o, &o); /* use string itself as key */ } -int luaK_numberK (FuncState *fs, lua_Number r) { - int n; - lua_State *L = fs->ls->L; +/* +** Add an integer to list of constants and return its index. +** Integers use userdata as keys to avoid collision with floats with +** same value; conversion to 'void*' is used only for hashing, so there +** are no "precision" problems. +*/ +int luaK_intK (FuncState *fs, lua_Integer n) { + TValue k, o; + setpvalue(&k, cast(void*, cast(size_t, n))); + setivalue(&o, n); + return addk(fs, &k, &o); +} + +/* +** Add a float to list of constants and return its index. +*/ +static int luaK_numberK (FuncState *fs, lua_Number r) { TValue o; - setnvalue(&o, r); - if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */ - /* use raw representation as key to avoid numeric problems */ - setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r))); - n = addk(fs, L->top - 1, &o); - L->top--; - } - else - n = addk(fs, &o, &o); /* regular case */ - return n; + setfltvalue(&o, r); + return addk(fs, &o, &o); /* use number itself as key */ } +/* +** Add a boolean to list of constants and return its index. +*/ static int boolK (FuncState *fs, int b) { TValue o; setbvalue(&o, b); - return addk(fs, &o, &o); + return addk(fs, &o, &o); /* use boolean itself as key */ } +/* +** Add nil to list of constants and return its index. +*/ static int nilK (FuncState *fs) { TValue k, v; setnilvalue(&v); /* cannot use nil as key; instead use table itself to represent nil */ - sethvalue(fs->ls->L, &k, fs->h); + sethvalue(fs->ls->L, &k, fs->ls->h); return addk(fs, &k, &v); } +/* +** Fix an expression to return the number of results 'nresults'. +** Either 'e' is a multi-ret expression (function call or vararg) +** or 'nresults' is LUA_MULTRET (as any expression can satisfy that). +*/ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { if (e->k == VCALL) { /* expression is an open function call? */ - SETARG_C(getcode(fs, e), nresults+1); + SETARG_C(getinstruction(fs, e), nresults + 1); } else if (e->k == VVARARG) { - SETARG_B(getcode(fs, e), nresults+1); - SETARG_A(getcode(fs, e), fs->freereg); + Instruction *pc = &getinstruction(fs, e); + SETARG_B(*pc, nresults + 1); + SETARG_A(*pc, fs->freereg); luaK_reserveregs(fs, 1); } + else lua_assert(nresults == LUA_MULTRET); } +/* +** Fix an expression to return one result. +** If expression is not a multi-ret expression (function call or +** vararg), it already returns one result, so nothing needs to be done. +** Function calls become VNONRELOC expressions (as its result comes +** fixed in the base register of the call), while vararg expressions +** become VRELOCABLE (as OP_VARARG puts its results where it wants). +** (Calls are created returning one result, so that does not need +** to be fixed.) +*/ void luaK_setoneret (FuncState *fs, expdesc *e) { if (e->k == VCALL) { /* expression is an open function call? */ - e->k = VNONRELOC; - e->u.info = GETARG_A(getcode(fs, e)); + /* already returns 1 value */ + lua_assert(GETARG_C(getinstruction(fs, e)) == 2); + e->k = VNONRELOC; /* result has fixed position */ + e->u.info = GETARG_A(getinstruction(fs, e)); } else if (e->k == VVARARG) { - SETARG_B(getcode(fs, e), 2); + SETARG_B(getinstruction(fs, e), 2); e->k = VRELOCABLE; /* can relocate its simple result */ } } +/* +** Ensure that expression 'e' is not a variable. +*/ void luaK_dischargevars (FuncState *fs, expdesc *e) { switch (e->k) { - case VLOCAL: { - e->k = VNONRELOC; + case VLOCAL: { /* already in a register */ + e->k = VNONRELOC; /* becomes a non-relocatable value */ break; } - case VUPVAL: { + case VUPVAL: { /* move value to some (pending) register */ e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); e->k = VRELOCABLE; break; } case VINDEXED: { - OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */ + OpCode op; freereg(fs, e->u.ind.idx); - if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */ + if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */ freereg(fs, e->u.ind.t); op = OP_GETTABLE; } + else { + lua_assert(e->u.ind.vt == VUPVAL); + op = OP_GETTABUP; /* 't' is in an upvalue */ + } e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); e->k = VRELOCABLE; break; } - case VVARARG: - case VCALL: { + case VVARARG: case VCALL: { luaK_setoneret(fs, e); break; } @@ -412,12 +588,10 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { } -static int code_label (FuncState *fs, int A, int b, int jump) { - luaK_getlabel(fs); /* those instructions may be jump targets */ - return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); -} - - +/* +** Ensures expression value is in register 'reg' (and therefore +** 'e' will become a non-relocatable expression). +*/ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_dischargevars(fs, e); switch (e->k) { @@ -433,13 +607,17 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_codek(fs, reg, e->u.info); break; } - case VKNUM: { + case VKFLT: { luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); break; } + case VKINT: { + luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); + break; + } case VRELOCABLE: { - Instruction *pc = &getcode(fs, e); - SETARG_A(*pc, reg); + Instruction *pc = &getinstruction(fs, e); + SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ break; } case VNONRELOC: { @@ -448,7 +626,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { break; } default: { - lua_assert(e->k == VVOID || e->k == VJMP); + lua_assert(e->k == VJMP); return; /* nothing to do... */ } } @@ -457,26 +635,55 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { } +/* +** Ensures expression value is in any register. +*/ static void discharge2anyreg (FuncState *fs, expdesc *e) { - if (e->k != VNONRELOC) { - luaK_reserveregs(fs, 1); - discharge2reg(fs, e, fs->freereg-1); + if (e->k != VNONRELOC) { /* no fixed register yet? */ + luaK_reserveregs(fs, 1); /* get a register */ + discharge2reg(fs, e, fs->freereg-1); /* put value there */ } } +static int code_loadbool (FuncState *fs, int A, int b, int jump) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); +} + + +/* +** check whether list has any jump that do not produce a value +** or produce an inverted value +*/ +static int need_value (FuncState *fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + Instruction i = *getjumpcontrol(fs, list); + if (GET_OPCODE(i) != OP_TESTSET) return 1; + } + return 0; /* not found */ +} + + +/* +** Ensures final expression result (including results from its jump +** lists) is in register 'reg'. +** If expression has jumps, need to patch these jumps either to +** its final position or to "load" instructions (for those tests +** that do not produce values). +*/ static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); - if (e->k == VJMP) - luaK_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */ + if (e->k == VJMP) /* expression itself is a test? */ + luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(fs, e->t) || need_value(fs, e->f)) { int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); - p_f = code_label(fs, reg, 0, 1); - p_t = code_label(fs, reg, 1, 0); + p_f = code_loadbool(fs, reg, 0, 1); + p_t = code_loadbool(fs, reg, 1, 0); luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); @@ -489,6 +696,10 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) { } +/* +** Ensures final expression result (including results from its jump +** lists) is in next available register. +*/ void luaK_exp2nextreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); freeexp(fs, e); @@ -497,26 +708,39 @@ void luaK_exp2nextreg (FuncState *fs, expdesc *e) { } +/* +** Ensures final expression result (including results from its jump +** lists) is in some (any) register and return that register. +*/ int luaK_exp2anyreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); - if (e->k == VNONRELOC) { - if (!hasjumps(e)) return e->u.info; /* exp is already in a register */ + if (e->k == VNONRELOC) { /* expression already has a register? */ + if (!hasjumps(e)) /* no jumps? */ + return e->u.info; /* result is already in a register */ if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ - exp2reg(fs, e, e->u.info); /* put value on it */ + exp2reg(fs, e, e->u.info); /* put final result in it */ return e->u.info; } } - luaK_exp2nextreg(fs, e); /* default */ + luaK_exp2nextreg(fs, e); /* otherwise, use next available register */ return e->u.info; } +/* +** Ensures final expression result is either in a register or in an +** upvalue. +*/ void luaK_exp2anyregup (FuncState *fs, expdesc *e) { if (e->k != VUPVAL || hasjumps(e)) luaK_exp2anyreg(fs, e); } +/* +** Ensures final expression result is either in a register or it is +** a constant. +*/ void luaK_exp2val (FuncState *fs, expdesc *e) { if (hasjumps(e)) luaK_exp2anyreg(fs, e); @@ -525,29 +749,26 @@ void luaK_exp2val (FuncState *fs, expdesc *e) { } +/* +** Ensures final expression result is in a valid R/K index +** (that is, it is either in a register or in 'k' with an index +** in the range of R/K indices). +** Returns R/K index. +*/ int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); - switch (e->k) { - case VTRUE: - case VFALSE: - case VNIL: { - if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */ - e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); - e->k = VK; - return RKASK(e->u.info); - } - else break; - } - case VKNUM: { - e->u.info = luaK_numberK(fs, e->u.nval); + switch (e->k) { /* move constants to 'k' */ + case VTRUE: e->u.info = boolK(fs, 1); goto vk; + case VFALSE: e->u.info = boolK(fs, 0); goto vk; + case VNIL: e->u.info = nilK(fs); goto vk; + case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk; + case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk; + case VK: + vk: e->k = VK; - /* go through */ - } - case VK: { - if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */ + if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ return RKASK(e->u.info); else break; - } default: break; } /* not a constant in the right range: put it in a register */ @@ -555,11 +776,14 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) { } +/* +** Generate code to store result of expression 'ex' into variable 'var'. +*/ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { freeexp(fs, ex); - exp2reg(fs, ex, var->u.info); + exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */ return; } case VUPVAL: { @@ -573,29 +797,32 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); break; } - default: { - lua_assert(0); /* invalid var kind to store */ - break; - } + default: lua_assert(0); /* invalid var kind to store */ } freeexp(fs, ex); } +/* +** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). +*/ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { int ereg; luaK_exp2anyreg(fs, e); ereg = e->u.info; /* register where 'e' was placed */ freeexp(fs, e); e->u.info = fs->freereg; /* base register for op_self */ - e->k = VNONRELOC; + e->k = VNONRELOC; /* self expression has a fixed register */ luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); freeexp(fs, key); } -static void invertjump (FuncState *fs, expdesc *e) { +/* +** Negate condition 'e' (where 'e' is a comparison). +*/ +static void negatecondition (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->u.info); lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && GET_OPCODE(*pc) != OP_TEST); @@ -603,9 +830,15 @@ static void invertjump (FuncState *fs, expdesc *e) { } +/* +** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond' +** is true, code will jump if 'e' is true.) Return jump position. +** Optimize when 'e' is 'not' something, inverting the condition +** and removing the 'not'. +*/ static int jumponcond (FuncState *fs, expdesc *e, int cond) { if (e->k == VRELOCABLE) { - Instruction ie = getcode(fs, e); + Instruction ie = getinstruction(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); @@ -618,36 +851,42 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) { } +/* +** Emit code to go through if 'e' is true, jump otherwise. +*/ void luaK_goiftrue (FuncState *fs, expdesc *e) { - int pc; /* pc of last jump */ + int pc; /* pc of new jump */ luaK_dischargevars(fs, e); switch (e->k) { - case VJMP: { - invertjump(fs, e); - pc = e->u.info; + case VJMP: { /* condition? */ + negatecondition(fs, e); /* jump when it is false */ + pc = e->u.info; /* save jump position */ break; } - case VK: case VKNUM: case VTRUE: { + case VK: case VKFLT: case VKINT: case VTRUE: { pc = NO_JUMP; /* always true; do nothing */ break; } default: { - pc = jumponcond(fs, e, 0); + pc = jumponcond(fs, e, 0); /* jump when false */ break; } } - luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ - luaK_patchtohere(fs, e->t); + luaK_concat(fs, &e->f, pc); /* insert new jump in false list */ + luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */ e->t = NO_JUMP; } +/* +** Emit code to go through if 'e' is false, jump otherwise. +*/ void luaK_goiffalse (FuncState *fs, expdesc *e) { - int pc; /* pc of last jump */ + int pc; /* pc of new jump */ luaK_dischargevars(fs, e); switch (e->k) { case VJMP: { - pc = e->u.info; + pc = e->u.info; /* already jump if true */ break; } case VNIL: case VFALSE: { @@ -655,29 +894,32 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) { break; } default: { - pc = jumponcond(fs, e, 1); + pc = jumponcond(fs, e, 1); /* jump if true */ break; } } - luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ - luaK_patchtohere(fs, e->f); + luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */ + luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */ e->f = NO_JUMP; } +/* +** Code 'not e', doing constant folding. +*/ static void codenot (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); switch (e->k) { case VNIL: case VFALSE: { - e->k = VTRUE; + e->k = VTRUE; /* true == not nil == not false */ break; } - case VK: case VKNUM: case VTRUE: { - e->k = VFALSE; + case VK: case VKFLT: case VKINT: case VTRUE: { + e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ break; } case VJMP: { - invertjump(fs, e); + negatecondition(fs, e); break; } case VRELOCABLE: @@ -688,118 +930,177 @@ static void codenot (FuncState *fs, expdesc *e) { e->k = VRELOCABLE; break; } - default: { - lua_assert(0); /* cannot happen */ - break; - } + default: lua_assert(0); /* cannot happen */ } /* interchange true and false lists */ { int temp = e->f; e->f = e->t; e->t = temp; } - removevalues(fs, e->f); + removevalues(fs, e->f); /* values are useless when negated */ removevalues(fs, e->t); } +/* +** Create expression 't[k]'. 't' must have its final result already in a +** register or upvalue. +*/ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { - lua_assert(!hasjumps(t)); - t->u.ind.t = t->u.info; - t->u.ind.idx = luaK_exp2RK(fs, k); - t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL - : check_exp(vkisinreg(t->k), VLOCAL); + lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL)); + t->u.ind.t = t->u.info; /* register or upvalue index */ + t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */ + t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL; t->k = VINDEXED; } -static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { - lua_Number r; - if (!isnumeral(e1) || !isnumeral(e2)) return 0; - if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0) - return 0; /* do not attempt to divide by 0 */ - r = luaO_arith(op - OP_ADD + LUA_OPADD, e1->u.nval, e2->u.nval); - e1->u.nval = r; - return 1; +/* +** Return false if folding can raise an error. +** Bitwise operations need operands convertible to integers; division +** operations cannot have 0 as divisor. +*/ +static int validop (int op, TValue *v1, TValue *v2) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ + lua_Integer i; + return (tointeger(v1, &i) && tointeger(v2, &i)); + } + case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ + return (nvalue(v2) != 0); + default: return 1; /* everything else is valid */ + } } -static void codearith (FuncState *fs, OpCode op, - expdesc *e1, expdesc *e2, int line) { - if (constfolding(op, e1, e2)) - return; - else { - int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; - int o1 = luaK_exp2RK(fs, e1); - if (o1 > o2) { - freeexp(fs, e1); - freeexp(fs, e2); - } - else { - freeexp(fs, e2); - freeexp(fs, e1); - } - e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); - e1->k = VRELOCABLE; - luaK_fixline(fs, line); +/* +** Try to "constant-fold" an operation; return 1 iff successful. +** (In this case, 'e1' has the final result.) +*/ +static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) { + TValue v1, v2, res; + if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) + return 0; /* non-numeric operands or not safe to fold */ + luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ + if (ttisinteger(&res)) { + e1->k = VKINT; + e1->u.ival = ivalue(&res); } + else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */ + lua_Number n = fltvalue(&res); + if (luai_numisnan(n) || n == 0) + return 0; + e1->k = VKFLT; + e1->u.nval = n; + } + return 1; } -static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, - expdesc *e2) { - int o1 = luaK_exp2RK(fs, e1); - int o2 = luaK_exp2RK(fs, e2); - freeexp(fs, e2); - freeexp(fs, e1); - if (cond == 0 && op != OP_EQ) { - int temp; /* exchange args to replace by `<' or `<=' */ - temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ - cond = 1; +/* +** Emit code for unary expressions that "produce values" +** (everything but 'not'). +** Expression to produce final result will be encoded in 'e'. +*/ +static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { + int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ + freeexp(fs, e); + e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ + e->k = VRELOCABLE; /* all those operations are relocatable */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for binary expressions that "produce values" +** (everything but logical operators 'and'/'or' and comparison +** operators). +** Expression to produce final result will be encoded in 'e1'. +*/ +static void codebinexpval (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int line) { + int rk1 = luaK_exp2RK(fs, e1); /* both operands are "RK" */ + int rk2 = luaK_exp2RK(fs, e2); + freeexps(fs, e1, e2); + e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ + e1->k = VRELOCABLE; /* all those operations are relocatable */ + luaK_fixline(fs, line); +} + + +/* +** Emit code for comparisons. +** 'e1' was already put in R/K form by 'luaK_infix'. +*/ +static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { + int rk1 = (e1->k == VK) ? RKASK(e1->u.info) + : check_exp(e1->k == VNONRELOC, e1->u.info); + int rk2 = luaK_exp2RK(fs, e2); + freeexps(fs, e1, e2); + switch (opr) { + case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */ + e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2); + break; + } + case OPR_GT: case OPR_GE: { + /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */ + OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); + e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */ + break; + } + default: { /* '==', '<', '<=' use their own opcodes */ + OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); + e1->u.info = condjump(fs, op, 1, rk1, rk2); + break; + } } - e1->u.info = condjump(fs, op, cond, o1, o2); e1->k = VJMP; } +/* +** Aplly prefix operation 'op' to expression 'e'. +*/ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { - expdesc e2; - e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; + static expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; /* fake 2nd operand */ switch (op) { - case OPR_MINUS: { - if (isnumeral(e)) /* minus constant? */ - e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */ - else { - luaK_exp2anyreg(fs, e); - codearith(fs, OP_UNM, e, &e2, line); - } + case OPR_MINUS: case OPR_BNOT: + if (constfolding(fs, op + LUA_OPUNM, e, &ef)) + break; + /* FALLTHROUGH */ + case OPR_LEN: + codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); break; - } case OPR_NOT: codenot(fs, e); break; - case OPR_LEN: { - luaK_exp2anyreg(fs, e); /* cannot operate on constants */ - codearith(fs, OP_LEN, e, &e2, line); - break; - } default: lua_assert(0); } } +/* +** Process 1st operand 'v' of binary operation 'op' before reading +** 2nd operand. +*/ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { switch (op) { case OPR_AND: { - luaK_goiftrue(fs, v); + luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ break; } case OPR_OR: { - luaK_goiffalse(fs, v); + luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */ break; } case OPR_CONCAT: { - luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ + luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ break; } - case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_MOD: case OPR_POW: { - if (!isnumeral(v)) luaK_exp2RK(fs, v); + case OPR_ADD: case OPR_SUB: + case OPR_MUL: case OPR_DIV: case OPR_IDIV: + case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: + case OPR_SHL: case OPR_SHR: { + if (!tonumeral(v, NULL)) + luaK_exp2RK(fs, v); + /* else keep numeral, which may be folded with 2nd operand */ break; } default: { @@ -810,18 +1111,24 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { } +/* +** Finalize code for binary operation, after reading 2nd operand. +** For '(a .. b .. c)' (which is '(a .. (b .. c))', because +** concatenation is right associative), merge second CONCAT into first +** one. +*/ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2, int line) { switch (op) { case OPR_AND: { - lua_assert(e1->t == NO_JUMP); /* list must be closed */ + lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->f, e1->f); *e1 = *e2; break; } case OPR_OR: { - lua_assert(e1->f == NO_JUMP); /* list must be closed */ + lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->t, e1->t); *e1 = *e2; @@ -829,29 +1136,30 @@ void luaK_posfix (FuncState *fs, BinOpr op, } case OPR_CONCAT: { luaK_exp2val(fs, e2); - if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { - lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1); + if (e2->k == VRELOCABLE && + GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) { + lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1); freeexp(fs, e1); - SETARG_B(getcode(fs, e2), e1->u.info); + SETARG_B(getinstruction(fs, e2), e1->u.info); e1->k = VRELOCABLE; e1->u.info = e2->u.info; } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ - codearith(fs, OP_CONCAT, e1, e2, line); + codebinexpval(fs, OP_CONCAT, e1, e2, line); } break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_MOD: case OPR_POW: { - codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line); - break; - } - case OPR_EQ: case OPR_LT: case OPR_LE: { - codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2); + case OPR_IDIV: case OPR_MOD: case OPR_POW: + case OPR_BAND: case OPR_BOR: case OPR_BXOR: + case OPR_SHL: case OPR_SHR: { + if (!constfolding(fs, op + LUA_OPADD, e1, e2)) + codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); break; } + case OPR_EQ: case OPR_LT: case OPR_LE: case OPR_NE: case OPR_GT: case OPR_GE: { - codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2); + codecomp(fs, op, e1, e2); break; } default: lua_assert(0); @@ -859,15 +1167,25 @@ void luaK_posfix (FuncState *fs, BinOpr op, } +/* +** Change line information associated with current position. +*/ void luaK_fixline (FuncState *fs, int line) { fs->f->lineinfo[fs->pc - 1] = line; } +/* +** Emit a SETLIST instruction. +** 'base' is register that keeps table; +** 'nelems' is #table plus those to be stored now; +** 'tostore' is number of values (in registers 'base + 1',...) to add to +** table (or LUA_MULTRET to add up to stack top). +*/ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; int b = (tostore == LUA_MULTRET) ? 0 : tostore; - lua_assert(tostore != 0); + lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); if (c <= MAXARG_C) luaK_codeABC(fs, OP_SETLIST, base, b, c); else if (c <= MAXARG_Ax) { diff --git a/depends/lua/src/lcorolib.c b/depends/lua/src/lcorolib.c index ce4f6ad42..2303429e7 100644 --- a/depends/lua/src/lcorolib.c +++ b/depends/lua/src/lcorolib.c @@ -1,15 +1,16 @@ /* -** $Id: lcorolib.c,v 1.5.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $ ** Coroutine Library ** See Copyright Notice in lua.h */ +#define lcorolib_c +#define LUA_LIB -#include +#include "lprefix.h" -#define lcorolib_c -#define LUA_LIB +#include #include "lua.h" @@ -17,6 +18,13 @@ #include "lualib.h" +static lua_State *getco (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + luaL_argcheck(L, co, 1, "thread expected"); + return co; +} + + static int auxresume (lua_State *L, lua_State *co, int narg) { int status; if (!lua_checkstack(co, narg)) { @@ -47,9 +55,8 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { static int luaB_coresume (lua_State *L) { - lua_State *co = lua_tothread(L, 1); + lua_State *co = getco(L); int r; - luaL_argcheck(L, co, 1, "coroutine expected"); r = auxresume(L, co, lua_gettop(L) - 1); if (r < 0) { lua_pushboolean(L, 0); @@ -59,7 +66,7 @@ static int luaB_coresume (lua_State *L) { else { lua_pushboolean(L, 1); lua_insert(L, -(r + 1)); - return r + 1; /* return true + `resume' returns */ + return r + 1; /* return true + 'resume' returns */ } } @@ -68,7 +75,7 @@ static int luaB_auxwrap (lua_State *L) { lua_State *co = lua_tothread(L, lua_upvalueindex(1)); int r = auxresume(L, co, lua_gettop(L)); if (r < 0) { - if (lua_isstring(L, -1)) { /* error object is a string? */ + if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */ luaL_where(L, 1); /* add extra info */ lua_insert(L, -2); lua_concat(L, 2); @@ -102,8 +109,7 @@ static int luaB_yield (lua_State *L) { static int luaB_costatus (lua_State *L) { - lua_State *co = lua_tothread(L, 1); - luaL_argcheck(L, co, 1, "coroutine expected"); + lua_State *co = getco(L); if (L == co) lua_pushliteral(L, "running"); else { switch (lua_status(co)) { @@ -129,6 +135,12 @@ static int luaB_costatus (lua_State *L) { } +static int luaB_yieldable (lua_State *L) { + lua_pushboolean(L, lua_isyieldable(L)); + return 1; +} + + static int luaB_corunning (lua_State *L) { int ismain = lua_pushthread(L); lua_pushboolean(L, ismain); @@ -143,6 +155,7 @@ static const luaL_Reg co_funcs[] = { {"status", luaB_costatus}, {"wrap", luaB_cowrap}, {"yield", luaB_yield}, + {"isyieldable", luaB_yieldable}, {NULL, NULL} }; diff --git a/depends/lua/src/lctype.c b/depends/lua/src/lctype.c index 93f8cadc3..ae9367e69 100644 --- a/depends/lua/src/lctype.c +++ b/depends/lua/src/lctype.c @@ -1,5 +1,5 @@ /* -** $Id: lctype.c,v 1.11.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lctype.c,v 1.12 2014/11/02 19:19:04 roberto Exp $ ** 'ctype' functions for Lua ** See Copyright Notice in lua.h */ @@ -7,6 +7,9 @@ #define lctype_c #define LUA_CORE +#include "lprefix.h" + + #include "lctype.h" #if !LUA_USE_CTYPE /* { */ diff --git a/depends/lua/src/ldblib.c b/depends/lua/src/ldblib.c index 84fe3c7d8..786f6cd95 100644 --- a/depends/lua/src/ldblib.c +++ b/depends/lua/src/ldblib.c @@ -1,26 +1,42 @@ /* -** $Id: ldblib.c,v 1.132.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ +#define ldblib_c +#define LUA_LIB + +#include "lprefix.h" + #include #include #include -#define ldblib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" #include "lualib.h" -#define HOOKKEY "_HKEY" +/* +** The hook table at registry[&HOOKKEY] maps threads to their current +** hook function. (We only need the unique address of 'HOOKKEY'.) +*/ +static const int HOOKKEY = 0; +/* +** If L1 != L, L1 can be in any state, and therefore there are no +** guarantees about its stack space; any push in L1 must be +** checked. +*/ +static void checkstack (lua_State *L, lua_State *L1, int n) { + if (L != L1 && !lua_checkstack(L1, n)) + luaL_error(L, "stack overflow"); +} + static int db_getregistry (lua_State *L) { lua_pushvalue(L, LUA_REGISTRYINDEX); @@ -57,35 +73,20 @@ static int db_getuservalue (lua_State *L) { static int db_setuservalue (lua_State *L) { - if (lua_type(L, 1) == LUA_TLIGHTUSERDATA) - luaL_argerror(L, 1, "full userdata expected, got light userdata"); luaL_checktype(L, 1, LUA_TUSERDATA); - if (!lua_isnoneornil(L, 2)) - luaL_checktype(L, 2, LUA_TTABLE); + luaL_checkany(L, 2); lua_settop(L, 2); lua_setuservalue(L, 1); return 1; } -static void settabss (lua_State *L, const char *i, const char *v) { - lua_pushstring(L, v); - lua_setfield(L, -2, i); -} - - -static void settabsi (lua_State *L, const char *i, int v) { - lua_pushinteger(L, v); - lua_setfield(L, -2, i); -} - - -static void settabsb (lua_State *L, const char *i, int v) { - lua_pushboolean(L, v); - lua_setfield(L, -2, i); -} - - +/* +** Auxiliary function used by several library functions: check for +** an optional thread as function's first argument and set 'arg' with +** 1 if this argument is present (so that functions can skip it to +** access their other arguments) +*/ static lua_State *getthread (lua_State *L, int *arg) { if (lua_isthread(L, 1)) { *arg = 1; @@ -93,44 +94,74 @@ static lua_State *getthread (lua_State *L, int *arg) { } else { *arg = 0; - return L; + return L; /* function will operate over current thread */ } } +/* +** Variations of 'lua_settable', used by 'db_getinfo' to put results +** from 'lua_getinfo' into result table. Key is always a string; +** value can be a string, an int, or a boolean. +*/ +static void settabss (lua_State *L, const char *k, const char *v) { + lua_pushstring(L, v); + lua_setfield(L, -2, k); +} + +static void settabsi (lua_State *L, const char *k, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, k); +} + +static void settabsb (lua_State *L, const char *k, int v) { + lua_pushboolean(L, v); + lua_setfield(L, -2, k); +} + + +/* +** In function 'db_getinfo', the call to 'lua_getinfo' may push +** results on the stack; later it creates the result table to put +** these objects. Function 'treatstackoption' puts the result from +** 'lua_getinfo' on top of the result table so that it can call +** 'lua_setfield'. +*/ static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { - if (L == L1) { - lua_pushvalue(L, -2); - lua_remove(L, -3); - } + if (L == L1) + lua_rotate(L, -2, 1); /* exchange object and table */ else - lua_xmove(L1, L, 1); - lua_setfield(L, -2, fname); + lua_xmove(L1, L, 1); /* move object to the "main" stack */ + lua_setfield(L, -2, fname); /* put object into table */ } +/* +** Calls 'lua_getinfo' and collects all results in a new table. +** L1 needs stack space for an optional input (function) plus +** two optional outputs (function and line table) from function +** 'lua_getinfo'. +*/ static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); const char *options = luaL_optstring(L, arg+2, "flnStu"); - if (lua_isnumber(L, arg+1)) { - if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { + checkstack(L, L1, 3); + if (lua_isfunction(L, arg + 1)) { /* info about a function? */ + options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ + lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ + lua_xmove(L, L1, 1); + } + else { /* stack level */ + if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } - else if (lua_isfunction(L, arg+1)) { - lua_pushfstring(L, ">%s", options); - options = lua_tostring(L, -1); - lua_pushvalue(L, arg+1); - lua_xmove(L, L1, 1); - } - else - return luaL_argerror(L, arg+1, "function or level expected"); if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+2, "invalid option"); - lua_createtable(L, 0, 2); + lua_newtable(L); /* table to collect results */ if (strchr(options, 'S')) { settabss(L, "source", ar.source); settabss(L, "short_src", ar.short_src); @@ -164,20 +195,22 @@ static int db_getlocal (lua_State *L) { lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; - int nvar = luaL_checkint(L, arg+2); /* local-variable index */ + int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ if (lua_isfunction(L, arg + 1)) { /* function argument? */ lua_pushvalue(L, arg + 1); /* push function */ lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ - return 1; + return 1; /* return only name (there is no value) */ } else { /* stack-level argument */ - if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + int level = (int)luaL_checkinteger(L, arg + 1); + if (!lua_getstack(L1, level, &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); + checkstack(L, L1, 1); name = lua_getlocal(L1, &ar, nvar); if (name) { - lua_xmove(L1, L, 1); /* push local value */ + lua_xmove(L1, L, 1); /* move local value */ lua_pushstring(L, name); /* push name */ - lua_pushvalue(L, -2); /* re-order */ + lua_rotate(L, -2, 1); /* re-order */ return 2; } else { @@ -190,26 +223,36 @@ static int db_getlocal (lua_State *L) { static int db_setlocal (lua_State *L) { int arg; + const char *name; lua_State *L1 = getthread(L, &arg); lua_Debug ar; - if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ + int level = (int)luaL_checkinteger(L, arg + 1); + int nvar = (int)luaL_checkinteger(L, arg + 2); + if (!lua_getstack(L1, level, &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); luaL_checkany(L, arg+3); lua_settop(L, arg+3); + checkstack(L, L1, 1); lua_xmove(L, L1, 1); - lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); + name = lua_setlocal(L1, &ar, nvar); + if (name == NULL) + lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ + lua_pushstring(L, name); return 1; } +/* +** get (if 'get' is true) or set an upvalue from a closure +*/ static int auxupvalue (lua_State *L, int get) { const char *name; - int n = luaL_checkint(L, 2); - luaL_checktype(L, 1, LUA_TFUNCTION); + int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ + luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); - lua_insert(L, -(get+1)); + lua_insert(L, -(get+1)); /* no-op if get is false */ return get + 1; } @@ -225,13 +268,15 @@ static int db_setupvalue (lua_State *L) { } +/* +** Check whether a given upvalue from a given closure exists and +** returns its index +*/ static int checkupval (lua_State *L, int argf, int argnup) { - lua_Debug ar; - int nup = luaL_checkint(L, argnup); - luaL_checktype(L, argf, LUA_TFUNCTION); - lua_pushvalue(L, argf); - lua_getinfo(L, ">u", &ar); - luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index"); + int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ + luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ + luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, + "invalid upvalue index"); return nup; } @@ -253,26 +298,29 @@ static int db_upvaluejoin (lua_State *L) { } -#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY) - - +/* +** Call hook function registered at hook table for the current +** thread (if there is one) +*/ static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = {"call", "return", "line", "count", "tail call"}; - gethooktable(L); + lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); lua_pushthread(L); - lua_rawget(L, -2); - if (lua_isfunction(L, -1)) { - lua_pushstring(L, hooknames[(int)ar->event]); + if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ + lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ if (ar->currentline >= 0) - lua_pushinteger(L, ar->currentline); + lua_pushinteger(L, ar->currentline); /* push current line */ else lua_pushnil(L); lua_assert(lua_getinfo(L, "lS", ar)); - lua_call(L, 2, 0); + lua_call(L, 2, 0); /* call hook function */ } } +/* +** Convert a string mask (for 'sethook') into a bit mask +*/ static int makemask (const char *smask, int count) { int mask = 0; if (strchr(smask, 'c')) mask |= LUA_MASKCALL; @@ -283,6 +331,9 @@ static int makemask (const char *smask, int count) { } +/* +** Convert a bit mask (for 'gethook') into a string mask +*/ static char *unmakemask (int mask, char *smask) { int i = 0; if (mask & LUA_MASKCALL) smask[i++] = 'c'; @@ -297,26 +348,30 @@ static int db_sethook (lua_State *L) { int arg, mask, count; lua_Hook func; lua_State *L1 = getthread(L, &arg); - if (lua_isnoneornil(L, arg+1)) { + if (lua_isnoneornil(L, arg+1)) { /* no hook? */ lua_settop(L, arg+1); func = NULL; mask = 0; count = 0; /* turn off hooks */ } else { const char *smask = luaL_checkstring(L, arg+2); luaL_checktype(L, arg+1, LUA_TFUNCTION); - count = luaL_optint(L, arg+3, 0); + count = (int)luaL_optinteger(L, arg + 3, 0); func = hookf; mask = makemask(smask, count); } - if (gethooktable(L) == 0) { /* creating hook table? */ + if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) { + lua_createtable(L, 0, 2); /* create a hook table */ + lua_pushvalue(L, -1); + lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */ lua_pushstring(L, "k"); lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ lua_pushvalue(L, -1); lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ } - lua_pushthread(L1); lua_xmove(L1, L, 1); - lua_pushvalue(L, arg+1); - lua_rawset(L, -3); /* set new hook */ - lua_sethook(L1, func, mask, count); /* set hooks */ + checkstack(L, L1, 1); + lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ + lua_pushvalue(L, arg + 1); /* value (hook function) */ + lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ + lua_sethook(L1, func, mask, count); return 0; } @@ -327,16 +382,19 @@ static int db_gethook (lua_State *L) { char buff[5]; int mask = lua_gethookmask(L1); lua_Hook hook = lua_gethook(L1); - if (hook != NULL && hook != hookf) /* external hook? */ + if (hook == NULL) /* no hook? */ + lua_pushnil(L); + else if (hook != hookf) /* external hook? */ lua_pushliteral(L, "external hook"); - else { - gethooktable(L); + else { /* hook table must exist */ + lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); + checkstack(L, L1, 1); lua_pushthread(L1); lua_xmove(L1, L, 1); - lua_rawget(L, -2); /* get hook */ + lua_rawget(L, -2); /* 1st result = hooktable[L1] */ lua_remove(L, -2); /* remove hook table */ } - lua_pushstring(L, unmakemask(mask, buff)); - lua_pushinteger(L, lua_gethookcount(L1)); + lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ + lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ return 3; } @@ -344,13 +402,13 @@ static int db_gethook (lua_State *L) { static int db_debug (lua_State *L) { for (;;) { char buffer[250]; - luai_writestringerror("%s", "lua_debug> "); + lua_writestringerror("%s", "lua_debug> "); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || lua_pcall(L, 0, 0, 0)) - luai_writestringerror("%s\n", lua_tostring(L, -1)); + lua_writestringerror("%s\n", lua_tostring(L, -1)); lua_settop(L, 0); /* remove eventual returns */ } } @@ -363,7 +421,7 @@ static int db_traceback (lua_State *L) { if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ lua_pushvalue(L, arg + 1); /* return it untouched */ else { - int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0); + int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); luaL_traceback(L, L1, msg, level); } return 1; diff --git a/depends/lua/src/ldebug.c b/depends/lua/src/ldebug.c index 20d663eff..e499ee362 100644 --- a/depends/lua/src/ldebug.c +++ b/depends/lua/src/ldebug.c @@ -1,18 +1,19 @@ /* -** $Id: ldebug.c,v 2.90.1.3 2013/05/16 16:04:15 roberto Exp $ +** $Id: ldebug.c,v 2.120 2016/03/31 19:01:21 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ +#define ldebug_c +#define LUA_CORE + +#include "lprefix.h" + #include #include #include - -#define ldebug_c -#define LUA_CORE - #include "lua.h" #include "lapi.h" @@ -33,6 +34,10 @@ #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) +/* Active Lua function (given call info) */ +#define ci_func(ci) (clLvalue((ci)->func)) + + static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); @@ -48,9 +53,31 @@ static int currentline (CallInfo *ci) { /* -** this function can be called asynchronous (e.g. during a signal) +** If function yielded, its 'func' can be in the 'extra' field. The +** next function restores 'func' to its correct value for debugging +** purposes. (It exchanges 'func' and 'extra'; so, when called again, +** after debugging, it also "re-restores" ** 'func' to its altered value. +*/ +static void swapextra (lua_State *L) { + if (L->status == LUA_YIELD) { + CallInfo *ci = L->ci; /* get function that yielded */ + StkId temp = ci->func; /* exchange its 'func' and 'extra' values */ + ci->func = restorestack(L, ci->extra); + ci->extra = savestack(L, temp); + } +} + + +/* +** This function can be called asynchronously (e.g. during a signal). +** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by +** 'resethookcount') are for debug only, and it is no problem if they +** get arbitrary values (causes at most one wrong hook call). 'hookmask' +** is an atomic value. We assume that pointers are atomic too (e.g., gcc +** ensures that for all platforms where it runs). Moreover, 'hook' is +** always checked before being called (see 'luaD_hook'). */ -LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { +LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { if (func == NULL || mask == 0) { /* turn off hooks? */ mask = 0; func = NULL; @@ -61,7 +88,6 @@ LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { L->basehookcount = count; resethookcount(L); L->hookmask = cast_byte(mask); - return 1; } @@ -106,7 +132,7 @@ static const char *upvalname (Proto *p, int uv) { static const char *findvararg (CallInfo *ci, int n, StkId *pos) { int nparams = clLvalue(ci->func)->p->numparams; - if (n >= ci->u.l.base - ci->func - nparams) + if (n >= cast_int(ci->u.l.base - ci->func) - nparams) return NULL; /* no such vararg */ else { *pos = ci->func + nparams + n; @@ -144,6 +170,7 @@ static const char *findlocal (lua_State *L, CallInfo *ci, int n, LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { const char *name; lua_lock(L); + swapextra(L); if (ar == NULL) { /* information about non-active function? */ if (!isLfunction(L->top - 1)) /* not a Lua function? */ name = NULL; @@ -151,25 +178,30 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0); } else { /* active function; get information through 'ar' */ - StkId pos = 0; /* to avoid warnings */ + StkId pos = NULL; /* to avoid warnings */ name = findlocal(L, ar->i_ci, n, &pos); if (name) { setobj2s(L, L->top, pos); api_incr_top(L); } } + swapextra(L); lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { - StkId pos = 0; /* to avoid warnings */ - const char *name = findlocal(L, ar->i_ci, n, &pos); + StkId pos = NULL; /* to avoid warnings */ + const char *name; lua_lock(L); - if (name) + swapextra(L); + name = findlocal(L, ar->i_ci, n, &pos); + if (name) { setobjs2s(L, pos, L->top - 1); - L->top--; /* pop value */ + L->top--; /* pop value */ + } + swapextra(L); lua_unlock(L); return name; } @@ -269,6 +301,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { CallInfo *ci; StkId func; lua_lock(L); + swapextra(L); if (*what == '>') { ci = NULL; func = L->top - 1; @@ -287,6 +320,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { setobjs2s(L, L->top, func); api_incr_top(L); } + swapextra(L); /* correct before option 'L', which can raise a mem. error */ if (strchr(what, 'L')) collectvalidlines(L, cl); lua_unlock(L); @@ -366,18 +400,13 @@ static int findsetreg (Proto *p, int lastpc, int reg) { case OP_JMP: { int b = GETARG_sBx(i); 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 (dest > jmptarget) jmptarget = dest; /* update 'jmptarget' */ } break; } - case OP_TEST: { - if (reg == a) /* jumped code can change 'a' */ - setreg = filterpc(pc, jmptarget); - break; - } default: if (testAMode(op) && reg == a) /* any instruction that set A */ setreg = filterpc(pc, jmptarget); @@ -443,10 +472,14 @@ static const char *getobjname (Proto *p, int lastpc, int reg, static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { - TMS tm; + TMS tm = (TMS)0; /* to avoid warnings */ Proto *p = ci_func(ci)->p; /* calling function */ int pc = currentpc(ci); /* calling instruction index */ Instruction i = p->code[pc]; /* calling instruction */ + if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ + *name = "?"; + return "hook"; + } switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: /* get function name */ @@ -456,25 +489,27 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { return "for iterator"; } /* all other instructions can call only through metamethods */ - case OP_SELF: - case OP_GETTABUP: - case OP_GETTABLE: tm = TM_INDEX; break; - case OP_SETTABUP: - case OP_SETTABLE: tm = TM_NEWINDEX; break; - case OP_EQ: tm = TM_EQ; break; - case OP_ADD: tm = TM_ADD; break; - case OP_SUB: tm = TM_SUB; break; - case OP_MUL: tm = TM_MUL; break; - case OP_DIV: tm = TM_DIV; break; - case OP_MOD: tm = TM_MOD; break; - case OP_POW: tm = TM_POW; break; + case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: + tm = TM_INDEX; + break; + case OP_SETTABUP: case OP_SETTABLE: + tm = TM_NEWINDEX; + break; + case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD: + case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND: + case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: { + int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */ + tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */ + break; + } case OP_UNM: tm = TM_UNM; break; + case OP_BNOT: tm = TM_BNOT; break; case OP_LEN: tm = TM_LEN; break; + case OP_CONCAT: tm = TM_CONCAT; break; + case OP_EQ: tm = TM_EQ; break; case OP_LT: tm = TM_LT; break; case OP_LE: tm = TM_LE; break; - case OP_CONCAT: tm = TM_CONCAT; break; - default: - return NULL; /* else no useful name can be found */ + default: lua_assert(0); /* other instructions cannot call a function */ } *name = getstr(G(L)->tmname[tm]); return "metamethod"; @@ -485,17 +520,21 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { /* -** only ANSI way to check whether a pointer points to an array -** (used only for error messages, so efficiency is not a big concern) +** The subtraction of two potentially unrelated pointers is +** not ISO C, but it should not crash a program; the subsequent +** checks are ISO C and ensure a correct result. */ static int isinstack (CallInfo *ci, const TValue *o) { - StkId p; - for (p = ci->u.l.base; p < ci->top; p++) - if (o == p) return 1; - return 0; + ptrdiff_t i = o - ci->u.l.base; + return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o); } +/* +** Checks whether value 'o' came from an upvalue. (That can only happen +** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on +** upvalues.) +*/ static const char *getupvalname (CallInfo *ci, const TValue *o, const char **name) { LClosure *c = ci_func(ci); @@ -510,10 +549,9 @@ static const char *getupvalname (CallInfo *ci, const TValue *o, } -l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { +static const char *varinfo (lua_State *L, const TValue *o) { + const char *name = NULL; /* to avoid warnings */ CallInfo *ci = L->ci; - const char *name = NULL; - const char *t = objtypename(o); const char *kind = NULL; if (isLua(ci)) { kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ @@ -521,73 +559,121 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { kind = getobjname(ci_func(ci)->p, currentpc(ci), cast_int(o - ci->u.l.base), &name); } - if (kind) - luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", - op, kind, name, t); - else - luaG_runerror(L, "attempt to %s a %s value", op, t); + return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; } -l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) { - if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; - lua_assert(!ttisstring(p1) && !ttisnumber(p1)); +l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + const char *t = luaT_objtypename(L, o); + luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); +} + + +l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { + if (ttisstring(p1) || cvt2str(p1)) p1 = p2; luaG_typeerror(L, p1, "concatenate"); } -l_noret luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { - TValue temp; - if (luaV_tonumber(p1, &temp) == NULL) - p2 = p1; /* first operand is wrong */ - luaG_typeerror(L, p2, "perform arithmetic on"); +l_noret luaG_opinterror (lua_State *L, const TValue *p1, + const TValue *p2, const char *msg) { + lua_Number temp; + if (!tonumber(p1, &temp)) /* first operand is wrong? */ + p2 = p1; /* now second is wrong */ + luaG_typeerror(L, p2, msg); +} + + +/* +** Error when both values are convertible to numbers, but not to integers +*/ +l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { + lua_Integer temp; + if (!tointeger(p1, &temp)) + p2 = p1; + luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); } l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { - const char *t1 = objtypename(p1); - const char *t2 = objtypename(p2); - if (t1 == t2) + const char *t1 = luaT_objtypename(L, p1); + const char *t2 = luaT_objtypename(L, p2); + if (strcmp(t1, t2) == 0) luaG_runerror(L, "attempt to compare two %s values", t1); else luaG_runerror(L, "attempt to compare %s with %s", t1, t2); } -static void addinfo (lua_State *L, const char *msg) { - CallInfo *ci = L->ci; - if (isLua(ci)) { /* is Lua code? */ - char buff[LUA_IDSIZE]; /* add file:line information */ - int line = currentline(ci); - TString *src = ci_func(ci)->p->source; - if (src) - luaO_chunkid(buff, getstr(src), LUA_IDSIZE); - else { /* no source available; use "?" instead */ - buff[0] = '?'; buff[1] = '\0'; - } - luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); +/* add src:line information to 'msg' */ +const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, + int line) { + char buff[LUA_IDSIZE]; + if (src) + luaO_chunkid(buff, getstr(src), LUA_IDSIZE); + else { /* no source available; use "?" instead */ + buff[0] = '?'; buff[1] = '\0'; } + return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } l_noret luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); - if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ - L->top++; - luaD_call(L, L->top - 2, 1, 0); /* call it */ + L->top++; /* assume EXTRA_STACK */ + luaD_callnoyield(L, L->top - 2, 1); /* call it */ } luaD_throw(L, LUA_ERRRUN); } l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { + CallInfo *ci = L->ci; + const char *msg; va_list argp; va_start(argp, fmt); - addinfo(L, luaO_pushvfstring(L, fmt, argp)); + msg = luaO_pushvfstring(L, fmt, argp); /* format message */ va_end(argp); + if (isLua(ci)) /* if Lua function, add source:line information */ + luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci)); luaG_errormsg(L); } + +void luaG_traceexec (lua_State *L) { + CallInfo *ci = L->ci; + lu_byte mask = L->hookmask; + int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); + if (counthook) + resethookcount(L); /* reset count */ + else if (!(mask & LUA_MASKLINE)) + return; /* no line hook and count != 0; nothing to be done */ + if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ + return; /* do not call hook again (VM yielded, so it did not move) */ + } + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ + if (mask & LUA_MASKLINE) { + Proto *p = ci_func(ci)->p; + int npc = pcRel(ci->u.l.savedpc, p); + int newline = getfuncline(p, npc); + if (npc == 0 || /* call linehook when enter a new function, */ + ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ + newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ + luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ + } + L->oldpc = ci->u.l.savedpc; + if (L->status == LUA_YIELD) { /* did hook yield? */ + if (counthook) + L->hookcount = 1; /* undo decrement to zero */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ + ci->func = L->top - 1; /* protect stack below results */ + luaD_throw(L, LUA_YIELD); + } +} + diff --git a/depends/lua/src/ldo.c b/depends/lua/src/ldo.c index e9dd5fa95..8804c9977 100644 --- a/depends/lua/src/ldo.c +++ b/depends/lua/src/ldo.c @@ -1,17 +1,19 @@ /* -** $Id: ldo.c,v 2.108.1.3 2013/11/08 18:22:50 roberto Exp $ +** $Id: ldo.c,v 2.151 2015/12/16 16:40:07 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ +#define ldo_c +#define LUA_CORE + +#include "lprefix.h" + #include #include #include -#define ldo_c -#define LUA_CORE - #include "lua.h" #include "lapi.h" @@ -33,6 +35,8 @@ +#define errorstatus(s) ((s) > LUA_YIELD) + /* ** {====================================================== @@ -46,30 +50,33 @@ ** C++ code, with _longjmp/_setjmp when asked to use them, and with ** longjmp/setjmp otherwise. */ -#if !defined(LUAI_THROW) +#if !defined(LUAI_THROW) /* { */ + +#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */ -#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) \ try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } #define luai_jmpbuf int /* dummy variable */ -#elif defined(LUA_USE_ULONGJMP) -/* in Unix, try _longjmp/_setjmp (more efficient) */ +#elif defined(LUA_USE_POSIX) /* }{ */ + +/* in POSIX, try _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf -#else -/* default handling with long jumps */ +#else /* }{ */ + +/* ISO C handling with long jumps */ #define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf -#endif +#endif /* } */ -#endif +#endif /* } */ @@ -106,15 +113,19 @@ l_noret luaD_throw (lua_State *L, int errcode) { LUAI_THROW(L, L->errorJmp); /* jump to it */ } else { /* thread has no error handler */ + global_State *g = G(L); L->status = cast_byte(errcode); /* mark it as dead */ - if (G(L)->mainthread->errorJmp) { /* main thread has a handler? */ - setobjs2s(L, G(L)->mainthread->top++, L->top - 1); /* copy error obj. */ - luaD_throw(G(L)->mainthread, errcode); /* re-throw in main thread */ + if (g->mainthread->errorJmp) { /* main thread has a handler? */ + setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ + luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ } else { /* no handler at all; abort */ - if (G(L)->panic) { /* panic function? */ + if (g->panic) { /* panic function? */ + seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ + if (L->ci->top < L->top) + L->ci->top = L->top; /* pushing msg. can break this invariant */ lua_unlock(L); - G(L)->panic(L); /* call it (last chance to jump out) */ + g->panic(L); /* call panic function (last chance to jump out) */ } abort(); } @@ -139,12 +150,17 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { /* }====================================================== */ +/* +** {================================================================== +** Stack reallocation +** =================================================================== +*/ static void correctstack (lua_State *L, TValue *oldstack) { CallInfo *ci; - GCObject *up; + UpVal *up; L->top = (L->top - oldstack) + L->stack; - for (up = L->openupval; up != NULL; up = up->gch.next) - gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; + for (up = L->openupval; up != NULL; up = up->u.open.next) + up->v = (up->v - oldstack) + L->stack; for (ci = L->ci; ci != NULL; ci = ci->previous) { ci->top = (ci->top - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack; @@ -206,17 +222,34 @@ void luaD_shrinkstack (lua_State *L) { int inuse = stackinuse(L); int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; - if (inuse > LUAI_MAXSTACK || /* handling stack overflow? */ - goodsize >= L->stacksize) /* would grow instead of shrink? */ - condmovestack(L); /* don't change stack (change only for debugging) */ + if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */ + luaE_freeCI(L); /* free all CIs (list grew because of an error) */ else + luaE_shrinkCI(L); /* shrink list */ + if (inuse <= LUAI_MAXSTACK && /* not handling stack overflow? */ + goodsize < L->stacksize) /* trying to shrink? */ luaD_reallocstack(L, goodsize); /* shrink it */ + else + condmovestack(L,,); /* don't change stack (change only for debugging) */ } +void luaD_inctop (lua_State *L) { + luaD_checkstack(L, 1); + L->top++; +} + +/* }================================================================== */ + + +/* +** Call a hook for the given event. Make sure there is a hook to be +** called. (Both 'L->hook' and 'L->hookmask', which triggers this +** function, can be changed asynchronously by signals.) +*/ void luaD_hook (lua_State *L, int event, int line) { lua_Hook hook = L->hook; - if (hook && L->allowhook) { + if (hook && L->allowhook) { /* make sure there is a hook */ CallInfo *ci = L->ci; ptrdiff_t top = savestack(L, L->top); ptrdiff_t ci_top = savestack(L, ci->top); @@ -258,31 +291,34 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; int nfixargs = p->numparams; StkId base, fixed; - lua_assert(actual >= nfixargs); /* move fixed parameters to final position */ - luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */ fixed = L->top - actual; /* first fixed argument */ base = L->top; /* final position of first argument */ - for (i=0; itop++, fixed + i); - setnilvalue(fixed + i); + setnilvalue(fixed + i); /* erase original copy (for GC) */ } + for (; i < nfixargs; i++) + setnilvalue(L->top++); /* complete missing arguments */ return base; } -static StkId tryfuncTM (lua_State *L, StkId func) { +/* +** Check whether __call metafield of 'func' is a function. If so, put +** it in stack below original 'func' so that 'luaD_precall' can call +** it. Raise an error if __call metafield is not a function. +*/ +static void tryfuncTM (lua_State *L, StkId func) { const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; - ptrdiff_t funcr = savestack(L, func); if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); - /* Open a hole inside the stack at `func' */ - for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); - incr_top(L); - func = restorestack(L, funcr); /* previous call may change stack */ + /* Open a hole inside the stack at 'func' */ + for (p = L->top; p > func; p--) + setobjs2s(L, p, p-1); + L->top++; /* slot ensured by caller */ setobj2s(L, func, tm); /* tag method is the new function to be called */ - return func; } @@ -290,79 +326,133 @@ static StkId tryfuncTM (lua_State *L, StkId func) { #define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) +/* macro to check stack size, preserving 'p' */ +#define checkstackp(L,n,p) \ + luaD_checkstackaux(L, n, \ + ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ + luaC_checkGC(L), /* stack grow uses memory */ \ + p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ + + /* -** returns true if function has been executed (C function) +** Prepares a function call: checks the stack, creates a new CallInfo +** entry, fills in the relevant information, calls hook if needed. +** If function is a C function, does the call, too. (Otherwise, leave +** the execution ('luaV_execute') to the caller, to allow stackless +** calls.) Returns true iff function has been executed (C function). */ int luaD_precall (lua_State *L, StkId func, int nresults) { lua_CFunction f; CallInfo *ci; - int n; /* number of arguments (Lua) or returns (C) */ - ptrdiff_t funcr = savestack(L, func); switch (ttype(func)) { + case LUA_TCCL: /* C closure */ + f = clCvalue(func)->f; + goto Cfunc; case LUA_TLCF: /* light C function */ f = fvalue(func); - goto Cfunc; - case LUA_TCCL: { /* C closure */ - f = clCvalue(func)->f; - Cfunc: - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + Cfunc: { + int n; /* number of returns */ + checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ ci = next_ci(L); /* now 'enter' new function */ ci->nresults = nresults; - ci->func = restorestack(L, funcr); + ci->func = func; ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); ci->callstatus = 0; - luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) luaD_hook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*f)(L); /* do the actual call */ lua_lock(L); api_checknelems(L, n); - luaD_poscall(L, L->top - n); + luaD_poscall(L, ci, L->top - n, n); return 1; } case LUA_TLCL: { /* Lua function: prepare its call */ StkId base; Proto *p = clLvalue(func)->p; - n = cast_int(L->top - func) - 1; /* number of real arguments */ - luaD_checkstack(L, p->maxstacksize); - for (; n < p->numparams; n++) - setnilvalue(L->top++); /* complete missing arguments */ - if (!p->is_vararg) { - func = restorestack(L, funcr); + int n = cast_int(L->top - func) - 1; /* number of real arguments */ + int fsize = p->maxstacksize; /* frame size */ + checkstackp(L, fsize, func); + if (p->is_vararg != 1) { /* do not use vararg? */ + for (; n < p->numparams; n++) + setnilvalue(L->top++); /* complete missing arguments */ base = func + 1; } - else { + 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->nresults = nresults; ci->func = func; ci->u.l.base = base; - ci->top = base + p->maxstacksize; + L->top = ci->top = base + fsize; lua_assert(ci->top <= L->stack_last); ci->u.l.savedpc = p->code; /* starting point */ ci->callstatus = CIST_LUA; - L->top = ci->top; - luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) callhook(L, ci); return 0; } default: { /* not a function */ - func = tryfuncTM(L, func); /* retry with 'function' tag method */ + checkstackp(L, 1, func); /* ensure space for metamethod */ + tryfuncTM(L, func); /* try to get '__call' metamethod */ return luaD_precall(L, func, nresults); /* now it must be a function */ } } } -int luaD_poscall (lua_State *L, StkId firstResult) { +/* +** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'. +** Handle most typical cases (zero results for commands, one result for +** expressions, multiple results for tail calls/single parameters) +** separated. +*/ +static int moveresults (lua_State *L, const TValue *firstResult, StkId res, + int nres, int wanted) { + switch (wanted) { /* handle typical cases separately */ + case 0: break; /* nothing to move */ + case 1: { /* one result needed */ + if (nres == 0) /* no results? */ + firstResult = luaO_nilobject; /* adjust with nil */ + setobjs2s(L, res, firstResult); /* move it to proper place */ + break; + } + case LUA_MULTRET: { + int i; + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstResult + i); + L->top = res + nres; + return 0; /* wanted == LUA_MULTRET */ + } + default: { + int i; + if (wanted <= nres) { /* enough results? */ + for (i = 0; i < wanted; i++) /* move wanted results to correct place */ + setobjs2s(L, res + i, firstResult + i); + } + else { /* not enough results; use all of them plus nils */ + for (i = 0; i < nres; i++) /* move all results to correct place */ + setobjs2s(L, res + i, firstResult + i); + for (; i < wanted; i++) /* complete wanted number of results */ + setnilvalue(res + i); + } + break; + } + } + L->top = res + wanted; /* top points after the last result */ + return 1; +} + + +/* +** Finishes a function call: calls hook if necessary, removes CallInfo, +** moves current number of results to proper place; returns 0 iff call +** wanted multiple (variable number of) results. +*/ +int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { StkId res; - int wanted, i; - CallInfo *ci = L->ci; + int wanted = ci->nresults; if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { if (L->hookmask & LUA_MASKRET) { ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ @@ -372,15 +462,24 @@ int luaD_poscall (lua_State *L, StkId firstResult) { L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ } res = ci->func; /* res == final position of 1st result */ - wanted = ci->nresults; - L->ci = ci = ci->previous; /* back to caller */ - /* move results to correct place */ - for (i = wanted; i != 0 && firstResult < L->top; i--) - setobjs2s(L, res++, firstResult++); - while (i-- > 0) - setnilvalue(res++); - L->top = res; - return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ + L->ci = ci->previous; /* back to caller */ + /* move results to proper place */ + return moveresults(L, firstResult, res, nres, wanted); +} + + +/* +** Check appropriate error for stack overflow ("regular" overflow or +** overflow while handling stack overflow). If 'nCalls' is larger than +** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but +** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to +** allow overflow handling to work) +*/ +static void stackerror (lua_State *L) { + if (L->nCcalls == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } @@ -390,53 +489,67 @@ int luaD_poscall (lua_State *L, StkId firstResult) { ** When returns, all the results are on the stack, starting at the original ** function position. */ -void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { - if (++L->nCcalls >= LUAI_MAXCCALLS) { - if (L->nCcalls == LUAI_MAXCCALLS) - luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) - luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ - } - if (!allowyield) L->nny++; +void luaD_call (lua_State *L, StkId func, int nResults) { + if (++L->nCcalls >= LUAI_MAXCCALLS) + stackerror(L); if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ luaV_execute(L); /* call it */ - if (!allowyield) L->nny--; L->nCcalls--; } -static void finishCcall (lua_State *L) { +/* +** Similar to 'luaD_call', but does not allow yields during the call +*/ +void luaD_callnoyield (lua_State *L, StkId func, int nResults) { + L->nny++; + luaD_call(L, func, nResults); + L->nny--; +} + + +/* +** Completes the execution of an interrupted C function, calling its +** continuation function. +*/ +static void finishCcall (lua_State *L, int status) { CallInfo *ci = L->ci; int n; - lua_assert(ci->u.c.k != NULL); /* must have a continuation */ - lua_assert(L->nny == 0); + /* must have a continuation and must be able to call it */ + lua_assert(ci->u.c.k != NULL && L->nny == 0); + /* error status can only happen in a protected call */ + lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ L->errfunc = ci->u.c.old_errfunc; } - /* finish 'lua_callk'/'lua_pcall' */ + /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already + handled */ adjustresults(L, ci->nresults); /* call continuation function */ - if (!(ci->callstatus & CIST_STAT)) /* no call status? */ - ci->u.c.status = LUA_YIELD; /* 'default' status */ - lua_assert(ci->u.c.status != LUA_OK); - ci->callstatus = (ci->callstatus & ~(CIST_YPCALL | CIST_STAT)) | CIST_YIELDED; lua_unlock(L); - n = (*ci->u.c.k)(L); + n = (*ci->u.c.k)(L, status, ci->u.c.ctx); lua_lock(L); api_checknelems(L, n); /* finish 'luaD_precall' */ - luaD_poscall(L, L->top - n); + luaD_poscall(L, ci, L->top - n, n); } +/* +** Executes "full continuation" (everything in the stack) of a +** previously interrupted coroutine until the stack is empty (or another +** interruption long-jumps out of the loop). If the coroutine is +** recovering from an error, 'ud' points to the error status, which must +** be passed to the first continuation function (otherwise the default +** status is LUA_YIELD). +*/ static void unroll (lua_State *L, void *ud) { - UNUSED(ud); - for (;;) { - if (L->ci == &L->base_ci) /* stack is empty? */ - return; /* coroutine finished normally */ + if (ud != NULL) /* error status? */ + finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ + while (L->ci != &L->base_ci) { /* something in the stack */ if (!isLua(L->ci)) /* C function? */ - finishCcall(L); + finishCcall(L, LUA_YIELD); /* complete its execution */ else { /* Lua function */ luaV_finishOp(L); /* finish interrupted instruction */ luaV_execute(L); /* execute down to higher C 'boundary' */ @@ -446,7 +559,8 @@ static void unroll (lua_State *L, void *ud) { /* -** check whether thread has a suspended protected call +** Try to find a suspended protected call (a "recover point") for the +** given thread. */ static CallInfo *findpcall (lua_State *L) { CallInfo *ci; @@ -458,6 +572,11 @@ static CallInfo *findpcall (lua_State *L) { } +/* +** Recovers from an error in a coroutine. Finds a recover point (if +** there is one) and completes the execution of the interrupted +** 'luaD_pcall'. If there is no recover point, returns zero. +*/ static int recover (lua_State *L, int status) { StkId oldtop; CallInfo *ci = findpcall(L); @@ -467,12 +586,10 @@ static int recover (lua_State *L, int status) { luaF_close(L, oldtop); seterrorobj(L, status, oldtop); L->ci = ci; - L->allowhook = ci->u.c.old_allowhook; + L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ L->nny = 0; /* should be zero to be yieldable */ luaD_shrinkstack(L); L->errfunc = ci->u.c.old_errfunc; - ci->callstatus |= CIST_STAT; /* call has error status */ - ci->u.c.status = status; /* (here it is) */ return 1; /* continue running the coroutine */ } @@ -491,11 +608,16 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { /* -** do the work for 'lua_resume' in protected mode +** Do the work for 'lua_resume' in protected mode. Most of the work +** depends on the status of the coroutine: initial state, suspended +** inside a hook, or regularly suspended (optionally with a continuation +** function), plus erroneous cases: non-suspended coroutine or dead +** coroutine. */ static void resume (lua_State *L, void *ud) { int nCcalls = L->nCcalls; - StkId firstArg = cast(StkId, ud); + int n = *(cast(int*, ud)); /* number of arguments */ + StkId firstArg = L->top - n; /* first argument */ CallInfo *ci = L->ci; if (nCcalls >= LUAI_MAXCCALLS) resume_error(L, "C stack overflow", firstArg); @@ -509,24 +631,21 @@ static void resume (lua_State *L, void *ud) { else if (L->status != LUA_YIELD) resume_error(L, "cannot resume dead coroutine", firstArg); else { /* resuming from previous yield */ - L->status = LUA_OK; + L->status = LUA_OK; /* mark that it is running (again) */ ci->func = restorestack(L, ci->extra); if (isLua(ci)) /* yielded inside a hook? */ luaV_execute(L); /* just continue running Lua code */ else { /* 'common' yield */ - if (ci->u.c.k != NULL) { /* does it have a continuation? */ - int n; - ci->u.c.status = LUA_YIELD; /* 'default' status */ - ci->callstatus |= CIST_YIELDED; + if (ci->u.c.k != NULL) { /* does it have a continuation function? */ lua_unlock(L); - n = (*ci->u.c.k)(L); /* call continuation */ + n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ lua_lock(L); api_checknelems(L, n); firstArg = L->top - n; /* yield results come from continuation */ } - luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ + luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ } - unroll(L, NULL); + unroll(L, NULL); /* run continuation */ } lua_assert(nCcalls == L->nCcalls); } @@ -534,27 +653,26 @@ static void resume (lua_State *L, void *ud) { LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { int status; - int oldnny = L->nny; /* save 'nny' */ + unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ lua_lock(L); luai_userstateresume(L, nargs); L->nCcalls = (from) ? from->nCcalls + 1 : 1; L->nny = 0; /* allow yields */ api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); - status = luaD_rawrunprotected(L, resume, L->top - nargs); + status = luaD_rawrunprotected(L, resume, &nargs); if (status == -1) /* error calling 'lua_resume'? */ status = LUA_ERRRUN; - else { /* yield or regular error */ - while (status != LUA_OK && status != LUA_YIELD) { /* error? */ - if (recover(L, status)) /* recover point? */ - status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */ - else { /* unrecoverable error */ - L->status = cast_byte(status); /* mark thread as `dead' */ - seterrorobj(L, status, L->top); - L->ci->top = L->top; - break; - } + else { /* continue running after recoverable errors */ + while (errorstatus(status) && recover(L, status)) { + /* unroll continuation */ + status = luaD_rawrunprotected(L, unroll, &status); } - lua_assert(status == L->status); + if (errorstatus(status)) { /* unrecoverable error? */ + L->status = cast_byte(status); /* mark thread as 'dead' */ + seterrorobj(L, status, L->top); /* push error message */ + L->ci->top = L->top; + } + else lua_assert(status == L->status); /* normal end or yield */ } L->nny = oldnny; /* restore 'nny' */ L->nCcalls--; @@ -564,7 +682,13 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { } -LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { +LUA_API int lua_isyieldable (lua_State *L) { + return (L->nny == 0); +} + + +LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k) { CallInfo *ci = L->ci; luai_userstateyield(L, nresults); lua_lock(L); @@ -619,7 +743,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, /* ** Execute a protected parser. */ -struct SParser { /* data to `f_parser' */ +struct SParser { /* data to 'f_parser' */ ZIO *z; Mbuffer buff; /* dynamic structure used by the scanner */ Dyndata dyd; /* dynamic structures used by the parser */ @@ -631,31 +755,26 @@ struct SParser { /* data to `f_parser' */ static void checkmode (lua_State *L, const char *mode, const char *x) { if (mode && strchr(mode, x[0]) == NULL) { luaO_pushfstring(L, - "attempt to load a %s chunk (mode is " LUA_QS ")", x, mode); + "attempt to load a %s chunk (mode is '%s')", x, mode); luaD_throw(L, LUA_ERRSYNTAX); } } static void f_parser (lua_State *L, void *ud) { - int i; - Closure *cl; + LClosure *cl; struct SParser *p = cast(struct SParser *, ud); int c = zgetc(p->z); /* read first character */ if (c == LUA_SIGNATURE[0]) { checkmode(L, p->mode, "binary"); - cl = luaU_undump(L, p->z, &p->buff, p->name); + cl = luaU_undump(L, p->z, p->name); } else { checkmode(L, p->mode, "text"); cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); } - lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); - for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */ - UpVal *up = luaF_newupval(L); - cl->l.upvals[i] = up; - luaC_objbarrier(L, cl, up); - } + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luaF_initupvals(L, cl); } diff --git a/depends/lua/src/ldump.c b/depends/lua/src/ldump.c index 61fa2cd89..016e30082 100644 --- a/depends/lua/src/ldump.c +++ b/depends/lua/src/ldump.c @@ -1,173 +1,215 @@ /* -** $Id: ldump.c,v 2.17.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ -#include - #define ldump_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "lobject.h" #include "lstate.h" #include "lundump.h" + typedef struct { - lua_State* L; - lua_Writer writer; - void* data; - int strip; - int status; + lua_State *L; + lua_Writer writer; + void *data; + int strip; + int status; } DumpState; -#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D) -#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D) - -static void DumpBlock(const void* b, size_t size, DumpState* D) -{ - if (D->status==0) - { - lua_unlock(D->L); - D->status=(*D->writer)(D->L,b,size,D->data); - lua_lock(D->L); - } + +/* +** All high-level dumps go through DumpVector; you can change it to +** change the endianness of the result +*/ +#define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) + +#define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) + + +static void DumpBlock (const void *b, size_t size, DumpState *D) { + if (D->status == 0 && size > 0) { + lua_unlock(D->L); + D->status = (*D->writer)(D->L, b, size, D->data); + lua_lock(D->L); + } } -static void DumpChar(int y, DumpState* D) -{ - char x=(char)y; - DumpVar(x,D); + +#define DumpVar(x,D) DumpVector(&x,1,D) + + +static void DumpByte (int y, DumpState *D) { + lu_byte x = (lu_byte)y; + DumpVar(x, D); } -static void DumpInt(int x, DumpState* D) -{ - DumpVar(x,D); + +static void DumpInt (int x, DumpState *D) { + DumpVar(x, D); } -static void DumpNumber(lua_Number x, DumpState* D) -{ - DumpVar(x,D); + +static void DumpNumber (lua_Number x, DumpState *D) { + DumpVar(x, D); } -static void DumpVector(const void* b, int n, size_t size, DumpState* D) -{ - DumpInt(n,D); - DumpMem(b,n,size,D); + +static void DumpInteger (lua_Integer x, DumpState *D) { + DumpVar(x, D); } -static void DumpString(const TString* s, DumpState* D) -{ - if (s==NULL) - { - size_t size=0; - DumpVar(size,D); - } - else - { - size_t size=s->tsv.len+1; /* include trailing '\0' */ - DumpVar(size,D); - DumpBlock(getstr(s),size*sizeof(char),D); - } + +static void DumpString (const TString *s, DumpState *D) { + if (s == NULL) + DumpByte(0, D); + else { + size_t size = tsslen(s) + 1; /* include trailing '\0' */ + const char *str = getstr(s); + if (size < 0xFF) + DumpByte(cast_int(size), D); + else { + DumpByte(0xFF, D); + DumpVar(size, D); + } + DumpVector(str, size - 1, D); /* no need to save '\0' */ + } } -#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D) - -static void DumpFunction(const Proto* f, DumpState* D); - -static void DumpConstants(const Proto* f, DumpState* D) -{ - int i,n=f->sizek; - DumpInt(n,D); - for (i=0; ik[i]; - DumpChar(ttypenv(o),D); - switch (ttypenv(o)) - { - case LUA_TNIL: - break; - case LUA_TBOOLEAN: - DumpChar(bvalue(o),D); - break; - case LUA_TNUMBER: - DumpNumber(nvalue(o),D); - break; - case LUA_TSTRING: - DumpString(rawtsvalue(o),D); - break; - default: lua_assert(0); + +static void DumpCode (const Proto *f, DumpState *D) { + DumpInt(f->sizecode, D); + DumpVector(f->code, f->sizecode, D); +} + + +static void DumpFunction(const Proto *f, TString *psource, DumpState *D); + +static void DumpConstants (const Proto *f, DumpState *D) { + int i; + int n = f->sizek; + DumpInt(n, D); + for (i = 0; i < n; i++) { + const TValue *o = &f->k[i]; + DumpByte(ttype(o), D); + switch (ttype(o)) { + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpByte(bvalue(o), D); + break; + case LUA_TNUMFLT: + DumpNumber(fltvalue(o), D); + break; + case LUA_TNUMINT: + DumpInteger(ivalue(o), D); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + DumpString(tsvalue(o), D); + break; + default: + lua_assert(0); + } } - } - n=f->sizep; - DumpInt(n,D); - for (i=0; ip[i],D); } -static void DumpUpvalues(const Proto* f, DumpState* D) -{ - int i,n=f->sizeupvalues; - DumpInt(n,D); - for (i=0; iupvalues[i].instack,D); - DumpChar(f->upvalues[i].idx,D); - } + +static void DumpProtos (const Proto *f, DumpState *D) { + int i; + int n = f->sizep; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpFunction(f->p[i], f->source, D); +} + + +static void DumpUpvalues (const Proto *f, DumpState *D) { + int i, n = f->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) { + DumpByte(f->upvalues[i].instack, D); + DumpByte(f->upvalues[i].idx, D); + } } -static void DumpDebug(const Proto* f, DumpState* D) -{ - int i,n; - DumpString((D->strip) ? NULL : f->source,D); - n= (D->strip) ? 0 : f->sizelineinfo; - DumpVector(f->lineinfo,n,sizeof(int),D); - n= (D->strip) ? 0 : f->sizelocvars; - DumpInt(n,D); - for (i=0; ilocvars[i].varname,D); - DumpInt(f->locvars[i].startpc,D); - DumpInt(f->locvars[i].endpc,D); - } - n= (D->strip) ? 0 : f->sizeupvalues; - DumpInt(n,D); - for (i=0; iupvalues[i].name,D); + +static void DumpDebug (const Proto *f, DumpState *D) { + int i, n; + n = (D->strip) ? 0 : f->sizelineinfo; + DumpInt(n, D); + DumpVector(f->lineinfo, n, D); + n = (D->strip) ? 0 : f->sizelocvars; + DumpInt(n, D); + for (i = 0; i < n; i++) { + DumpString(f->locvars[i].varname, D); + DumpInt(f->locvars[i].startpc, D); + DumpInt(f->locvars[i].endpc, D); + } + n = (D->strip) ? 0 : f->sizeupvalues; + DumpInt(n, D); + for (i = 0; i < n; i++) + DumpString(f->upvalues[i].name, D); } -static void DumpFunction(const Proto* f, DumpState* D) -{ - DumpInt(f->linedefined,D); - DumpInt(f->lastlinedefined,D); - DumpChar(f->numparams,D); - DumpChar(f->is_vararg,D); - DumpChar(f->maxstacksize,D); - DumpCode(f,D); - DumpConstants(f,D); - DumpUpvalues(f,D); - DumpDebug(f,D); + +static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { + if (D->strip || f->source == psource) + DumpString(NULL, D); /* no debug info or same source as its parent */ + else + DumpString(f->source, D); + DumpInt(f->linedefined, D); + DumpInt(f->lastlinedefined, D); + DumpByte(f->numparams, D); + DumpByte(f->is_vararg, D); + DumpByte(f->maxstacksize, D); + DumpCode(f, D); + DumpConstants(f, D); + DumpUpvalues(f, D); + DumpProtos(f, D); + DumpDebug(f, D); } -static void DumpHeader(DumpState* D) -{ - lu_byte h[LUAC_HEADERSIZE]; - luaU_header(h); - DumpBlock(h,LUAC_HEADERSIZE,D); + +static void DumpHeader (DumpState *D) { + DumpLiteral(LUA_SIGNATURE, D); + DumpByte(LUAC_VERSION, D); + DumpByte(LUAC_FORMAT, D); + DumpLiteral(LUAC_DATA, D); + DumpByte(sizeof(int), D); + DumpByte(sizeof(size_t), D); + DumpByte(sizeof(Instruction), D); + DumpByte(sizeof(lua_Integer), D); + DumpByte(sizeof(lua_Number), D); + DumpInteger(LUAC_INT, D); + DumpNumber(LUAC_NUM, D); } + /* ** dump Lua function as precompiled chunk */ -int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip) -{ - DumpState D; - D.L=L; - D.writer=w; - D.data=data; - D.strip=strip; - D.status=0; - DumpHeader(&D); - DumpFunction(f,&D); - return D.status; +int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, + int strip) { + DumpState D; + D.L = L; + D.writer = w; + D.data = data; + D.strip = strip; + D.status = 0; + DumpHeader(&D); + DumpByte(f->sizeupvalues, &D); + DumpFunction(f, NULL, &D); + return D.status; } + diff --git a/depends/lua/src/lfunc.c b/depends/lua/src/lfunc.c index e90e1520c..67967dab3 100644 --- a/depends/lua/src/lfunc.c +++ b/depends/lua/src/lfunc.c @@ -1,15 +1,17 @@ /* -** $Id: lfunc.c,v 2.30.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ - -#include - #define lfunc_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "lfunc.h" @@ -20,95 +22,83 @@ -Closure *luaF_newCclosure (lua_State *L, int n) { - Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl; - c->c.nupvalues = cast_byte(n); +CClosure *luaF_newCclosure (lua_State *L, int n) { + GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); + CClosure *c = gco2ccl(o); + c->nupvalues = cast_byte(n); return c; } -Closure *luaF_newLclosure (lua_State *L, int n) { - Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl; - c->l.p = NULL; - c->l.nupvalues = cast_byte(n); - while (n--) c->l.upvals[n] = NULL; +LClosure *luaF_newLclosure (lua_State *L, int n) { + GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); + LClosure *c = gco2lcl(o); + c->p = NULL; + c->nupvalues = cast_byte(n); + while (n--) c->upvals[n] = NULL; return c; } - -UpVal *luaF_newupval (lua_State *L) { - UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv; - uv->v = &uv->u.value; - setnilvalue(uv->v); - return uv; +/* +** fill a closure with new closed upvalues +*/ +void luaF_initupvals (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + UpVal *uv = luaM_new(L, UpVal); + uv->refcount = 1; + uv->v = &uv->u.value; /* make it closed */ + setnilvalue(uv->v); + cl->upvals[i] = uv; + } } UpVal *luaF_findupval (lua_State *L, StkId level) { - global_State *g = G(L); - GCObject **pp = &L->openupval; + UpVal **pp = &L->openupval; UpVal *p; UpVal *uv; - while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { - GCObject *o = obj2gco(p); - lua_assert(p->v != &p->u.value); - lua_assert(!isold(o) || isold(obj2gco(L))); - if (p->v == level) { /* found a corresponding upvalue? */ - if (isdead(g, o)) /* is it dead? */ - changewhite(o); /* resurrect it */ - return p; - } - pp = &p->next; + lua_assert(isintwups(L) || L->openupval == NULL); + while (*pp != NULL && (p = *pp)->v >= level) { + lua_assert(upisopen(p)); + if (p->v == level) /* found a corresponding upvalue? */ + return p; /* return it */ + pp = &p->u.open.next; } - /* not found: create a new one */ - uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv; + /* not found: create a new upvalue */ + uv = luaM_new(L, UpVal); + uv->refcount = 0; + uv->u.open.next = *pp; /* link it to list of open upvalues */ + uv->u.open.touched = 1; + *pp = uv; uv->v = level; /* current value lives in the stack */ - uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */ - uv->u.l.next = g->uvhead.u.l.next; - uv->u.l.next->u.l.prev = uv; - g->uvhead.u.l.next = uv; - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ + L->twups = G(L)->twups; /* link it to the list */ + G(L)->twups = L; + } return uv; } -static void unlinkupval (UpVal *uv) { - lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); - uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */ - uv->u.l.prev->u.l.next = uv->u.l.next; -} - - -void luaF_freeupval (lua_State *L, UpVal *uv) { - if (uv->v != &uv->u.value) /* is it open? */ - unlinkupval(uv); /* remove from open list */ - luaM_free(L, uv); /* free upvalue */ -} - - void luaF_close (lua_State *L, StkId level) { UpVal *uv; - global_State *g = G(L); - while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) { - GCObject *o = obj2gco(uv); - lua_assert(!isblack(o) && uv->v != &uv->u.value); - L->openupval = uv->next; /* remove from `open' list */ - if (isdead(g, o)) - luaF_freeupval(L, uv); /* free upvalue */ + while (L->openupval != NULL && (uv = L->openupval)->v >= level) { + lua_assert(upisopen(uv)); + L->openupval = uv->u.open.next; /* remove from 'open' list */ + if (uv->refcount == 0) /* no references? */ + luaM_free(L, uv); /* free upvalue */ else { - unlinkupval(uv); /* remove upvalue from 'uvhead' list */ setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ uv->v = &uv->u.value; /* now current value lives here */ - gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */ - g->allgc = o; - luaC_checkupvalcolor(g, uv); + luaC_upvalbarrier(L, uv); } } } Proto *luaF_newproto (lua_State *L) { - Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p; + GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); + Proto *f = gco2p(o); f->k = NULL; f->sizek = 0; f->p = NULL; @@ -144,7 +134,7 @@ void luaF_freeproto (lua_State *L, Proto *f) { /* -** Look for n-th local variable at line `line' in function `func'. +** Look for n-th local variable at line 'line' in function 'func'. ** Returns NULL if not found. */ const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { diff --git a/depends/lua/src/lgc.c b/depends/lua/src/lgc.c index 52460dcdd..7c29fb030 100644 --- a/depends/lua/src/lgc.c +++ b/depends/lua/src/lgc.c @@ -1,14 +1,17 @@ /* -** $Id: lgc.c,v 2.140.1.2 2013/04/26 18:22:05 roberto Exp $ +** $Id: lgc.c,v 2.212 2016/03/31 19:02:03 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ -#include - #define lgc_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "ldebug.h" @@ -23,6 +26,11 @@ #include "ltm.h" +/* +** internal state for collector while inside the atomic phase. The +** collector should never be in this state while running regular code. +*/ +#define GCSinsideatomic (GCSpause + 1) /* ** cost of sweeping one element (the size of a small object divided @@ -33,8 +41,8 @@ /* maximum number of elements to sweep in each single step */ #define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) -/* maximum number of finalizers to call in each GC step */ -#define GCFINALIZENUM 4 +/* cost of calling one finalizer */ +#define GCFINALIZECOST GCSWEEPCOST /* @@ -52,18 +60,18 @@ /* -** 'makewhite' erases all color bits plus the old bit and then -** sets only the current white bit +** 'makewhite' erases all color bits then sets only the current white +** bit */ -#define maskcolors (~(bit2mask(BLACKBIT, OLDBIT) | WHITEBITS)) +#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) #define makewhite(g,x) \ - (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) + (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) -#define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) -#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) +#define white2gray(x) resetbits(x->marked, WHITEBITS) +#define black2gray(x) resetbit(x->marked, BLACKBIT) -#define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT) +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) #define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) @@ -75,8 +83,13 @@ #define markvalue(g,o) { checkconsistency(o); \ if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } -#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ - reallymarkobject(g, obj2gco(t)); } +#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } + +/* +** mark an object that can be NULL (either because it is really optional, +** or it was stripped as debug info, or inside an uncompleted structure) +*/ +#define markobjectN(g,t) { if (t) markobject(g,t); } static void reallymarkobject (global_State *g, GCObject *o); @@ -95,33 +108,38 @@ static void reallymarkobject (global_State *g, GCObject *o); /* -** link table 'h' into list pointed by 'p' +** link collectable object 'o' into list pointed by 'p' */ -#define linktable(h,p) ((h)->gclist = *(p), *(p) = obj2gco(h)) +#define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o)) /* -** if key is not marked, mark its entry as dead (therefore removing it -** from the table) +** If key is not marked, mark its entry as dead. This allows key to be +** collected, but keeps its entry in the table. A dead node is needed +** when Lua looks up for a key (it may be part of a chain) and when +** traversing a weak table (key might be removed from the table during +** traversal). Other places never manipulate dead keys, because its +** associated nil value is enough to signal that the entry is logically +** empty. */ static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); if (valiswhite(gkey(n))) - setdeadvalue(gkey(n)); /* unused and unmarked key; remove it */ + setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */ } /* ** tells whether a key or value can be cleared from a weak ** table. Non-collectable objects are never removed from weak -** tables. Strings behave as `values', so are never removed too. for +** tables. Strings behave as 'values', so are never removed too. for ** other objects: if really collected, cannot keep them; for objects ** being finalized, keep them in keys, but not in values */ static int iscleared (global_State *g, const TValue *o) { if (!iscollectable(o)) return 0; else if (ttisstring(o)) { - markobject(g, rawtsvalue(o)); /* strings are `values', so are never weak */ + markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */ return 0; } else return iswhite(gcvalue(o)); @@ -130,14 +148,14 @@ static int iscleared (global_State *g, const TValue *o) { /* ** barrier that moves collector forward, that is, mark the white object -** being pointed by a black object. +** being pointed by a black object. (If in sweep phase, clear the black +** object to white [sweep it] to avoid other barrier calls for this +** same object.) */ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcstate != GCSpause); - lua_assert(gch(o)->tt != LUA_TTABLE); - if (keepinvariantout(g)) /* must keep invariant? */ + if (keepinvariant(g)) /* must keep invariant? */ reallymarkobject(g, v); /* restore invariant */ else { /* sweep phase */ lua_assert(issweepphase(g)); @@ -148,78 +166,52 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { /* ** barrier that moves collector backward, that is, mark the black object -** pointing to a white object as gray again. (Current implementation -** only works for tables; access to 'gclist' is not uniform across -** different types.) +** pointing to a white object as gray again. */ -void luaC_barrierback_ (lua_State *L, GCObject *o) { +void luaC_barrierback_ (lua_State *L, Table *t) { global_State *g = G(L); - lua_assert(isblack(o) && !isdead(g, o) && gch(o)->tt == LUA_TTABLE); - black2gray(o); /* make object gray (again) */ - gco2t(o)->gclist = g->grayagain; - g->grayagain = o; + lua_assert(isblack(t) && !isdead(g, t)); + black2gray(t); /* make table gray (again) */ + linkgclist(t, g->grayagain); } /* -** barrier for prototypes. When creating first closure (cache is -** NULL), use a forward barrier; this may be the only closure of the -** prototype (if it is a "regular" function, with a single instance) -** and the prototype may be big, so it is better to avoid traversing -** it again. Otherwise, use a backward barrier, to avoid marking all -** possible instances. +** barrier for assignments to closed upvalues. Because upvalues are +** shared among closures, it is impossible to know the color of all +** closures pointing to it. So, we assume that the object being assigned +** must be marked. */ -LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c) { +void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { global_State *g = G(L); - lua_assert(isblack(obj2gco(p))); - if (p->cache == NULL) { /* first time? */ - luaC_objbarrier(L, p, c); - } - else { /* use a backward barrier */ - black2gray(obj2gco(p)); /* make prototype gray (again) */ - p->gclist = g->grayagain; - g->grayagain = obj2gco(p); - } + GCObject *o = gcvalue(uv->v); + lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ + if (keepinvariant(g)) + markobject(g, o); } -/* -** check color (and invariants) for an upvalue that was closed, -** i.e., moved into the 'allgc' list -*/ -void luaC_checkupvalcolor (global_State *g, UpVal *uv) { - GCObject *o = obj2gco(uv); - lua_assert(!isblack(o)); /* open upvalues are never black */ - if (isgray(o)) { - if (keepinvariant(g)) { - resetoldbit(o); /* see MOVE OLD rule */ - gray2black(o); /* it is being visited now */ - markvalue(g, uv->v); - } - else { - lua_assert(issweepphase(g)); - makewhite(g, o); - } - } +void luaC_fix (lua_State *L, GCObject *o) { + global_State *g = G(L); + lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ + white2gray(o); /* they will be gray forever */ + g->allgc = o->next; /* remove object from 'allgc' list */ + o->next = g->fixedgc; /* link it to 'fixedgc' list */ + g->fixedgc = o; } /* ** create a new collectable object (with given type and size) and link -** it to '*list'. 'offset' tells how many bytes to allocate before the -** object itself (used only by states). +** it to 'allgc' list. */ -GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, - int offset) { +GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { global_State *g = G(L); - char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz)); - GCObject *o = obj2gco(raw + offset); - if (list == NULL) - list = &g->allgc; /* standard list for collectable objects */ - gch(o)->marked = luaC_white(g); - gch(o)->tt = tt; - gch(o)->next = *list; - *list = o; + GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); + o->marked = luaC_white(g); + o->tt = tt; + o->next = g->allgc; + g->allgc = o; return o; } @@ -241,57 +233,53 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, ** upvalues are already linked in 'headuv' list.) */ static void reallymarkobject (global_State *g, GCObject *o) { - lu_mem size; + reentry: white2gray(o); - switch (gch(o)->tt) { - case LUA_TSHRSTR: - case LUA_TLNGSTR: { - size = sizestring(gco2ts(o)); - break; /* nothing else to mark; make it black */ + switch (o->tt) { + case LUA_TSHRSTR: { + gray2black(o); + g->GCmemtrav += sizelstring(gco2ts(o)->shrlen); + break; } - case LUA_TUSERDATA: { - Table *mt = gco2u(o)->metatable; - markobject(g, mt); - markobject(g, gco2u(o)->env); - size = sizeudata(gco2u(o)); + case LUA_TLNGSTR: { + gray2black(o); + g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen); break; } - case LUA_TUPVAL: { - UpVal *uv = gco2uv(o); - markvalue(g, uv->v); - if (uv->v != &uv->u.value) /* open? */ - return; /* open upvalues remain gray */ - size = sizeof(UpVal); + case LUA_TUSERDATA: { + TValue uvalue; + markobjectN(g, gco2u(o)->metatable); /* mark its metatable */ + gray2black(o); + g->GCmemtrav += sizeudata(gco2u(o)); + getuservalue(g->mainthread, gco2u(o), &uvalue); + if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */ + o = gcvalue(&uvalue); + goto reentry; + } break; } case LUA_TLCL: { - gco2lcl(o)->gclist = g->gray; - g->gray = o; - return; + linkgclist(gco2lcl(o), g->gray); + break; } case LUA_TCCL: { - gco2ccl(o)->gclist = g->gray; - g->gray = o; - return; + linkgclist(gco2ccl(o), g->gray); + break; } case LUA_TTABLE: { - linktable(gco2t(o), &g->gray); - return; + linkgclist(gco2t(o), g->gray); + break; } case LUA_TTHREAD: { - gco2th(o)->gclist = g->gray; - g->gray = o; - return; + linkgclist(gco2th(o), g->gray); + break; } case LUA_TPROTO: { - gco2p(o)->gclist = g->gray; - g->gray = o; - return; + linkgclist(gco2p(o), g->gray); + break; } - default: lua_assert(0); return; + default: lua_assert(0); break; } - gray2black(o); - g->GCmemtrav += size; } @@ -301,7 +289,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { static void markmt (global_State *g) { int i; for (i=0; i < LUA_NUMTAGS; i++) - markobject(g, g->mt[i]); + markobjectN(g, g->mt[i]); } @@ -310,29 +298,41 @@ static void markmt (global_State *g) { */ static void markbeingfnz (global_State *g) { GCObject *o; - for (o = g->tobefnz; o != NULL; o = gch(o)->next) { - makewhite(g, o); - reallymarkobject(g, o); - } + for (o = g->tobefnz; o != NULL; o = o->next) + markobject(g, o); } /* -** mark all values stored in marked open upvalues. (See comment in -** 'lstate.h'.) +** Mark all values stored in marked open upvalues from non-marked threads. +** (Values from marked threads were already marked when traversing the +** thread.) Remove from the list threads that no longer have upvalues and +** not-marked threads. */ static void remarkupvals (global_State *g) { - UpVal *uv; - for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { - if (isgray(obj2gco(uv))) - markvalue(g, uv->v); + lua_State *thread; + lua_State **p = &g->twups; + while ((thread = *p) != NULL) { + lua_assert(!isblack(thread)); /* threads are never black */ + if (isgray(thread) && thread->openupval != NULL) + p = &thread->twups; /* keep marked thread with upvalues in the list */ + else { /* thread is not marked or without upvalues */ + UpVal *uv; + *p = thread->twups; /* remove thread from the list */ + thread->twups = thread; /* mark that it is out of list */ + for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { + if (uv->u.open.touched) { + markvalue(g, uv->v); /* remark upvalue's value */ + uv->u.open.touched = 0; + } + } + } } } /* -** mark root set and reset all gray lists, to start a new -** incremental (or full) collection +** mark root set and reset all gray lists, to start a new collection */ static void restartcollection (global_State *g) { g->gray = g->grayagain = NULL; @@ -352,12 +352,18 @@ static void restartcollection (global_State *g) { ** ======================================================= */ +/* +** Traverse a table with weak values and link it to proper list. During +** propagate phase, keep it in 'grayagain' list, to be revisited in the +** atomic phase. In the atomic phase, if table has any white value, +** put it in 'weak' list, to be cleared. +*/ static void traverseweakvalue (global_State *g, Table *h) { Node *n, *limit = gnodelast(h); - /* if there is array part, assume it may have white values (do not - traverse it just to check) */ + /* if there is array part, assume it may have white values (it is not + worth traversing it now just to check) */ int hasclears = (h->sizearray > 0); - for (n = gnode(h, 0); n < limit; n++) { + for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ @@ -368,20 +374,30 @@ static void traverseweakvalue (global_State *g, Table *h) { hasclears = 1; /* table will have to be cleared */ } } - if (hasclears) - linktable(h, &g->weak); /* has to be cleared later */ - else /* no white values */ - linktable(h, &g->grayagain); /* no need to clean */ + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasclears) + linkgclist(h, g->weak); /* has to be cleared later */ } +/* +** Traverse an ephemeron table and link it to proper list. Returns true +** iff any object was marked during this traversal (which implies that +** convergence has to continue). During propagation phase, keep table +** in 'grayagain' list, to be visited again in the atomic phase. In +** the atomic phase, if table has any white->white entry, it has to +** be revisited during ephemeron convergence (as that key may turn +** black). Otherwise, if it has any white key, table has to be cleared +** (in the atomic phase). +*/ static int traverseephemeron (global_State *g, Table *h) { int marked = 0; /* true if an object is marked in this traversal */ int hasclears = 0; /* true if table has white keys */ - int prop = 0; /* true if table has entry "white-key -> white-value" */ + int hasww = 0; /* true if table has entry "white-key -> white-value" */ Node *n, *limit = gnodelast(h); - int i; - /* traverse array part (numeric keys are 'strong') */ + unsigned int i; + /* traverse array part */ for (i = 0; i < h->sizearray; i++) { if (valiswhite(&h->array[i])) { marked = 1; @@ -396,26 +412,27 @@ static int traverseephemeron (global_State *g, Table *h) { else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ hasclears = 1; /* table must be cleared */ if (valiswhite(gval(n))) /* value not marked yet? */ - prop = 1; /* must propagate again */ + hasww = 1; /* white-white entry */ } else if (valiswhite(gval(n))) { /* value not marked yet? */ marked = 1; reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ } } - if (prop) - linktable(h, &g->ephemeron); /* have to propagate again */ - else if (hasclears) /* does table have white keys? */ - linktable(h, &g->allweak); /* may have to clean white keys */ - else /* no white keys */ - linktable(h, &g->grayagain); /* no need to clean */ + /* link table into proper list */ + if (g->gcstate == GCSpropagate) + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ + else if (hasww) /* table has white->white entries? */ + linkgclist(h, g->ephemeron); /* have to propagate again */ + else if (hasclears) /* table has white keys? */ + linkgclist(h, g->allweak); /* may have to clean white keys */ return marked; } static void traversestrongtable (global_State *g, Table *h) { Node *n, *limit = gnodelast(h); - int i; + unsigned int i; for (i = 0; i < h->sizearray; i++) /* traverse array part */ markvalue(g, &h->array[i]); for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ @@ -434,18 +451,18 @@ static void traversestrongtable (global_State *g, Table *h) { static lu_mem traversetable (global_State *g, Table *h) { const char *weakkey, *weakvalue; const TValue *mode = gfasttm(g, h->metatable, TM_MODE); - markobject(g, h->metatable); + markobjectN(g, h->metatable); if (mode && ttisstring(mode) && /* is there a weak mode? */ ((weakkey = strchr(svalue(mode), 'k')), (weakvalue = strchr(svalue(mode), 'v')), (weakkey || weakvalue))) { /* is really weak? */ - black2gray(obj2gco(h)); /* keep table gray */ + black2gray(h); /* keep table gray */ if (!weakkey) /* strong keys? */ traverseweakvalue(g, h); else if (!weakvalue) /* strong values? */ traverseephemeron(g, h); else /* all weak */ - linktable(h, &g->allweak); /* nothing to traverse now */ + linkgclist(h, g->allweak); /* nothing to traverse now */ } else /* not weak */ traversestrongtable(g, h); @@ -454,19 +471,24 @@ static lu_mem traversetable (global_State *g, Table *h) { } +/* +** Traverse a prototype. (While a prototype is being build, its +** arrays can be larger than needed; the extra slots are filled with +** NULL, so the use of 'markobjectN') +*/ static int traverseproto (global_State *g, Proto *f) { int i; - if (f->cache && iswhite(obj2gco(f->cache))) + if (f->cache && iswhite(f->cache)) f->cache = NULL; /* allow cache to be collected */ - markobject(g, f->source); + markobjectN(g, f->source); for (i = 0; i < f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ - markobject(g, f->upvalues[i].name); + markobjectN(g, f->upvalues[i].name); for (i = 0; i < f->sizep; i++) /* mark nested protos */ - markobject(g, f->p[i]); + markobjectN(g, f->p[i]); for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ - markobject(g, f->locvars[i].varname); + markobjectN(g, f->locvars[i].varname); return sizeof(Proto) + sizeof(Instruction) * f->sizecode + sizeof(Proto *) * f->sizep + sizeof(TValue) * f->sizek + @@ -483,34 +505,50 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) { return sizeCclosure(cl->nupvalues); } +/* +** open upvalues point to values in a thread, so those values should +** be marked when the thread is traversed except in the atomic phase +** (because then the value cannot be changed by the thread and the +** thread may not be traversed again) +*/ static lu_mem traverseLclosure (global_State *g, LClosure *cl) { int i; - markobject(g, cl->p); /* mark its prototype */ - for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ - markobject(g, cl->upvals[i]); + markobjectN(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ + UpVal *uv = cl->upvals[i]; + if (uv != NULL) { + if (upisopen(uv) && g->gcstate != GCSinsideatomic) + uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ + else + markvalue(g, uv->v); + } + } return sizeLclosure(cl->nupvalues); } -static lu_mem traversestack (global_State *g, lua_State *th) { - int n = 0; +static lu_mem traversethread (global_State *g, lua_State *th) { StkId o = th->stack; if (o == NULL) return 1; /* stack not completely built yet */ + lua_assert(g->gcstate == GCSinsideatomic || + th->openupval == NULL || isintwups(th)); for (; o < th->top; o++) /* mark live elements in the stack */ markvalue(g, o); - if (g->gcstate == GCSatomic) { /* final traversal? */ + if (g->gcstate == GCSinsideatomic) { /* final traversal? */ StkId lim = th->stack + th->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); + /* 'remarkupvals' may have removed thread from 'twups' list */ + if (!isintwups(th) && th->openupval != NULL) { + th->twups = g->twups; /* link it back to the list */ + g->twups = th; + } } - 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; + else if (g->gckind != KGC_EMERGENCY) + luaD_shrinkstack(th); /* do not change stack in emergency cycle */ + return (sizeof(lua_State) + sizeof(TValue) * th->stacksize + + sizeof(CallInfo) * th->nci); } @@ -523,7 +561,7 @@ static void propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); - switch (gch(o)->tt) { + switch (o->tt) { case LUA_TTABLE: { Table *h = gco2t(o); g->gray = h->gclist; /* remove from 'gray' list */ @@ -545,10 +583,9 @@ static void propagatemark (global_State *g) { case LUA_TTHREAD: { lua_State *th = gco2th(o); g->gray = th->gclist; /* remove from 'gray' list */ - th->gclist = g->grayagain; - g->grayagain = o; /* insert into 'grayagain' list */ + linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ black2gray(o); - size = traversestack(g, th); + size = traversethread(g, th); break; } case LUA_TPROTO: { @@ -568,35 +605,12 @@ static void propagateall (global_State *g) { } -static void propagatelist (global_State *g, GCObject *l) { - lua_assert(g->gray == NULL); /* no grays left */ - g->gray = l; - propagateall(g); /* traverse all elements from 'l' */ -} - -/* -** retraverse all gray lists. Because tables may be reinserted in other -** lists when traversed, traverse the original lists to avoid traversing -** twice the same table (which is not wrong, but inefficient) -*/ -static void retraversegrays (global_State *g) { - GCObject *weak = g->weak; /* save original lists */ - GCObject *grayagain = g->grayagain; - GCObject *ephemeron = g->ephemeron; - g->weak = g->grayagain = g->ephemeron = NULL; - propagateall(g); /* traverse main gray list */ - propagatelist(g, grayagain); - propagatelist(g, weak); - propagatelist(g, ephemeron); -} - - static void convergeephemerons (global_State *g) { int changed; do { GCObject *w; GCObject *next = g->ephemeron; /* get ephemeron list */ - g->ephemeron = NULL; /* tables will return to this list when traversed */ + g->ephemeron = NULL; /* tables may return to this list when traversed */ changed = 0; while ((w = next) != NULL) { next = gco2t(w)->gclist; @@ -644,7 +658,7 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); - int i; + unsigned int i; for (i = 0; i < h->sizearray; i++) { TValue *o = &h->array[i]; if (iscleared(g, o)) /* value was collected? */ @@ -660,26 +674,45 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { } +void luaC_upvdeccount (lua_State *L, UpVal *uv) { + lua_assert(uv->refcount > 0); + uv->refcount--; + if (uv->refcount == 0 && !upisopen(uv)) + luaM_free(L, uv); +} + + +static void freeLclosure (lua_State *L, LClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) { + UpVal *uv = cl->upvals[i]; + if (uv) + luaC_upvdeccount(L, uv); + } + luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); +} + + static void freeobj (lua_State *L, GCObject *o) { - switch (gch(o)->tt) { + switch (o->tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TLCL: { - luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); + freeLclosure(L, gco2lcl(o)); break; } case LUA_TCCL: { luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); break; } - case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; case LUA_TTABLE: luaH_free(L, gco2t(o)); break; case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; case LUA_TSHRSTR: - G(L)->strt.nuse--; - /* go through */ + luaS_remove(L, gco2ts(o)); /* remove it from hash table */ + luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); + break; case LUA_TLNGSTR: { - luaM_freemem(L, o, sizestring(gco2ts(o))); + luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); break; } default: lua_assert(0); @@ -691,61 +724,27 @@ static void freeobj (lua_State *L, GCObject *o) { static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); -/* -** sweep the (open) upvalues of a thread and resize its stack and -** list of call-info structures. -*/ -static void sweepthread (lua_State *L, lua_State *L1) { - if (L1->stack == NULL) return; /* stack not completely built yet */ - sweepwholelist(L, &L1->openupval); /* sweep open upvalues */ - luaE_freeCI(L1); /* free extra CallInfo slots */ - /* should not change the stack during an emergency gc cycle */ - if (G(L)->gckind != KGC_EMERGENCY) - luaD_shrinkstack(L1); -} - - /* ** sweep at most 'count' elements from a list of GCObjects erasing dead -** objects, where a dead (not alive) object is one marked with the "old" -** (non current) white and not fixed. -** In non-generational mode, change all non-dead objects back to white, -** preparing for next collection cycle. -** In generational mode, keep black objects black, and also mark them as -** old; stop when hitting an old object, as all objects after that -** one will be old too. -** When object is a thread, sweep its list of open upvalues too. +** objects, where a dead object is one marked with the old (non current) +** white; change all non-dead objects back to white, preparing for next +** collection cycle. Return where to continue the traversal or NULL if +** list is finished. */ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { global_State *g = G(L); int ow = otherwhite(g); - int toclear, toset; /* bits to clear and to set in all live objects */ - int tostop; /* stop sweep when this is true */ - if (isgenerational(g)) { /* generational mode? */ - toclear = ~0; /* clear nothing */ - toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */ - tostop = bitmask(OLDBIT); /* do not sweep old generation */ - } - else { /* normal mode */ - toclear = maskcolors; /* clear all color bits + old bit */ - toset = luaC_white(g); /* make object white */ - tostop = 0; /* do not stop */ - } + int white = luaC_white(g); /* current white */ while (*p != NULL && count-- > 0) { GCObject *curr = *p; - int marked = gch(curr)->marked; + int marked = curr->marked; if (isdeadm(ow, marked)) { /* is 'curr' dead? */ - *p = gch(curr)->next; /* remove 'curr' from list */ + *p = curr->next; /* remove 'curr' from list */ freeobj(L, curr); /* erase 'curr' */ } - else { - if (testbits(marked, tostop)) - return NULL; /* stop sweeping this list */ - if (gch(curr)->tt == LUA_TTHREAD) - sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ - /* update marks */ - gch(curr)->marked = cast_byte((marked & toclear) | toset); - p = &gch(curr)->next; /* go to next element */ + else { /* change mark to 'white' */ + curr->marked = cast_byte((marked & maskcolors) | white); + p = &curr->next; /* go to next element */ } } return (*p == NULL) ? NULL : p; @@ -755,14 +754,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { /* ** sweep a list until a live object (or end of list) */ -static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { - GCObject ** old = p; - int i = 0; +static GCObject **sweeptolive (lua_State *L, GCObject **p) { + GCObject **old = p; do { - i++; p = sweeplist(L, p, 1); } while (p == old); - if (n) *n += i; return p; } @@ -775,26 +771,27 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { ** ======================================================= */ -static void checkSizes (lua_State *L) { - global_State *g = G(L); - if (g->gckind != KGC_EMERGENCY) { /* do not change sizes in emergency */ - int hs = g->strt.size / 2; /* half the size of the string table */ - if (g->strt.nuse < cast(lu_int32, hs)) /* using less than that half? */ - luaS_resize(L, hs); /* halve its size */ - luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */ +/* +** If possible, shrink string table +*/ +static void checkSizes (lua_State *L, global_State *g) { + if (g->gckind != KGC_EMERGENCY) { + l_mem olddebt = g->GCdebt; + if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ + luaS_resize(L, g->strt.size / 2); /* shrink it a little */ + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ } } static GCObject *udata2finalize (global_State *g) { GCObject *o = g->tobefnz; /* get first element */ - lua_assert(isfinalized(o)); - g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ - gch(o)->next = g->allgc; /* return it to 'allgc' list */ + lua_assert(tofinalize(o)); + g->tobefnz = o->next; /* remove it from 'tobefnz' list */ + o->next = g->allgc; /* return it to 'allgc' list */ g->allgc = o; - resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */ - lua_assert(!isold(o)); /* see MOVE OLD rule */ - if (!keepinvariantout(g)) /* not keeping invariant? */ + resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ + if (issweepphase(g)) makewhite(g, o); /* "sweep" object */ return o; } @@ -802,7 +799,7 @@ static GCObject *udata2finalize (global_State *g) { static void dothecall (lua_State *L, void *ud) { UNUSED(ud); - luaD_call(L, L->top - 2, 0, 0); + luaD_callnoyield(L, L->top - 2, 0); } @@ -838,29 +835,58 @@ static void GCTM (lua_State *L, int propagateerrors) { } +/* +** call a few (up to 'g->gcfinnum') finalizers +*/ +static int runafewfinalizers (lua_State *L) { + global_State *g = G(L); + unsigned int i; + lua_assert(!g->tobefnz || g->gcfinnum > 0); + for (i = 0; g->tobefnz && i < g->gcfinnum; i++) + GCTM(L, 1); /* call one finalizer */ + g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */ + : g->gcfinnum * 2; /* else call a few more next time */ + return i; +} + + +/* +** call all pending finalizers +*/ +static void callallpendingfinalizers (lua_State *L) { + global_State *g = G(L); + while (g->tobefnz) + GCTM(L, 0); +} + + +/* +** find last 'next' field in list 'p' list (to add elements in its end) +*/ +static GCObject **findlast (GCObject **p) { + while (*p != NULL) + p = &(*p)->next; + return p; +} + + /* ** move all unreachable objects (or 'all' objects) that need ** finalization from list 'finobj' to list 'tobefnz' (to be finalized) */ -static void separatetobefnz (lua_State *L, int all) { - global_State *g = G(L); - GCObject **p = &g->finobj; +static void separatetobefnz (global_State *g, int all) { GCObject *curr; - GCObject **lastnext = &g->tobefnz; - /* find last 'next' field in 'tobefnz' list (to add elements in its end) */ - while (*lastnext != NULL) - lastnext = &gch(*lastnext)->next; + GCObject **p = &g->finobj; + GCObject **lastnext = findlast(&g->tobefnz); while ((curr = *p) != NULL) { /* traverse all finalizable objects */ - lua_assert(!isfinalized(curr)); - lua_assert(testbit(gch(curr)->marked, SEPARATED)); + lua_assert(tofinalize(curr)); if (!(iswhite(curr) || all)) /* not being collected? */ - p = &gch(curr)->next; /* don't bother with it */ + p = &curr->next; /* don't bother with it */ else { - l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ - *p = gch(curr)->next; /* remove 'curr' from 'finobj' list */ - gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */ + *p = curr->next; /* remove 'curr' from 'finobj' list */ + curr->next = *lastnext; /* link at the end of 'tobefnz' list */ *lastnext = curr; - lastnext = &gch(curr)->next; + lastnext = &curr->next; } } } @@ -872,33 +898,29 @@ static void separatetobefnz (lua_State *L, int all) { */ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { global_State *g = G(L); - if (testbit(gch(o)->marked, SEPARATED) || /* obj. is already separated... */ - isfinalized(o) || /* ... or is finalized... */ - gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ + if (tofinalize(o) || /* obj. is already marked... */ + gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ return; /* nothing to be done */ else { /* move 'o' to 'finobj' list */ GCObject **p; - GCheader *ho = gch(o); - if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */ - lua_assert(issweepphase(g)); - g->sweepgc = sweeptolive(L, g->sweepgc, NULL); + if (issweepphase(g)) { + makewhite(g, o); /* "sweep" object 'o' */ + if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ + g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ } /* search for pointer pointing to 'o' */ - for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } - *p = ho->next; /* remove 'o' from root list */ - ho->next = g->finobj; /* link it in list 'finobj' */ + for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } + *p = o->next; /* remove 'o' from 'allgc' list */ + o->next = g->finobj; /* link it in 'finobj' list */ g->finobj = o; - l_setbit(ho->marked, SEPARATED); /* mark it as such */ - if (!keepinvariantout(g)) /* not keeping invariant? */ - makewhite(g, o); /* "sweep" object */ - else - resetoldbit(o); /* see MOVE OLD rule */ + l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ } } /* }====================================================== */ + /* ** {====================================================== ** GC control @@ -907,195 +929,164 @@ 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 +** Set a reasonable "time" to wait before starting a new GC cycle; cycle +** will start when memory use hits threshold. (Division by 'estimate' +** should be OK: it cannot be zero (because Lua cannot even start with +** less than PAUSEADJ bytes). */ -static void setpause (global_State *g, l_mem estimate) { - l_mem debt, threshold; - estimate = estimate / PAUSEADJ; /* adjust 'estimate' */ +static void setpause (global_State *g) { + l_mem threshold, debt; + l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ + lua_assert(estimate > 0); 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)); + debt = gettotalbytes(g) - threshold; luaE_setdebt(g, debt); } -#define sweepphases \ - (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) - - -/* -** enter first sweep phase (strings) and prepare pointers for other -** sweep phases. The calls to 'sweeptolive' make pointers point to an -** 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 -** of the real sweep. -** Returns how many objects it swept. -*/ -static int entersweep (lua_State *L) { - global_State *g = G(L); - int n = 0; - g->gcstate = GCSsweepstring; - lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); - /* prepare to sweep strings, finalizable objects, and regular objects */ - g->sweepstrgc = 0; - g->sweepfin = sweeptolive(L, &g->finobj, &n); - g->sweepgc = sweeptolive(L, &g->allgc, &n); - return n; -} - - -/* -** change GC mode -*/ -void luaC_changemode (lua_State *L, int mode) { - global_State *g = G(L); - if (mode == g->gckind) return; /* nothing to change */ - if (mode == KGC_GEN) { /* change to generational mode */ - /* make sure gray lists are consistent */ - luaC_runtilstate(L, bitmask(GCSpropagate)); - g->GCestimate = gettotalbytes(g); - g->gckind = KGC_GEN; - } - else { /* change to incremental mode */ - /* sweep all objects to turn them back to white - (as white has not changed, nothing extra will be collected) */ - g->gckind = KGC_NORMAL; - entersweep(L); - luaC_runtilstate(L, ~sweepphases); - } -} - - /* -** call all pending finalizers +** Enter first sweep phase. +** The call to 'sweeplist' tries to make pointer point to an 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 of the +** real sweep. */ -static void callallpendingfinalizers (lua_State *L, int propagateerrors) { +static void entersweep (lua_State *L) { global_State *g = G(L); - while (g->tobefnz) { - resetoldbit(g->tobefnz); - GCTM(L, propagateerrors); - } + g->gcstate = GCSswpallgc; + lua_assert(g->sweepgc == NULL); + g->sweepgc = sweeplist(L, &g->allgc, 1); } void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); - int i; - separatetobefnz(L, 1); /* separate all objects with finalizers */ + separatetobefnz(g, 1); /* separate all objects with finalizers */ lua_assert(g->finobj == NULL); - callallpendingfinalizers(L, 0); + callallpendingfinalizers(L); + lua_assert(g->tobefnz == NULL); g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ g->gckind = KGC_NORMAL; - sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ + sweepwholelist(L, &g->finobj); sweepwholelist(L, &g->allgc); - for (i = 0; i < g->strt.size; i++) /* free all string lists */ - sweepwholelist(L, &g->strt.hash[i]); + sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ lua_assert(g->strt.nuse == 0); } static l_mem atomic (lua_State *L) { global_State *g = G(L); - l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */ + l_mem work; GCObject *origweak, *origall; - lua_assert(!iswhite(obj2gco(g->mainthread))); + GCObject *grayagain = g->grayagain; /* save original list */ + lua_assert(g->ephemeron == NULL && g->weak == NULL); + lua_assert(!iswhite(g->mainthread)); + g->gcstate = GCSinsideatomic; + g->GCmemtrav = 0; /* start counting work */ markobject(g, L); /* mark running thread */ /* registry and global metatables may be changed by API */ markvalue(g, &g->l_registry); - markmt(g); /* mark basic metatables */ + markmt(g); /* mark global metatables */ /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); propagateall(g); /* propagate changes */ - work += g->GCmemtrav; /* stop counting (do not (re)count grays) */ - /* traverse objects caught by write barrier and by 'remarkupvals' */ - retraversegrays(g); - work -= g->GCmemtrav; /* restart counting */ + work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ + g->gray = grayagain; + propagateall(g); /* traverse 'grayagain' list */ + g->GCmemtrav = 0; /* restart counting */ convergeephemerons(g); /* at this point, all strongly accessible objects are marked. */ - /* clear values from weak tables, before checking finalizers */ + /* Clear values from weak tables, before checking finalizers */ clearvalues(g, g->weak, NULL); clearvalues(g, g->allweak, NULL); origweak = g->weak; origall = g->allweak; work += g->GCmemtrav; /* stop counting (objects being finalized) */ - separatetobefnz(L, 0); /* separate objects to be finalized */ + separatetobefnz(g, 0); /* separate objects to be finalized */ + g->gcfinnum = 1; /* there may be objects to be finalized */ markbeingfnz(g); /* mark objects that will be finalized */ - propagateall(g); /* remark, to propagate `preserveness' */ - work -= g->GCmemtrav; /* restart counting */ + propagateall(g); /* remark, to propagate 'resurrection' */ + g->GCmemtrav = 0; /* restart counting */ convergeephemerons(g); /* at this point, all resurrected objects are marked. */ /* remove dead objects from weak tables */ clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ - clearkeys(g, g->allweak, NULL); /* clear keys from all allweak tables */ + clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ /* clear values from resurrected weak tables */ clearvalues(g, g->weak, origweak); clearvalues(g, g->allweak, origall); + luaS_clearcache(g); g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ work += g->GCmemtrav; /* complete counting */ return work; /* estimate of memory marked by 'atomic' */ } +static lu_mem sweepstep (lua_State *L, global_State *g, + int nextstate, GCObject **nextlist) { + if (g->sweepgc) { + l_mem olddebt = g->GCdebt; + g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + if (g->sweepgc) /* is there still something to sweep? */ + return (GCSWEEPMAX * GCSWEEPCOST); + } + /* else enter next state */ + g->gcstate = nextstate; + g->sweepgc = nextlist; + return 0; +} + + static lu_mem singlestep (lua_State *L) { global_State *g = G(L); switch (g->gcstate) { case GCSpause: { - /* start to count memory traversed */ g->GCmemtrav = g->strt.size * sizeof(GCObject*); - lua_assert(!isgenerational(g)); restartcollection(g); g->gcstate = GCSpropagate; return g->GCmemtrav; } case GCSpropagate: { - if (g->gray) { - lu_mem oldtrav = g->GCmemtrav; - propagatemark(g); - return g->GCmemtrav - oldtrav; /* memory traversed in this step */ - } - else { /* no more `gray' objects */ - lu_mem work; - int sw; - g->gcstate = GCSatomic; /* finish mark phase */ - g->GCestimate = g->GCmemtrav; /* save what was counted */; - work = atomic(L); /* add what was traversed by 'atomic' */ - g->GCestimate += work; /* estimate of total memory traversed */ - sw = entersweep(L); - return work + sw * GCSWEEPCOST; - } + g->GCmemtrav = 0; + lua_assert(g->gray); + propagatemark(g); + if (g->gray == NULL) /* no more gray objects? */ + g->gcstate = GCSatomic; /* finish propagate phase */ + return g->GCmemtrav; /* memory traversed in this step */ } - case GCSsweepstring: { - int i; - for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++) - sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]); - g->sweepstrgc += i; - if (g->sweepstrgc >= g->strt.size) /* no more strings to sweep? */ - g->gcstate = GCSsweepudata; - return i * GCSWEEPCOST; + case GCSatomic: { + lu_mem work; + propagateall(g); /* make sure gray list is empty */ + work = atomic(L); /* work is what was traversed by 'atomic' */ + entersweep(L); + g->GCestimate = gettotalbytes(g); /* first estimate */; + return work; } - case GCSsweepudata: { - if (g->sweepfin) { - g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX); - return GCSWEEPMAX*GCSWEEPCOST; - } - else { - g->gcstate = GCSsweep; - return 0; - } + case GCSswpallgc: { /* sweep "regular" objects */ + return sweepstep(L, g, GCSswpfinobj, &g->finobj); + } + case GCSswpfinobj: { /* sweep objects with finalizers */ + return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); } - case GCSsweep: { - if (g->sweepgc) { - g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); - return GCSWEEPMAX*GCSWEEPCOST; + case GCSswptobefnz: { /* sweep objects to be finalized */ + return sweepstep(L, g, GCSswpend, NULL); + } + case GCSswpend: { /* finish sweeps */ + makewhite(g, g->mainthread); /* sweep main thread */ + checkSizes(L, g); + g->gcstate = GCScallfin; + return 0; + } + case GCScallfin: { /* call remaining finalizers */ + if (g->tobefnz && g->gckind != KGC_EMERGENCY) { + int n = runafewfinalizers(L); + return (n * GCFINALIZECOST); } - else { - /* sweep main thread */ - GCObject *mt = obj2gco(g->mainthread); - sweeplist(L, &mt, 1); - checkSizes(L); + else { /* emergency mode or no more finalizers */ g->gcstate = GCSpause; /* finish collection */ - return GCSWEEPCOST; + return 0; } } default: lua_assert(0); return 0; @@ -1114,105 +1105,70 @@ void luaC_runtilstate (lua_State *L, int statesmask) { } -static void generationalcollection (lua_State *L) { - global_State *g = G(L); - lua_assert(g->gcstate == GCSpropagate); - if (g->GCestimate == 0) { /* signal for another major collection? */ - luaC_fullgc(L, 0); /* perform a full regular collection */ - g->GCestimate = gettotalbytes(g); /* update control */ - } +/* +** get GC debt and convert it from Kb to 'work units' (avoid zero debt +** and overflows) +*/ +static l_mem getdebt (global_State *g) { + l_mem debt = g->GCdebt; + int stepmul = g->gcstepmul; + if (debt <= 0) return 0; /* minimal debt */ else { - lu_mem estimate = g->GCestimate; - luaC_runtilstate(L, bitmask(GCSpause)); /* run complete (minor) cycle */ - g->gcstate = GCSpropagate; /* skip restart */ - if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) - g->GCestimate = 0; /* signal for a major collection */ - else - g->GCestimate = estimate; /* keep estimate from last major coll. */ - + debt = (debt / STEPMULADJ) + 1; + debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; + return debt; } - setpause(g, gettotalbytes(g)); - lua_assert(g->gcstate == GCSpropagate); } - -static void incstep (lua_State *L) { +/* +** performs a basic GC step when collector is running +*/ +void luaC_step (lua_State *L) { global_State *g = G(L); - l_mem debt = g->GCdebt; - int stepmul = g->gcstepmul; - if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values (and 0) */ - /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */ - debt = (debt / STEPMULADJ) + 1; - debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; - do { /* always perform at least one single step */ - lu_mem work = singlestep(L); /* do some work */ + l_mem debt = getdebt(g); /* GC deficit (be paid now) */ + if (!g->gcrunning) { /* not running? */ + luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ + return; + } + do { /* repeat until pause or enough "credit" (negative debt) */ + lu_mem work = singlestep(L); /* perform one single step */ debt -= work; } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); if (g->gcstate == GCSpause) - setpause(g, g->GCestimate); /* pause until next cycle */ + setpause(g); /* pause until next cycle */ else { - debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */ + debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */ luaE_setdebt(g, debt); + runafewfinalizers(L); } } /* -** performs a basic GC step -*/ -void luaC_forcestep (lua_State *L) { - global_State *g = G(L); - int i; - if (isgenerational(g)) generationalcollection(L); - else incstep(L); - /* run a few finalizers (or all of them at the end of a collect cycle) */ - for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) - GCTM(L, 1); /* call one finalizer */ -} - - -/* -** performs a basic GC step only if collector is running -*/ -void luaC_step (lua_State *L) { - global_State *g = G(L); - if (g->gcrunning) luaC_forcestep(L); - else luaE_setdebt(g, -GCSTEPSIZE); /* avoid being called too often */ -} - - - -/* -** performs a full GC cycle; if "isemergency", does not call -** finalizers (which could change stack positions) +** Performs a full GC cycle; if 'isemergency', set a flag to avoid +** some operations which could change the interpreter state in some +** unexpected ways (running finalizers and shrinking some structures). +** Before running the collection, check 'keepinvariant'; if it is true, +** there may be some objects marked as black, so the collector has +** to sweep all objects to turn them back to white (as white has not +** changed, nothing will be collected). */ void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); - int origkind = g->gckind; - lua_assert(origkind != KGC_EMERGENCY); - if (isemergency) /* do not run finalizers during emergency GC */ - g->gckind = KGC_EMERGENCY; - else { - g->gckind = KGC_NORMAL; - callallpendingfinalizers(L, 1); - } - if (keepinvariant(g)) { /* may there be some black objects? */ - /* must sweep all objects to turn them back to white - (as white has not changed, nothing will be collected) */ - entersweep(L); + lua_assert(g->gckind == KGC_NORMAL); + if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ + if (keepinvariant(g)) { /* black objects? */ + entersweep(L); /* sweep everything to turn them back to white */ } /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ - luaC_runtilstate(L, bitmask(GCSpause)); /* run entire collection */ - if (origkind == KGC_GEN) { /* generational mode? */ - /* generational mode must be kept in propagate phase */ - luaC_runtilstate(L, bitmask(GCSpropagate)); - } - g->gckind = origkind; - setpause(g, gettotalbytes(g)); - if (!isemergency) /* do not run finalizers during emergency GC */ - callallpendingfinalizers(L, 1); + luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ + /* estimate must be correct after a full GC cycle */ + lua_assert(g->GCestimate == gettotalbytes(g)); + luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ + g->gckind = KGC_NORMAL; + setpause(g); } /* }====================================================== */ diff --git a/depends/lua/src/linit.c b/depends/lua/src/linit.c index c1a383047..8ce94ccb3 100644 --- a/depends/lua/src/linit.c +++ b/depends/lua/src/linit.c @@ -1,20 +1,33 @@ /* -** $Id: linit.c,v 1.32.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: linit.c,v 1.38 2015/01/05 13:48:33 roberto Exp $ ** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ +#define linit_c +#define LUA_LIB + /* ** If you embed Lua in your program and need to open the standard ** libraries, call luaL_openlibs in your program. If you need a ** different set of libraries, copy this file to your project and edit ** it to suit your needs. +** +** You can also *preload* libraries, so that a later 'require' can +** open the library, which is already linked to the application. +** For that, do the following code: +** +** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); +** lua_pushcfunction(L, luaopen_modname); +** lua_setfield(L, -2, modname); +** lua_pop(L, 1); // remove _PRELOAD table */ +#include "lprefix.h" -#define linit_c -#define LUA_LIB + +#include #include "lua.h" @@ -34,34 +47,22 @@ static const luaL_Reg loadedlibs[] = { {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, - {LUA_BITLIBNAME, luaopen_bit32}, {LUA_MATHLIBNAME, luaopen_math}, + {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_DBLIBNAME, luaopen_debug}, - {NULL, NULL} -}; - - -/* -** these libs are preloaded and must be required before used -*/ -static const luaL_Reg preloadedlibs[] = { +#if defined(LUA_COMPAT_BITLIB) + {LUA_BITLIBNAME, luaopen_bit32}, +#endif {NULL, NULL} }; LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; - /* call open functions from 'loadedlibs' and set results to global table */ + /* "require" functions from 'loadedlibs' and set results to global table */ for (lib = loadedlibs; lib->func; lib++) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ } - /* add open functions from 'preloadedlibs' into 'package.preload' table */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); - for (lib = preloadedlibs; lib->func; lib++) { - lua_pushcfunction(L, lib->func); - lua_setfield(L, -2, lib->name); - } - lua_pop(L, 1); /* remove _PRELOAD table */ } diff --git a/depends/lua/src/liolib.c b/depends/lua/src/liolib.c index 2a4ec4aa3..aa78e593f 100644 --- a/depends/lua/src/liolib.c +++ b/depends/lua/src/liolib.c @@ -1,120 +1,139 @@ /* -** $Id: liolib.c,v 2.112.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: liolib.c,v 2.149 2016/05/02 14:03:19 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ +#define liolib_c +#define LUA_LIB -/* -** This definition must come before the inclusion of 'stdio.h'; it -** should not affect non-POSIX systems -*/ -#if !defined(_FILE_OFFSET_BITS) -#define _LARGEFILE_SOURCE 1 -#define _FILE_OFFSET_BITS 64 -#endif +#include "lprefix.h" +#include #include +#include #include #include #include -#define liolib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.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) \ +#if !defined(l_checkmode) + +/* accepted extensions to 'mode' in 'fopen' */ +#if !defined(L_MODEEXT) +#define L_MODEEXT "b" +#endif + +/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ +#define l_checkmode(mode) \ (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \ - (*mode != '+' || ++mode) && /* skip if char is '+' */ \ - (*mode != 'b' || ++mode) && /* skip if char is 'b' */ \ - (*mode == '\0')) + (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ \ + (strspn(mode, L_MODEEXT) == strlen(mode))) #endif /* ** {====================================================== -** lua_popen spawns a new process connected to the current +** l_popen spawns a new process connected to the current ** one through the file streams. ** ======================================================= */ -#if !defined(lua_popen) /* { */ - -#if defined(LUA_USE_POPEN) /* { */ +#if !defined(l_popen) /* { */ -#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m)) -#define lua_pclose(L,file) ((void)L, pclose(file)) +#if defined(LUA_USE_POSIX) /* { */ -#elif defined(LUA_WIN) /* }{ */ +#define l_popen(L,c,m) (fflush(NULL), popen(c,m)) +#define l_pclose(L,file) (pclose(file)) -#define lua_popen(L,c,m) ((void)L, _popen(c,m)) -#define lua_pclose(L,file) ((void)L, _pclose(file)) +#elif defined(LUA_USE_WINDOWS) /* }{ */ +#define l_popen(L,c,m) (_popen(c,m)) +#define l_pclose(L,file) (_pclose(file)) #else /* }{ */ -#define lua_popen(L,c,m) ((void)((void)c, m), \ - luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0) -#define lua_pclose(L,file) ((void)((void)L, file), -1) - +/* ISO C definitions */ +#define l_popen(L,c,m) \ + ((void)((void)c, m), \ + luaL_error(L, "'popen' not supported"), \ + (FILE*)0) +#define l_pclose(L,file) ((void)L, (void)file, -1) #endif /* } */ -#endif /* } */ +#endif /* } */ /* }====================================================== */ +#if !defined(l_getc) /* { */ + +#if defined(LUA_USE_POSIX) +#define l_getc(f) getc_unlocked(f) +#define l_lockfile(f) flockfile(f) +#define l_unlockfile(f) funlockfile(f) +#else +#define l_getc(f) getc(f) +#define l_lockfile(f) ((void)0) +#define l_unlockfile(f) ((void)0) +#endif + +#endif /* } */ + + /* ** {====================================================== -** lua_fseek: configuration for longer offsets +** l_fseek: configuration for longer offsets ** ======================================================= */ -#if !defined(lua_fseek) && !defined(LUA_ANSI) /* { */ +#if !defined(l_fseek) /* { */ #if defined(LUA_USE_POSIX) /* { */ +#include + #define l_fseek(f,o,w) fseeko(f,o,w) #define l_ftell(f) ftello(f) #define l_seeknum off_t -#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \ +#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ && 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_ftell(f) _ftelli64(f) #define l_seeknum __int64 -#endif /* } */ - -#endif /* } */ - +#else /* }{ */ -#if !defined(l_fseek) /* default definitions */ +/* ISO C definitions */ #define l_fseek(f,o,w) fseek(f,o,w) #define l_ftell(f) ftell(f) #define l_seeknum long -#endif + +#endif /* } */ + +#endif /* } */ /* }====================================================== */ #define IO_PREFIX "_IO_" +#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) #define IO_INPUT (IO_PREFIX "input") #define IO_OUTPUT (IO_PREFIX "output") @@ -161,9 +180,9 @@ static FILE *tofile (lua_State *L) { /* -** When creating file handles, always creates a `closed' file handle +** When creating file handles, always creates a 'closed' file handle ** before opening the actual file; so, if there is a memory error, the -** file is not left opened. +** handle is in a consistent state. */ static LStream *newprefile (lua_State *L) { LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); @@ -173,9 +192,14 @@ static LStream *newprefile (lua_State *L) { } +/* +** Calls the 'close' function from a file handle. The 'volatile' avoids +** a bug in some versions of the Clang compiler (e.g., clang 3.0 for +** 32 bits). +*/ static int aux_close (lua_State *L) { LStream *p = tolstream(L); - lua_CFunction cf = p->closef; + volatile lua_CFunction cf = p->closef; p->closef = NULL; /* mark stream as closed */ return (*cf)(L); /* close it */ } @@ -219,7 +243,7 @@ static void opencheck (lua_State *L, const char *fname, const char *mode) { LStream *p = newfile(L); p->f = fopen(fname, mode); if (p->f == NULL) - luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno)); + luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); } @@ -228,7 +252,7 @@ static int io_open (lua_State *L) { const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newfile(L); const char *md = mode; /* to traverse/check mode */ - luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode"); + luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } @@ -239,7 +263,7 @@ static int io_open (lua_State *L) { */ static int io_pclose (lua_State *L) { LStream *p = tolstream(L); - return luaL_execresult(L, lua_pclose(L, p->f)); + return luaL_execresult(L, l_pclose(L, p->f)); } @@ -247,7 +271,7 @@ static int io_popen (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newprefile(L); - p->f = lua_popen(L, filename, mode); + p->f = l_popen(L, filename, mode); p->closef = &io_pclose; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } @@ -265,7 +289,7 @@ static FILE *getiofile (lua_State *L, const char *findex) { lua_getfield(L, LUA_REGISTRYINDEX, findex); p = (LStream *)lua_touserdata(L, -1); if (isclosed(p)) - luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX)); + luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); return p->f; } @@ -300,15 +324,18 @@ static int io_output (lua_State *L) { static int io_readline (lua_State *L); +/* +** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit +** in the limit for upvalues of a closure) +*/ +#define MAXARGLINE 250 + static void aux_lines (lua_State *L, int toclose) { - int i; int n = lua_gettop(L) - 1; /* number of arguments to read */ - /* ensure that arguments will fit here and into 'io_readline' stack */ - luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options"); - lua_pushvalue(L, 1); /* file handle */ + luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); lua_pushinteger(L, n); /* number of arguments to read */ lua_pushboolean(L, toclose); /* close/not close file when finished */ - for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1); /* copy arguments */ + lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ lua_pushcclosure(L, io_readline, 3 + n); } @@ -347,13 +374,91 @@ static int io_lines (lua_State *L) { */ -static int read_number (lua_State *L, FILE *f) { - lua_Number d; - if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) { - lua_pushnumber(L, d); - return 1; +/* maximum length of a numeral */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif + + +/* auxiliary structure used by 'read_number' */ +typedef struct { + FILE *f; /* file being read */ + int c; /* current character (look ahead) */ + int n; /* number of elements in buffer 'buff' */ + char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */ +} RN; + + +/* +** Add current char to buffer (if not out of space) and read next one +*/ +static int nextc (RN *rn) { + if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */ + rn->buff[0] = '\0'; /* invalidate result */ + return 0; /* fail */ } else { + rn->buff[rn->n++] = rn->c; /* save current char */ + rn->c = l_getc(rn->f); /* read next one */ + return 1; + } +} + + +/* +** Accept current char if it is in 'set' (of size 2) +*/ +static int test2 (RN *rn, const char *set) { + if (rn->c == set[0] || rn->c == set[1]) + return nextc(rn); + else return 0; +} + + +/* +** Read a sequence of (hex)digits +*/ +static int readdigits (RN *rn, int hex) { + int count = 0; + while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) + count++; + return count; +} + + +/* +** Read a number: first reads a valid prefix of a numeral into a buffer. +** Then it calls 'lua_stringtonumber' to check whether the format is +** correct and to convert it to a Lua number +*/ +static int read_number (lua_State *L, FILE *f) { + RN rn; + int count = 0; + int hex = 0; + char decp[2]; + rn.f = f; rn.n = 0; + decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ + decp[1] = '.'; /* always accept a dot */ + l_lockfile(rn.f); + do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ + test2(&rn, "-+"); /* optional signal */ + if (test2(&rn, "00")) { + if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ + else count = 1; /* count initial '0' as a valid digit */ + } + count += readdigits(&rn, hex); /* integral part */ + if (test2(&rn, decp)) /* decimal point? */ + count += readdigits(&rn, hex); /* fractional part */ + if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ + test2(&rn, "-+"); /* exponent signal */ + readdigits(&rn, 0); /* exponent digits */ + } + ungetc(rn.c, rn.f); /* unread look-ahead char */ + l_unlockfile(rn.f); + rn.buff[rn.n] = '\0'; /* finish string */ + if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ + return 1; /* ok */ + else { /* invalid format */ lua_pushnil(L); /* "result" to be removed */ return 0; /* read fails */ } @@ -362,48 +467,42 @@ static int read_number (lua_State *L, FILE *f) { static int test_eof (lua_State *L, FILE *f) { int c = getc(f); - ungetc(c, f); - lua_pushlstring(L, NULL, 0); + ungetc(c, f); /* no-op when c == EOF */ + lua_pushliteral(L, ""); return (c != EOF); } static int read_line (lua_State *L, FILE *f, int chop) { luaL_Buffer b; + int c = '\0'; luaL_buffinit(L, &b); - for (;;) { - size_t l; - char *p = luaL_prepbuffer(&b); - if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */ - luaL_pushresult(&b); /* close buffer */ - return (lua_rawlen(L, -1) > 0); /* check whether read something */ - } - l = strlen(p); - if (l == 0 || p[l-1] != '\n') - luaL_addsize(&b, l); - else { - luaL_addsize(&b, l - chop); /* chop 'eol' if needed */ - luaL_pushresult(&b); /* close buffer */ - return 1; /* read at least an `eol' */ - } + while (c != EOF && c != '\n') { /* repeat until end of line */ + char *buff = luaL_prepbuffer(&b); /* preallocate buffer */ + int i = 0; + l_lockfile(f); /* no memory errors can happen inside the lock */ + while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') + buff[i++] = c; + l_unlockfile(f); + luaL_addsize(&b, i); } + if (!chop && c == '\n') /* want a newline and have one? */ + luaL_addchar(&b, c); /* add ending newline to result */ + luaL_pushresult(&b); /* close buffer */ + /* return ok if read something (either a newline or something else) */ + return (c == '\n' || lua_rawlen(L, -1) > 0); } -#define MAX_SIZE_T (~(size_t)0) - static void read_all (lua_State *L, FILE *f) { - size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */ + size_t nr; luaL_Buffer b; luaL_buffinit(L, &b); - for (;;) { - char *p = luaL_prepbuffsize(&b, rlen); - size_t nr = fread(p, sizeof(char), rlen, f); + do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ + char *p = luaL_prepbuffer(&b); + nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); luaL_addsize(&b, nr); - if (nr < rlen) break; /* eof? */ - else if (rlen <= (MAX_SIZE_T / 4)) /* avoid buffers too large */ - rlen *= 2; /* double buffer size at each iteration */ - } + } while (nr == LUAL_BUFFERSIZE); luaL_pushresult(&b); /* close buffer */ } @@ -435,13 +534,13 @@ static int g_read (lua_State *L, FILE *f, int first) { success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { - size_t l = (size_t)lua_tointeger(L, n); + size_t l = (size_t)luaL_checkinteger(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { - const char *p = lua_tostring(L, n); - luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); - switch (p[1]) { + const char *p = luaL_checkstring(L, n); + if (*p == '*') p++; /* skip optional '*' (for compatibility) */ + switch (*p) { case 'n': /* number */ success = read_number(L, f); break; @@ -488,11 +587,12 @@ static int io_readline (lua_State *L) { if (isclosed(p)) /* file is already closed? */ return luaL_error(L, "file is already closed"); lua_settop(L , 1); + luaL_checkstack(L, n, "too many arguments"); for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ lua_pushvalue(L, lua_upvalueindex(3 + i)); n = g_read(L, p->f, 2); /* 'n' is number of results */ lua_assert(n > 0); /* should return at least a nil */ - if (!lua_isnil(L, -n)) /* read at least one value? */ + if (lua_toboolean(L, -n)) /* read at least one value? */ return n; /* return them */ else { /* first result is nil: EOF or error */ if (n > 1) { /* is there error information? */ @@ -517,8 +617,10 @@ static int g_write (lua_State *L, FILE *f, int arg) { for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ - status = status && - fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0; + int len = lua_isinteger(L, arg) + ? fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg)) + : fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)); + status = status && (len > 0); } else { size_t l; @@ -548,15 +650,15 @@ static int f_seek (lua_State *L) { static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, "cur", modenames); - lua_Number p3 = luaL_optnumber(L, 3, 0); + lua_Integer p3 = luaL_optinteger(L, 3, 0); l_seeknum offset = (l_seeknum)p3; - luaL_argcheck(L, (lua_Number)offset == p3, 3, + luaL_argcheck(L, (lua_Integer)offset == p3, 3, "not an integer in proper range"); op = l_fseek(f, offset, mode[op]); if (op) return luaL_fileresult(L, 0, NULL); /* error */ else { - lua_pushnumber(L, (lua_Number)l_ftell(f)); + lua_pushinteger(L, (lua_Integer)l_ftell(f)); return 1; } } @@ -568,7 +670,7 @@ static int f_setvbuf (lua_State *L) { FILE *f = tofile(L); int op = luaL_checkoption(L, 2, NULL, modenames); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], sz); + int res = setvbuf(f, NULL, mode[op], (size_t)sz); return luaL_fileresult(L, res == 0, NULL); } diff --git a/depends/lua/src/llex.c b/depends/lua/src/llex.c index c4b820e83..70328273f 100644 --- a/depends/lua/src/llex.c +++ b/depends/lua/src/llex.c @@ -1,20 +1,24 @@ /* -** $Id: llex.c,v 2.63.1.2 2013/08/30 15:49:41 roberto Exp $ +** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ +#define llex_c +#define LUA_CORE + +#include "lprefix.h" + #include #include -#define llex_c -#define LUA_CORE - #include "lua.h" #include "lctype.h" +#include "ldebug.h" #include "ldo.h" +#include "lgc.h" #include "llex.h" #include "lobject.h" #include "lparser.h" @@ -38,8 +42,9 @@ static const char *const luaX_tokens [] = { "end", "false", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", - "..", "...", "==", ">=", "<=", "~=", "::", "", - "", "", "" + "//", "..", "...", "==", ">=", "<=", "~=", + "<<", ">>", "::", "", + "", "", "", "" }; @@ -53,7 +58,7 @@ static void save (LexState *ls, int c) { Mbuffer *b = ls->buff; if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { size_t newsize; - if (luaZ_sizebuffer(b) >= MAX_SIZET/2) + if (luaZ_sizebuffer(b) >= MAX_SIZE/2) lexerror(ls, "lexical element too long", 0); newsize = luaZ_sizebuffer(b) * 2; luaZ_resizebuffer(ls->L, b, newsize); @@ -64,24 +69,25 @@ static void save (LexState *ls, int c) { void luaX_init (lua_State *L) { int i; + TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */ + luaC_fix(L, obj2gco(e)); /* never collect this name */ for (i=0; itsv.extra = cast_byte(i+1); /* reserved word */ + luaC_fix(L, obj2gco(ts)); /* reserved words are never collected */ + ts->extra = cast_byte(i+1); /* reserved word */ } } const char *luaX_token2str (LexState *ls, int token) { if (token < FIRST_RESERVED) { /* single-byte symbols? */ - lua_assert(token == cast(unsigned char, token)); - return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) : - luaO_pushfstring(ls->L, "char(%d)", token); + lua_assert(token == cast_uchar(token)); + return luaO_pushfstring(ls->L, "'%c'", token); } else { const char *s = luaX_tokens[token - FIRST_RESERVED]; if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ - return luaO_pushfstring(ls->L, LUA_QS, s); + return luaO_pushfstring(ls->L, "'%s'", s); else /* names, strings, and numerals */ return s; } @@ -90,11 +96,10 @@ const char *luaX_token2str (LexState *ls, int token) { static const char *txtToken (LexState *ls, int token) { switch (token) { - case TK_NAME: - case TK_STRING: - case TK_NUMBER: + case TK_NAME: case TK_STRING: + case TK_FLT: case TK_INT: save(ls, '\0'); - return luaO_pushfstring(ls->L, LUA_QS, luaZ_buffer(ls->buff)); + return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); default: return luaX_token2str(ls, token); } @@ -102,9 +107,7 @@ static const char *txtToken (LexState *ls, int token) { static l_noret lexerror (LexState *ls, const char *msg, int token) { - char buff[LUA_IDSIZE]; - luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE); - msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); + msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber); if (token) luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); luaD_throw(ls->L, LUA_ERRSYNTAX); @@ -117,24 +120,24 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) { /* -** creates a new string and anchors it in function's table so that -** it will not be collected until the end of the function's compilation -** (by that time it should be anchored in function's prototype) +** creates a new string and anchors it in scanner's table so that +** it will not be collected until the end of the compilation +** (by that time it should be anchored somewhere) */ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; - TValue *o; /* entry for `str' */ + TValue *o; /* entry for 'str' */ TString *ts = luaS_newlstr(L, str, l); /* create new string */ setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ - o = luaH_set(L, ls->fs->h, L->top - 1); - if (ttisnil(o)) { /* not in use yet? (see 'addK') */ + o = luaH_set(L, ls->h, L->top - 1); + if (ttisnil(o)) { /* not in use yet? */ /* boolean value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ setbvalue(o, 1); /* t[string] = true */ luaC_checkGC(L); } else { /* string already present */ - ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */ + ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ } L->top--; /* remove string from stack */ return ts; @@ -148,17 +151,17 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { static void inclinenumber (LexState *ls) { int old = ls->current; lua_assert(currIsNewline(ls)); - next(ls); /* skip `\n' or `\r' */ + next(ls); /* skip '\n' or '\r' */ if (currIsNewline(ls) && ls->current != old) - next(ls); /* skip `\n\r' or `\r\n' */ + next(ls); /* skip '\n\r' or '\r\n' */ if (++ls->linenumber >= MAX_INT) - luaX_syntaxerror(ls, "chunk has too many lines"); + lexerror(ls, "chunk has too many lines", 0); } void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, int firstchar) { - ls->decpoint = '.'; + ls->t.token = 0; ls->L = L; ls->current = firstchar; ls->lookahead.token = TK_EOS; /* no look-ahead token */ @@ -167,8 +170,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, ls->linenumber = 1; ls->lastline = 1; ls->source = source; - ls->envn = luaS_new(L, LUA_ENV); /* create env name */ - luaS_fix(ls->envn); /* never collect this name */ + ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */ luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ } @@ -181,78 +183,70 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, */ - -static int check_next (LexState *ls, const char *set) { - if (ls->current == '\0' || !strchr(set, ls->current)) - return 0; - save_and_next(ls); - return 1; -} - - -/* -** change all characters 'from' in buffer to 'to' -*/ -static void buffreplace (LexState *ls, char from, char to) { - size_t n = luaZ_bufflen(ls->buff); - char *p = luaZ_buffer(ls->buff); - while (n--) - if (p[n] == from) p[n] = to; +static int check_next1 (LexState *ls, int c) { + if (ls->current == c) { + next(ls); + return 1; + } + else return 0; } -#if !defined(getlocaledecpoint) -#define getlocaledecpoint() (localeconv()->decimal_point[0]) -#endif - - -#define buff2d(b,e) luaO_str2d(luaZ_buffer(b), luaZ_bufflen(b) - 1, e) - /* -** in case of format error, try to change decimal point separator to -** the one defined in the current locale and check again +** Check whether current char is in set 'set' (with two chars) and +** saves it */ -static void trydecpoint (LexState *ls, SemInfo *seminfo) { - char old = ls->decpoint; - ls->decpoint = getlocaledecpoint(); - buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ - if (!buff2d(ls->buff, &seminfo->r)) { - /* format error with correct decimal point: no more options */ - buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ - lexerror(ls, "malformed number", TK_NUMBER); +static int check_next2 (LexState *ls, const char *set) { + lua_assert(set[2] == '\0'); + if (ls->current == set[0] || ls->current == set[1]) { + save_and_next(ls); + return 1; } + else return 0; } /* LUA_NUMBER */ /* -** this function is quite liberal in what it accepts, as 'luaO_str2d' +** this function is quite liberal in what it accepts, as 'luaO_str2num' ** will reject ill-formed numerals. */ -static void read_numeral (LexState *ls, SemInfo *seminfo) { +static int read_numeral (LexState *ls, SemInfo *seminfo) { + TValue obj; const char *expo = "Ee"; int first = ls->current; lua_assert(lisdigit(ls->current)); save_and_next(ls); - if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ + if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ expo = "Pp"; for (;;) { - if (check_next(ls, expo)) /* exponent part? */ - check_next(ls, "+-"); /* optional exponent sign */ - if (lisxdigit(ls->current) || ls->current == '.') + if (check_next2(ls, expo)) /* exponent part? */ + check_next2(ls, "-+"); /* optional exponent sign */ + if (lisxdigit(ls->current)) + save_and_next(ls); + else if (ls->current == '.') save_and_next(ls); - else break; + else break; } save(ls, '\0'); - buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ - if (!buff2d(ls->buff, &seminfo->r)) /* format error? */ - trydecpoint(ls, seminfo); /* try to update decimal point separator */ + if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ + lexerror(ls, "malformed number", TK_FLT); + if (ttisinteger(&obj)) { + seminfo->i = ivalue(&obj); + return TK_INT; + } + else { + lua_assert(ttisfloat(&obj)); + seminfo->r = fltvalue(&obj); + return TK_FLT; + } } /* -** skip a sequence '[=*[' or ']=*]' and return its number of '='s or -** -1 if sequence is malformed +** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return +** its number of '='s; otherwise, return a negative number (-1 iff there +** are no '='s after initial bracket) */ static int skip_sep (LexState *ls) { int count = 0; @@ -268,18 +262,22 @@ static int skip_sep (LexState *ls) { static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { - save_and_next(ls); /* skip 2nd `[' */ + int line = ls->linenumber; /* initial line (for error message) */ + save_and_next(ls); /* skip 2nd '[' */ if (currIsNewline(ls)) /* string starts with a newline? */ inclinenumber(ls); /* skip it */ for (;;) { switch (ls->current) { - case EOZ: - lexerror(ls, (seminfo) ? "unfinished long string" : - "unfinished long comment", TK_EOS); + case EOZ: { /* error */ + const char *what = (seminfo ? "string" : "comment"); + const char *msg = luaO_pushfstring(ls->L, + "unfinished long %s (starting at line %d)", what, line); + lexerror(ls, msg, TK_EOS); break; /* to avoid warnings */ + } case ']': { if (skip_sep(ls) == sep) { - save_and_next(ls); /* skip 2nd `]' */ + save_and_next(ls); /* skip 2nd ']' */ goto endloop; } break; @@ -302,40 +300,65 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { } -static void escerror (LexState *ls, int *c, int n, const char *msg) { - int i; - luaZ_resetbuffer(ls->buff); /* prepare error message */ - save(ls, '\\'); - for (i = 0; i < n && c[i] != EOZ; i++) - save(ls, c[i]); - lexerror(ls, msg, TK_STRING); +static void esccheck (LexState *ls, int c, const char *msg) { + if (!c) { + if (ls->current != EOZ) + save_and_next(ls); /* add current to buffer for error message */ + lexerror(ls, msg, TK_STRING); + } +} + + +static int gethexa (LexState *ls) { + save_and_next(ls); + esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected"); + return luaO_hexavalue(ls->current); } static int readhexaesc (LexState *ls) { - int c[3], i; /* keep input for error message */ - int r = 0; /* result accumulator */ - c[0] = 'x'; /* for error message */ - for (i = 1; i < 3; i++) { /* read two hexadecimal digits */ - c[i] = next(ls); - if (!lisxdigit(c[i])) - escerror(ls, c, i + 1, "hexadecimal digit expected"); - r = (r << 4) + luaO_hexavalue(c[i]); + int r = gethexa(ls); + r = (r << 4) + gethexa(ls); + luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ + return r; +} + + +static unsigned long readutf8esc (LexState *ls) { + unsigned long r; + int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ + save_and_next(ls); /* skip 'u' */ + esccheck(ls, ls->current == '{', "missing '{'"); + r = gethexa(ls); /* must have at least one digit */ + while ((save_and_next(ls), lisxdigit(ls->current))) { + i++; + r = (r << 4) + luaO_hexavalue(ls->current); + esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large"); } + esccheck(ls, ls->current == '}', "missing '}'"); + next(ls); /* skip '}' */ + luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ return r; } +static void utf8esc (LexState *ls) { + char buff[UTF8BUFFSZ]; + int n = luaO_utf8esc(buff, readutf8esc(ls)); + for (; n > 0; n--) /* add 'buff' to string */ + save(ls, buff[UTF8BUFFSZ - n]); +} + + static int readdecesc (LexState *ls) { - int c[3], i; + int i; int r = 0; /* result accumulator */ for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ - c[i] = ls->current; - r = 10*r + c[i] - '0'; - next(ls); + r = 10*r + ls->current - '0'; + save_and_next(ls); } - if (r > UCHAR_MAX) - escerror(ls, c, i, "decimal escape too large"); + esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); + luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ return r; } @@ -353,7 +376,7 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { break; /* to avoid warnings */ case '\\': { /* escape sequences */ int c; /* final character to be saved */ - next(ls); /* do not save the `\' */ + save_and_next(ls); /* keep '\\' for error messages */ switch (ls->current) { case 'a': c = '\a'; goto read_save; case 'b': c = '\b'; goto read_save; @@ -363,12 +386,14 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { case 't': c = '\t'; goto read_save; case 'v': c = '\v'; goto read_save; case 'x': c = readhexaesc(ls); goto read_save; + case 'u': utf8esc(ls); goto no_save; case '\n': case '\r': inclinenumber(ls); c = '\n'; goto only_save; case '\\': case '\"': case '\'': c = ls->current; goto read_save; case EOZ: goto no_save; /* will raise an error next loop */ case 'z': { /* zap following span of spaces */ + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ next(ls); /* skip the 'z' */ while (lisspace(ls->current)) { if (currIsNewline(ls)) inclinenumber(ls); @@ -377,15 +402,18 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { goto no_save; } default: { - if (!lisdigit(ls->current)) - escerror(ls, &ls->current, 1, "invalid escape sequence"); - /* digital escape \ddd */ - c = readdecesc(ls); + esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); + c = readdecesc(ls); /* digital escape '\ddd' */ goto only_save; } } - read_save: next(ls); /* read next character */ - only_save: save(ls, c); /* save 'c' */ + read_save: + next(ls); + /* go through */ + only_save: + luaZ_buffremove(ls->buff, 1); /* remove '\\' */ + save(ls, c); + /* go through */ no_save: break; } default: @@ -417,7 +445,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { next(ls); if (ls->current == '[') { /* long comment? */ int sep = skip_sep(ls); - luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ + luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ if (sep >= 0) { read_long_string(ls, NULL, sep); /* skip long comment */ luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ @@ -435,33 +463,41 @@ static int llex (LexState *ls, SemInfo *seminfo) { read_long_string(ls, seminfo, sep); return TK_STRING; } - else if (sep == -1) return '['; - else lexerror(ls, "invalid long string delimiter", TK_STRING); + else if (sep != -1) /* '[=...' missing second bracket */ + lexerror(ls, "invalid long string delimiter", TK_STRING); + return '['; } case '=': { next(ls); - if (ls->current != '=') return '='; - else { next(ls); return TK_EQ; } + if (check_next1(ls, '=')) return TK_EQ; + else return '='; } case '<': { next(ls); - if (ls->current != '=') return '<'; - else { next(ls); return TK_LE; } + if (check_next1(ls, '=')) return TK_LE; + else if (check_next1(ls, '<')) return TK_SHL; + else return '<'; } case '>': { next(ls); - if (ls->current != '=') return '>'; - else { next(ls); return TK_GE; } + if (check_next1(ls, '=')) return TK_GE; + else if (check_next1(ls, '>')) return TK_SHR; + else return '>'; + } + case '/': { + next(ls); + if (check_next1(ls, '/')) return TK_IDIV; + else return '/'; } case '~': { next(ls); - if (ls->current != '=') return '~'; - else { next(ls); return TK_NE; } + if (check_next1(ls, '=')) return TK_NE; + else return '~'; } case ':': { next(ls); - if (ls->current != ':') return ':'; - else { next(ls); return TK_DBCOLON; } + if (check_next1(ls, ':')) return TK_DBCOLON; + else return ':'; } case '"': case '\'': { /* short literal strings */ read_string(ls, ls->current, seminfo); @@ -469,18 +505,17 @@ static int llex (LexState *ls, SemInfo *seminfo) { } case '.': { /* '.', '..', '...', or number */ save_and_next(ls); - if (check_next(ls, ".")) { - if (check_next(ls, ".")) + if (check_next1(ls, '.')) { + if (check_next1(ls, '.')) return TK_DOTS; /* '...' */ else return TK_CONCAT; /* '..' */ } else if (!lisdigit(ls->current)) return '.'; - /* else go through */ + else return read_numeral(ls, seminfo); } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { - read_numeral(ls, seminfo); - return TK_NUMBER; + return read_numeral(ls, seminfo); } case EOZ: { return TK_EOS; @@ -495,7 +530,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { luaZ_bufflen(ls->buff)); seminfo->ts = ts; if (isreserved(ts)) /* reserved word? */ - return ts->tsv.extra - 1 + FIRST_RESERVED; + return ts->extra - 1 + FIRST_RESERVED; else { return TK_NAME; } diff --git a/depends/lua/src/lmathlib.c b/depends/lua/src/lmathlib.c index fe9fc5423..94815f129 100644 --- a/depends/lua/src/lmathlib.c +++ b/depends/lua/src/lmathlib.c @@ -1,16 +1,18 @@ /* -** $Id: lmathlib.c,v 1.83.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lmathlib.c,v 1.117 2015/10/02 15:39:23 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ +#define lmathlib_c +#define LUA_LIB + +#include "lprefix.h" + #include #include -#define lmathlib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -18,13 +20,30 @@ #undef PI -#define PI ((lua_Number)(3.1415926535897932384626433832795)) -#define RADIANS_PER_DEGREE ((lua_Number)(PI/180.0)) - +#define PI (l_mathop(3.141592653589793238462643383279502884)) + + +#if !defined(l_rand) /* { */ +#if defined(LUA_USE_POSIX) +#define l_rand() random() +#define l_srand(x) srandom(x) +#define L_RANDMAX 2147483647 /* (2^31 - 1), following POSIX */ +#else +#define l_rand() rand() +#define l_srand(x) srand(x) +#define L_RANDMAX RAND_MAX +#endif +#endif /* } */ static int math_abs (lua_State *L) { - lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); + if (lua_isinteger(L, 1)) { + lua_Integer n = lua_tointeger(L, 1); + if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); + lua_pushinteger(L, n); + } + else + lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); return 1; } @@ -33,31 +52,16 @@ static int math_sin (lua_State *L) { return 1; } -static int math_sinh (lua_State *L) { - lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); - return 1; -} - static int math_cos (lua_State *L) { lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); return 1; } -static int math_cosh (lua_State *L) { - lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); - return 1; -} - static int math_tan (lua_State *L) { lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); return 1; } -static int math_tanh (lua_State *L) { - lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); - return 1; -} - static int math_asin (lua_State *L) { lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); return 1; @@ -69,49 +73,106 @@ static int math_acos (lua_State *L) { } static int math_atan (lua_State *L) { - lua_pushnumber(L, l_mathop(atan)(luaL_checknumber(L, 1))); + lua_Number y = luaL_checknumber(L, 1); + lua_Number x = luaL_optnumber(L, 2, 1); + lua_pushnumber(L, l_mathop(atan2)(y, x)); return 1; } -static int math_atan2 (lua_State *L) { - lua_pushnumber(L, l_mathop(atan2)(luaL_checknumber(L, 1), - luaL_checknumber(L, 2))); + +static int math_toint (lua_State *L) { + int valid; + lua_Integer n = lua_tointegerx(L, 1, &valid); + if (valid) + lua_pushinteger(L, n); + else { + luaL_checkany(L, 1); + lua_pushnil(L); /* value is not convertible to integer */ + } return 1; } -static int math_ceil (lua_State *L) { - lua_pushnumber(L, l_mathop(ceil)(luaL_checknumber(L, 1))); - return 1; + +static void pushnumint (lua_State *L, lua_Number d) { + lua_Integer n; + if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ + lua_pushinteger(L, n); /* result is integer */ + else + lua_pushnumber(L, d); /* result is float */ } + static int math_floor (lua_State *L) { - lua_pushnumber(L, l_mathop(floor)(luaL_checknumber(L, 1))); + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own floor */ + else { + lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } + return 1; +} + + +static int math_ceil (lua_State *L) { + if (lua_isinteger(L, 1)) + lua_settop(L, 1); /* integer is its own ceil */ + else { + lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); + pushnumint(L, d); + } return 1; } + static int math_fmod (lua_State *L) { - lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), - luaL_checknumber(L, 2))); + if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { + lua_Integer d = lua_tointeger(L, 2); + if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ + luaL_argcheck(L, d != 0, 2, "zero"); + lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ + } + else + lua_pushinteger(L, lua_tointeger(L, 1) % d); + } + else + lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), + luaL_checknumber(L, 2))); return 1; } + +/* +** next function does not use 'modf', avoiding problems with 'double*' +** (which is not compatible with 'float*') when lua_Number is not +** 'double'. +*/ static int math_modf (lua_State *L) { - lua_Number ip; - lua_Number fp = l_mathop(modf)(luaL_checknumber(L, 1), &ip); - lua_pushnumber(L, ip); - lua_pushnumber(L, fp); + if (lua_isinteger(L ,1)) { + lua_settop(L, 1); /* number is its own integer part */ + lua_pushnumber(L, 0); /* no fractional part */ + } + else { + lua_Number n = luaL_checknumber(L, 1); + /* integer part (rounds toward zero) */ + lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); + pushnumint(L, ip); + /* fractional part (test needed for inf/-inf) */ + lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); + } return 2; } + static int math_sqrt (lua_State *L) { lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); return 1; } -static int math_pow (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - lua_Number y = luaL_checknumber(L, 2); - lua_pushnumber(L, l_mathop(pow)(x, y)); + +static int math_ult (lua_State *L) { + lua_Integer a = luaL_checkinteger(L, 1); + lua_Integer b = luaL_checkinteger(L, 2); + lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); return 1; } @@ -122,145 +183,208 @@ static int math_log (lua_State *L) { res = l_mathop(log)(x); else { lua_Number base = luaL_checknumber(L, 2); - if (base == (lua_Number)10.0) res = l_mathop(log10)(x); +#if !defined(LUA_USE_C89) + if (base == 2.0) res = l_mathop(log2)(x); else +#endif + if (base == 10.0) res = l_mathop(log10)(x); else res = l_mathop(log)(x)/l_mathop(log)(base); } lua_pushnumber(L, res); return 1; } -#if defined(LUA_COMPAT_LOG10) -static int math_log10 (lua_State *L) { - lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); - return 1; -} -#endif - static int math_exp (lua_State *L) { lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); return 1; } static int math_deg (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); + lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); return 1; } static int math_rad (lua_State *L) { - lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); - return 1; -} - -static int math_frexp (lua_State *L) { - int e; - lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); - lua_pushinteger(L, e); - return 2; -} - -static int math_ldexp (lua_State *L) { - lua_Number x = luaL_checknumber(L, 1); - int ep = luaL_checkint(L, 2); - lua_pushnumber(L, l_mathop(ldexp)(x, ep)); + lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); return 1; } - static int math_min (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ - lua_Number dmin = luaL_checknumber(L, 1); + int imin = 1; /* index of current minimum value */ int i; - for (i=2; i<=n; i++) { - lua_Number d = luaL_checknumber(L, i); - if (d < dmin) - dmin = d; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, i, imin, LUA_OPLT)) + imin = i; } - lua_pushnumber(L, dmin); + lua_pushvalue(L, imin); return 1; } static int math_max (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ - lua_Number dmax = luaL_checknumber(L, 1); + int imax = 1; /* index of current maximum value */ int i; - for (i=2; i<=n; i++) { - lua_Number d = luaL_checknumber(L, i); - if (d > dmax) - dmax = d; + luaL_argcheck(L, n >= 1, 1, "value expected"); + for (i = 2; i <= n; i++) { + if (lua_compare(L, imax, i, LUA_OPLT)) + imax = i; } - lua_pushnumber(L, dmax); + lua_pushvalue(L, imax); return 1; } - +/* +** This function uses 'double' (instead of 'lua_Number') to ensure that +** all bits from 'l_rand' can be represented, and that 'RANDMAX + 1.0' +** will keep full precision (ensuring that 'r' is always less than 1.0.) +*/ static int math_random (lua_State *L) { - /* the `%' avoids the (rare) case of r==1, and is needed also because on - some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ - lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX; + lua_Integer low, up; + double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0)); switch (lua_gettop(L)) { /* check number of arguments */ case 0: { /* no arguments */ - lua_pushnumber(L, r); /* Number between 0 and 1 */ - break; + lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */ + return 1; } case 1: { /* only upper limit */ - lua_Number u = luaL_checknumber(L, 1); - luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty"); - lua_pushnumber(L, l_mathop(floor)(r*u) + (lua_Number)(1.0)); /* [1, u] */ + low = 1; + up = luaL_checkinteger(L, 1); break; } case 2: { /* lower and upper limits */ - lua_Number l = luaL_checknumber(L, 1); - lua_Number u = luaL_checknumber(L, 2); - luaL_argcheck(L, l <= u, 2, "interval is empty"); - lua_pushnumber(L, l_mathop(floor)(r*(u-l+1)) + l); /* [l, u] */ + low = luaL_checkinteger(L, 1); + up = luaL_checkinteger(L, 2); break; } default: return luaL_error(L, "wrong number of arguments"); } + /* random integer in the interval [low, up] */ + luaL_argcheck(L, low <= up, 1, "interval is empty"); + luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, + "interval too large"); + r *= (double)(up - low) + 1.0; + lua_pushinteger(L, (lua_Integer)r + low); return 1; } static int math_randomseed (lua_State *L) { - srand(luaL_checkunsigned(L, 1)); - (void)rand(); /* discard first value to avoid undesirable correlations */ + l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1)); + (void)l_rand(); /* discard first value to avoid undesirable correlations */ return 0; } +static int math_type (lua_State *L) { + if (lua_type(L, 1) == LUA_TNUMBER) { + if (lua_isinteger(L, 1)) + lua_pushliteral(L, "integer"); + else + lua_pushliteral(L, "float"); + } + else { + luaL_checkany(L, 1); + lua_pushnil(L); + } + return 1; +} + + +/* +** {================================================================== +** Deprecated functions (for compatibility only) +** =================================================================== +*/ +#if defined(LUA_COMPAT_MATHLIB) + +static int math_cosh (lua_State *L) { + lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_sinh (lua_State *L) { + lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_tanh (lua_State *L) { + lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); + return 1; +} + +static int math_pow (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + lua_Number y = luaL_checknumber(L, 2); + lua_pushnumber(L, l_mathop(pow)(x, y)); + return 1; +} + +static int math_frexp (lua_State *L) { + int e; + lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); + lua_pushinteger(L, e); + return 2; +} + +static int math_ldexp (lua_State *L) { + lua_Number x = luaL_checknumber(L, 1); + int ep = (int)luaL_checkinteger(L, 2); + lua_pushnumber(L, l_mathop(ldexp)(x, ep)); + return 1; +} + +static int math_log10 (lua_State *L) { + lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); + return 1; +} + +#endif +/* }================================================================== */ + + + static const luaL_Reg mathlib[] = { {"abs", math_abs}, {"acos", math_acos}, {"asin", math_asin}, - {"atan2", math_atan2}, {"atan", math_atan}, {"ceil", math_ceil}, - {"cosh", math_cosh}, {"cos", math_cos}, {"deg", math_deg}, {"exp", math_exp}, + {"tointeger", math_toint}, {"floor", math_floor}, {"fmod", math_fmod}, - {"frexp", math_frexp}, - {"ldexp", math_ldexp}, -#if defined(LUA_COMPAT_LOG10) - {"log10", math_log10}, -#endif + {"ult", math_ult}, {"log", math_log}, {"max", math_max}, {"min", math_min}, {"modf", math_modf}, - {"pow", math_pow}, {"rad", math_rad}, {"random", math_random}, {"randomseed", math_randomseed}, - {"sinh", math_sinh}, {"sin", math_sin}, {"sqrt", math_sqrt}, - {"tanh", math_tanh}, {"tan", math_tan}, + {"type", math_type}, +#if defined(LUA_COMPAT_MATHLIB) + {"atan2", math_atan}, + {"cosh", math_cosh}, + {"sinh", math_sinh}, + {"tanh", math_tanh}, + {"pow", math_pow}, + {"frexp", math_frexp}, + {"ldexp", math_ldexp}, + {"log10", math_log10}, +#endif + /* placeholders */ + {"pi", NULL}, + {"huge", NULL}, + {"maxinteger", NULL}, + {"mininteger", NULL}, {NULL, NULL} }; @@ -272,8 +396,12 @@ LUAMOD_API int luaopen_math (lua_State *L) { luaL_newlib(L, mathlib); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); - lua_pushnumber(L, HUGE_VAL); + lua_pushnumber(L, (lua_Number)HUGE_VAL); lua_setfield(L, -2, "huge"); + lua_pushinteger(L, LUA_MAXINTEGER); + lua_setfield(L, -2, "maxinteger"); + lua_pushinteger(L, LUA_MININTEGER); + lua_setfield(L, -2, "mininteger"); return 1; } diff --git a/depends/lua/src/lmem.c b/depends/lua/src/lmem.c index ee343e3e0..0a0476cc7 100644 --- a/depends/lua/src/lmem.c +++ b/depends/lua/src/lmem.c @@ -1,15 +1,17 @@ /* -** $Id: lmem.c,v 1.84.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ - -#include - #define lmem_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "ldebug.h" @@ -24,15 +26,15 @@ /* ** About the realloc function: ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); -** (`osize' is the old size, `nsize' is the new size) +** ('osize' is the old size, 'nsize' is the new size) ** -** * frealloc(ud, NULL, x, s) creates a new block of size `s' (no +** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no ** matter 'x'). ** -** * frealloc(ud, p, x, 0) frees the block `p' +** * frealloc(ud, p, x, 0) frees the block 'p' ** (in this specific case, frealloc must return NULL); ** particularly, frealloc(ud, NULL, 0, 0) does nothing -** (which is equivalent to free(NULL) in ANSI C) +** (which is equivalent to free(NULL) in ISO C) ** ** frealloc returns NULL if it cannot create or reallocate the area ** (any reallocation to an equal or smaller size cannot fail!) @@ -83,9 +85,8 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { #endif newblock = (*g->frealloc)(g->ud, block, osize, nsize); if (newblock == NULL && nsize > 0) { - api_check(L, nsize > realosize, - "realloc cannot fail when shrinking a block"); - if (g->gcrunning) { + lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ + if (g->version) { /* is state fully built? */ luaC_fullgc(L, 1); /* try to free some memory... */ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ } diff --git a/depends/lua/src/loadlib.c b/depends/lua/src/loadlib.c index bedbea3e9..79119287a 100644 --- a/depends/lua/src/loadlib.c +++ b/depends/lua/src/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.111.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: loadlib.c,v 1.127 2015/11/23 11:30:45 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -8,22 +8,16 @@ ** systems. */ +#define loadlib_c +#define LUA_LIB -/* -** if needed, includes windows header before everything else -*/ -#if defined(_WIN32) -#include -#endif +#include "lprefix.h" +#include #include #include - -#define loadlib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -31,21 +25,21 @@ /* -** LUA_PATH and LUA_CPATH are the names of the environment +** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment ** variables that Lua check to set its paths. */ -#if !defined(LUA_PATH) -#define LUA_PATH "LUA_PATH" +#if !defined(LUA_PATH_VAR) +#define LUA_PATH_VAR "LUA_PATH" #endif -#if !defined(LUA_CPATH) -#define LUA_CPATH "LUA_CPATH" +#if !defined(LUA_CPATH_VAR) +#define LUA_CPATH_VAR "LUA_CPATH" #endif #define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR -#define LUA_PATHVERSION LUA_PATH LUA_PATHSUFFIX -#define LUA_CPATHVERSION LUA_CPATH LUA_PATHSUFFIX +#define LUA_PATHVARVERSION LUA_PATH_VAR LUA_PATHSUFFIX +#define LUA_CPATHVARVERSION LUA_CPATH_VAR LUA_PATHSUFFIX /* ** LUA_PATH_SEP is the character that separates templates in a path. @@ -92,29 +86,45 @@ #define LUA_OFSEP "_" -/* table (in the registry) that keeps handles for all loaded C libraries */ -#define CLIBS "_CLIBS" +/* +** unique key for table in the registry that keeps handles +** for all loaded C libraries +*/ +static const int CLIBS = 0; #define LIB_FAIL "open" - -/* error codes for ll_loadfunc */ -#define ERRLIB 1 -#define ERRFUNC 2 - #define setprogdir(L) ((void)0) /* ** system-dependent functions */ -static void ll_unloadlib (void *lib); -static void *ll_load (lua_State *L, const char *path, int seeglb); -static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); +/* +** unload library 'lib' +*/ +static void lsys_unloadlib (void *lib); + +/* +** load C library in file 'path'. If 'seeglb', load with all names in +** the library global. +** Returns the library; in case of error, returns NULL plus an +** error string in the stack. +*/ +static void *lsys_load (lua_State *L, const char *path, int seeglb); + +/* +** Try to find a function named 'sym' in library 'lib'. +** Returns the function; in case of error, returns NULL plus an +** error string in the stack. +*/ +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); -#if defined(LUA_USE_DLOPEN) + + +#if defined(LUA_USE_DLOPEN) /* { */ /* ** {======================================================================== ** This is an implementation of loadlib based on the dlfcn interface. @@ -126,20 +136,32 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); #include -static void ll_unloadlib (void *lib) { +/* +** Macro to convert pointer-to-void* to pointer-to-function. This cast +** is undefined according to ISO C, but POSIX assumes that it works. +** (The '__extension__' in gnu compilers is only to avoid warnings.) +*/ +#if defined(__GNUC__) +#define cast_func(p) (__extension__ (lua_CFunction)(p)) +#else +#define cast_func(p) ((lua_CFunction)(p)) +#endif + + +static void lsys_unloadlib (void *lib) { dlclose(lib); } -static void *ll_load (lua_State *L, const char *path, int seeglb) { +static void *lsys_load (lua_State *L, const char *path, int seeglb) { void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); if (lib == NULL) lua_pushstring(L, dlerror()); return lib; } -static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { - lua_CFunction f = (lua_CFunction)dlsym(lib, sym); +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { + lua_CFunction f = cast_func(dlsym(lib, sym)); if (f == NULL) lua_pushstring(L, dlerror()); return f; } @@ -148,13 +170,15 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { -#elif defined(LUA_DL_DLL) +#elif defined(LUA_DL_DLL) /* }{ */ /* ** {====================================================================== ** This is an implementation of loadlib for Windows using native functions. ** ======================================================================= */ +#include + #undef setprogdir /* @@ -190,12 +214,12 @@ static void pusherror (lua_State *L) { lua_pushfstring(L, "system error %d\n", error); } -static void ll_unloadlib (void *lib) { +static void lsys_unloadlib (void *lib) { FreeLibrary((HMODULE)lib); } -static void *ll_load (lua_State *L, const char *path, int seeglb) { +static void *lsys_load (lua_State *L, const char *path, int seeglb) { HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); (void)(seeglb); /* not used: symbols are 'global' by default */ if (lib == NULL) pusherror(L); @@ -203,7 +227,7 @@ static void *ll_load (lua_State *L, const char *path, int seeglb) { } -static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); if (f == NULL) pusherror(L); return f; @@ -212,7 +236,7 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { /* }====================================================== */ -#else +#else /* }{ */ /* ** {====================================================== ** Fallback for other systems @@ -226,31 +250,34 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #define DLMSG "dynamic libraries not enabled; check your Lua installation" -static void ll_unloadlib (void *lib) { +static void lsys_unloadlib (void *lib) { (void)(lib); /* not used */ } -static void *ll_load (lua_State *L, const char *path, int seeglb) { +static void *lsys_load (lua_State *L, const char *path, int seeglb) { (void)(path); (void)(seeglb); /* not used */ lua_pushliteral(L, DLMSG); return NULL; } -static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { +static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { (void)(lib); (void)(sym); /* not used */ lua_pushliteral(L, DLMSG); return NULL; } /* }====================================================== */ -#endif +#endif /* } */ -static void *ll_checkclib (lua_State *L, const char *path) { +/* +** return registry.CLIBS[path] +*/ +static void *checkclib (lua_State *L, const char *path) { void *plib; - lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); lua_getfield(L, -1, path); plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ lua_pop(L, 2); /* pop CLIBS table and 'plib' */ @@ -258,8 +285,12 @@ static void *ll_checkclib (lua_State *L, const char *path) { } -static void ll_addtoclib (lua_State *L, const char *path, void *plib) { - lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); +/* +** registry.CLIBS[path] = plib -- for queries +** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries +*/ +static void addtoclib (lua_State *L, const char *path, void *plib) { + lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); lua_pushlightuserdata(L, plib); lua_pushvalue(L, -1); lua_setfield(L, -3, path); /* CLIBS[path] = plib */ @@ -269,33 +300,49 @@ static void ll_addtoclib (lua_State *L, const char *path, void *plib) { /* -** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib +** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib ** handles in list CLIBS */ static int gctm (lua_State *L) { - int n = luaL_len(L, 1); + lua_Integer n = luaL_len(L, 1); for (; n >= 1; n--) { /* for each handle, in reverse order */ lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ - ll_unloadlib(lua_touserdata(L, -1)); + lsys_unloadlib(lua_touserdata(L, -1)); lua_pop(L, 1); /* pop handle */ } return 0; } -static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { - void *reg = ll_checkclib(L, path); /* check loaded C libraries */ + +/* error codes for 'lookforfunc' */ +#define ERRLIB 1 +#define ERRFUNC 2 + +/* +** Look for a C function named 'sym' in a dynamically loaded library +** 'path'. +** First, check whether the library is already loaded; if not, try +** to load it. +** Then, if 'sym' is '*', return true (as library has been loaded). +** Otherwise, look for symbol 'sym' in the library and push a +** C function with that symbol. +** Return 0 and 'true' or a function in the stack; in case of +** errors, return an error code and an error message in the stack. +*/ +static int lookforfunc (lua_State *L, const char *path, const char *sym) { + void *reg = checkclib(L, path); /* check loaded C libraries */ if (reg == NULL) { /* must load library? */ - reg = ll_load(L, path, *sym == '*'); + reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ if (reg == NULL) return ERRLIB; /* unable to load library */ - ll_addtoclib(L, path, reg); + addtoclib(L, path, reg); } if (*sym == '*') { /* loading only library (no function)? */ lua_pushboolean(L, 1); /* return 'true' */ return 0; /* no errors */ } else { - lua_CFunction f = ll_sym(L, reg, sym); + lua_CFunction f = lsys_sym(L, reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ lua_pushcfunction(L, f); /* else create new function */ @@ -307,7 +354,7 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { static int ll_loadlib (lua_State *L) { const char *path = luaL_checkstring(L, 1); const char *init = luaL_checkstring(L, 2); - int stat = ll_loadfunc(L, path, init); + int stat = lookforfunc(L, path, init); if (stat == 0) /* no errors? */ return 1; /* return the loaded function */ else { /* error; error message is on stack top */ @@ -360,7 +407,7 @@ static const char *searchpath (lua_State *L, const char *name, lua_remove(L, -2); /* remove path template */ if (readable(filename)) /* does file exist and is readable? */ return filename; /* return that file name */ - lua_pushfstring(L, "\n\tno file " LUA_QS, filename); + lua_pushfstring(L, "\n\tno file '%s'", filename); lua_remove(L, -2); /* remove file name */ luaL_addvalue(&msg); /* concatenate error msg. entry */ } @@ -390,7 +437,7 @@ static const char *findfile (lua_State *L, const char *name, lua_getfield(L, lua_upvalueindex(1), pname); path = lua_tostring(L, -1); if (path == NULL) - luaL_error(L, LUA_QL("package.%s") " must be a string", pname); + luaL_error(L, "'package.%s' must be a string", pname); return searchpath(L, name, path, ".", dirsep); } @@ -401,8 +448,7 @@ static int checkload (lua_State *L, int stat, const char *filename) { return 2; /* return open function and file name */ } else - return luaL_error(L, "error loading module " LUA_QS - " from file " LUA_QS ":\n\t%s", + return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", lua_tostring(L, 1), filename, lua_tostring(L, -1)); } @@ -416,21 +462,29 @@ static int searcher_Lua (lua_State *L) { } +/* +** Try to find a load function for module 'modname' at file 'filename'. +** First, change '.' to '_' in 'modname'; then, if 'modname' has +** the form X-Y (that is, it has an "ignore mark"), build a function +** name "luaopen_X" and look for it. (For compatibility, if that +** fails, it also tries "luaopen_Y".) If there is no ignore mark, +** look for a function named "luaopen_modname". +*/ static int loadfunc (lua_State *L, const char *filename, const char *modname) { - const char *funcname; + const char *openfunc; const char *mark; modname = luaL_gsub(L, modname, ".", LUA_OFSEP); mark = strchr(modname, *LUA_IGMARK); if (mark) { int stat; - funcname = lua_pushlstring(L, modname, mark - modname); - funcname = lua_pushfstring(L, LUA_POF"%s", funcname); - stat = ll_loadfunc(L, filename, funcname); + openfunc = lua_pushlstring(L, modname, mark - modname); + openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); + stat = lookforfunc(L, filename, openfunc); if (stat != ERRFUNC) return stat; modname = mark + 1; /* else go ahead and try old-style name */ } - funcname = lua_pushfstring(L, LUA_POF"%s", modname); - return ll_loadfunc(L, filename, funcname); + openfunc = lua_pushfstring(L, LUA_POF"%s", modname); + return lookforfunc(L, filename, openfunc); } @@ -455,8 +509,7 @@ static int searcher_Croot (lua_State *L) { if (stat != ERRFUNC) return checkload(L, 0, filename); /* real error */ else { /* open function not found */ - lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, - name, filename); + lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename); return 1; } } @@ -468,8 +521,7 @@ static int searcher_Croot (lua_State *L) { static int searcher_preload (lua_State *L) { const char *name = luaL_checkstring(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); - lua_getfield(L, -1, name); - if (lua_isnil(L, -1)) /* not found? */ + if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ lua_pushfstring(L, "\n\tno field package.preload['%s']", name); return 1; } @@ -479,17 +531,15 @@ static void findloader (lua_State *L, const char *name) { int i; luaL_Buffer msg; /* to build error message */ luaL_buffinit(L, &msg); - lua_getfield(L, lua_upvalueindex(1), "searchers"); /* will be at index 3 */ - if (!lua_istable(L, 3)) - luaL_error(L, LUA_QL("package.searchers") " must be a table"); + /* push 'package.searchers' to index 3 in the stack */ + if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) + luaL_error(L, "'package.searchers' must be a table"); /* iterate over available searchers to find a loader */ for (i = 1; ; i++) { - lua_rawgeti(L, 3, i); /* get a searcher */ - if (lua_isnil(L, -1)) { /* no more searchers? */ + if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ lua_pop(L, 1); /* remove nil */ luaL_pushresult(&msg); /* create error message */ - luaL_error(L, "module " LUA_QS " not found:%s", - name, lua_tostring(L, -1)); + luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); } lua_pushstring(L, name); lua_call(L, 1, 2); /* call it */ @@ -520,8 +570,7 @@ static int ll_require (lua_State *L) { lua_call(L, 2, 1); /* run loader to load module */ if (!lua_isnil(L, -1)) /* non-nil return? */ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ - lua_getfield(L, 2, name); - if (lua_isnil(L, -1)) { /* module did not set a value? */ + if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ lua_pushboolean(L, 1); /* use true as result */ lua_pushvalue(L, -1); /* extra copy to be returned */ lua_setfield(L, 2, name); /* _LOADED[name] = true */ @@ -548,7 +597,7 @@ static void set_env (lua_State *L) { if (lua_getstack(L, 1, &ar) == 0 || lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ lua_iscfunction(L, -1)) - luaL_error(L, LUA_QL("module") " not called from a Lua function"); + luaL_error(L, "'module' not called from a Lua function"); lua_pushvalue(L, -2); /* copy new environment table to top */ lua_setupvalue(L, -2, 1); lua_pop(L, 1); /* remove function */ @@ -587,9 +636,8 @@ static int ll_module (lua_State *L) { int lastarg = lua_gettop(L); /* last parameter */ luaL_pushmodule(L, modname, 1); /* get/create module table */ /* check whether table already has a _NAME field */ - lua_getfield(L, -1, "_NAME"); - if (!lua_isnil(L, -1)) /* is table an initialized module? */ - lua_pop(L, 1); + if (lua_getfield(L, -1, "_NAME") != LUA_TNIL) + lua_pop(L, 1); /* table is an initialized module */ else { /* no; initialize it */ lua_pop(L, 1); modinit(L, modname); @@ -659,6 +707,12 @@ static const luaL_Reg pk_funcs[] = { #if defined(LUA_COMPAT_MODULE) {"seeall", ll_seeall}, #endif + /* placeholders */ + {"preload", NULL}, + {"cpath", NULL}, + {"path", NULL}, + {"searchers", NULL}, + {"loaded", NULL}, {NULL, NULL} }; @@ -678,42 +732,50 @@ static void createsearcherstable (lua_State *L) { int i; /* create 'searchers' table */ lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); - /* fill it with pre-defined searchers */ + /* fill it with predefined searchers */ for (i=0; searchers[i] != NULL; i++) { lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ lua_pushcclosure(L, searchers[i], 1); lua_rawseti(L, -2, i+1); } +#if defined(LUA_COMPAT_LOADERS) + lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ + lua_setfield(L, -3, "loaders"); /* put it in field 'loaders' */ +#endif + lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ } -LUAMOD_API int luaopen_package (lua_State *L) { - /* create table CLIBS to keep track of loaded C libraries */ - luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); - lua_createtable(L, 0, 1); /* metatable for CLIBS */ +/* +** create table CLIBS to keep track of loaded C libraries, +** setting a finalizer to close all libraries when closing state. +*/ +static void createclibstable (lua_State *L) { + lua_newtable(L); /* create CLIBS table */ + lua_createtable(L, 0, 1); /* create metatable for CLIBS */ lua_pushcfunction(L, gctm); lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ lua_setmetatable(L, -2); - /* create `package' table */ - luaL_newlib(L, pk_funcs); + lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */ +} + + +LUAMOD_API int luaopen_package (lua_State *L) { + createclibstable(L); + luaL_newlib(L, pk_funcs); /* create 'package' table */ createsearcherstable(L); -#if defined(LUA_COMPAT_LOADERS) - lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ - lua_setfield(L, -3, "loaders"); /* put it in field `loaders' */ -#endif - lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ /* set field 'path' */ - setpath(L, "path", LUA_PATHVERSION, LUA_PATH, LUA_PATH_DEFAULT); + setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT); /* set field 'cpath' */ - setpath(L, "cpath", LUA_CPATHVERSION, LUA_CPATH, LUA_CPATH_DEFAULT); + setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, LUA_CPATH_DEFAULT); /* store config information */ lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); lua_setfield(L, -2, "config"); - /* set field `loaded' */ + /* set field 'loaded' */ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_setfield(L, -2, "loaded"); - /* set field `preload' */ + /* set field 'preload' */ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); lua_setfield(L, -2, "preload"); lua_pushglobaltable(L); diff --git a/depends/lua/src/lobject.c b/depends/lua/src/lobject.c index 882d994d4..a44b3850f 100644 --- a/depends/lua/src/lobject.c +++ b/depends/lua/src/lobject.c @@ -1,17 +1,22 @@ /* -** $Id: lobject.c,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lobject.c,v 2.111 2016/05/20 14:07:48 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ +#define lobject_c +#define LUA_CORE + +#include "lprefix.h" + + +#include +#include #include #include #include #include -#define lobject_c -#define LUA_CORE - #include "lua.h" #include "lctype.h" @@ -36,8 +41,12 @@ LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; int luaO_int2fb (unsigned int x) { int e = 0; /* exponent */ if (x < 8) return x; - while (x >= 0x10) { - x = (x+1) >> 1; + while (x >= (8 << 4)) { /* coarse steps */ + x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ + e += 4; + } + while (x >= (8 << 1)) { /* fine steps */ + x = (x + 1) >> 1; /* x = ceil(x / 2) */ e++; } return ((e+1) << 3) | (cast_int(x) - 8); @@ -46,14 +55,15 @@ int luaO_int2fb (unsigned int x) { /* converts back */ int luaO_fb2int (int x) { - int e = (x >> 3) & 0x1f; - if (e == 0) return x; - else return ((x & 7) + 8) << (e - 1); + return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1); } +/* +** Computes ceil(log2(x)) +*/ int luaO_ceillog2 (unsigned int x) { - static const lu_byte log_2[256] = { + static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, @@ -70,29 +80,90 @@ int luaO_ceillog2 (unsigned int x) { } -lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) { +static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, + lua_Integer v2) { switch (op) { - case LUA_OPADD: return luai_numadd(NULL, v1, v2); - case LUA_OPSUB: return luai_numsub(NULL, v1, v2); - case LUA_OPMUL: return luai_nummul(NULL, v1, v2); - case LUA_OPDIV: return luai_numdiv(NULL, v1, v2); - case LUA_OPMOD: return luai_nummod(NULL, v1, v2); - case LUA_OPPOW: return luai_numpow(NULL, v1, v2); - case LUA_OPUNM: return luai_numunm(NULL, v1); + case LUA_OPADD: return intop(+, v1, v2); + case LUA_OPSUB:return intop(-, v1, v2); + case LUA_OPMUL:return intop(*, v1, v2); + case LUA_OPMOD: return luaV_mod(L, v1, v2); + case LUA_OPIDIV: return luaV_div(L, v1, v2); + case LUA_OPBAND: return intop(&, v1, v2); + case LUA_OPBOR: return intop(|, v1, v2); + case LUA_OPBXOR: return intop(^, v1, v2); + case LUA_OPSHL: return luaV_shiftl(v1, v2); + case LUA_OPSHR: return luaV_shiftl(v1, -v2); + case LUA_OPUNM: return intop(-, 0, v1); + case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); default: lua_assert(0); return 0; } } -int luaO_hexavalue (int c) { - if (lisdigit(c)) return c - '0'; - else return ltolower(c) - 'a' + 10; +static lua_Number numarith (lua_State *L, int op, lua_Number v1, + lua_Number v2) { + switch (op) { + case LUA_OPADD: return luai_numadd(L, v1, v2); + case LUA_OPSUB: return luai_numsub(L, v1, v2); + case LUA_OPMUL: return luai_nummul(L, v1, v2); + case LUA_OPDIV: return luai_numdiv(L, v1, v2); + case LUA_OPPOW: return luai_numpow(L, v1, v2); + case LUA_OPIDIV: return luai_numidiv(L, v1, v2); + case LUA_OPUNM: return luai_numunm(L, v1); + case LUA_OPMOD: { + lua_Number m; + luai_nummod(L, v1, v2, m); + return m; + } + default: lua_assert(0); return 0; + } } -#if !defined(lua_strx2number) +void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, + TValue *res) { + switch (op) { + case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: + case LUA_OPSHL: case LUA_OPSHR: + case LUA_OPBNOT: { /* operate only on integers */ + lua_Integer i1; lua_Integer i2; + if (tointeger(p1, &i1) && tointeger(p2, &i2)) { + setivalue(res, intarith(L, op, i1, i2)); + return; + } + else break; /* go to the end */ + } + case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ + lua_Number n1; lua_Number n2; + if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return; + } + else break; /* go to the end */ + } + default: { /* other operations */ + lua_Number n1; lua_Number n2; + if (ttisinteger(p1) && ttisinteger(p2)) { + setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); + return; + } + else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { + setfltvalue(res, numarith(L, op, n1, n2)); + return; + } + else break; /* go to the end */ + } + } + /* could not perform raw operation; try metamethod */ + lua_assert(L != NULL); /* should not fail when folding (compile time) */ + luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); +} -#include + +int luaO_hexavalue (int c) { + if (lisdigit(c)) return c - '0'; + else return (ltolower(c) - 'a') + 10; +} static int isneg (const char **s) { @@ -102,122 +173,285 @@ static int isneg (const char **s) { } -static lua_Number readhexa (const char **s, lua_Number r, int *count) { - for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */ - r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s))); - (*count)++; - } - return r; -} +/* +** {================================================================== +** Lua's implementation for 'lua_strx2number' +** =================================================================== +*/ + +#if !defined(lua_strx2number) + +/* maximum number of significant digits to read (to avoid overflows + even with single floats) */ +#define MAXSIGDIG 30 /* ** convert an hexadecimal numeric string to a number, following ** C99 specification for 'strtod' */ static lua_Number lua_strx2number (const char *s, char **endptr) { - lua_Number r = 0.0; - int e = 0, i = 0; - int neg = 0; /* 1 if number is negative */ + int dot = lua_getlocaledecpoint(); + lua_Number r = 0.0; /* result (accumulator) */ + int sigdig = 0; /* number of significant digits */ + int nosigdig = 0; /* number of non-significant digits */ + int e = 0; /* exponent correction */ + int neg; /* 1 if number is negative */ + int hasdot = 0; /* true after seen a dot */ *endptr = cast(char *, s); /* nothing is valid yet */ while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ neg = isneg(&s); /* check signal */ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ return 0.0; /* invalid format (no '0x') */ - s += 2; /* skip '0x' */ - r = readhexa(&s, r, &i); /* read integer part */ - if (*s == '.') { - s++; /* skip dot */ - r = readhexa(&s, r, &e); /* read fractional part */ + for (s += 2; ; s++) { /* skip '0x' and read numeral */ + if (*s == dot) { + if (hasdot) break; /* second dot? stop loop */ + else hasdot = 1; + } + else if (lisxdigit(cast_uchar(*s))) { + if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ + nosigdig++; + else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ + r = (r * cast_num(16.0)) + luaO_hexavalue(*s); + else e++; /* too many digits; ignore, but still count for exponent */ + if (hasdot) e--; /* decimal digit? correct exponent */ + } + else break; /* neither a dot nor a digit */ } - if (i == 0 && e == 0) - return 0.0; /* invalid format (no digit) */ - e *= -4; /* each fractional digit divides value by 2^-4 */ + if (nosigdig + sigdig == 0) /* no digits? */ + return 0.0; /* invalid format */ *endptr = cast(char *, s); /* valid up to here */ + e *= 4; /* each digit multiplies/divides value by 2^4 */ if (*s == 'p' || *s == 'P') { /* exponent part? */ - int exp1 = 0; - int neg1; + int exp1 = 0; /* exponent value */ + int neg1; /* exponent signal */ s++; /* skip 'p' */ neg1 = isneg(&s); /* signal */ if (!lisdigit(cast_uchar(*s))) - goto ret; /* must have at least one digit */ + return 0.0; /* invalid; must have at least one digit */ while (lisdigit(cast_uchar(*s))) /* read exponent */ exp1 = exp1 * 10 + *(s++) - '0'; if (neg1) exp1 = -exp1; e += exp1; + *endptr = cast(char *, s); /* valid up to here */ } - *endptr = cast(char *, s); /* valid up to here */ - ret: if (neg) r = -r; return l_mathop(ldexp)(r, e); } #endif +/* }====================================================== */ + +/* maximum length of a numeral */ +#if !defined (L_MAXLENNUM) +#define L_MAXLENNUM 200 +#endif -int luaO_str2d (const char *s, size_t len, lua_Number *result) { +static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { char *endptr; - if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ - return 0; - else if (strpbrk(s, "xX")) /* hexa? */ - *result = lua_strx2number(s, &endptr); + *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */ + : lua_str2number(s, &endptr); + if (endptr == s) return NULL; /* nothing recognized? */ + while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ + return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */ +} + + +/* +** Convert string 's' to a Lua number (put in 'result'). Return NULL +** on fail or the address of the ending '\0' on success. +** 'pmode' points to (and 'mode' contains) special things in the string: +** - 'x'/'X' means an hexadecimal numeral +** - 'n'/'N' means 'inf' or 'nan' (which should be rejected) +** - '.' just optimizes the search for the common case (nothing special) +** This function accepts both the current locale or a dot as the radix +** mark. If the convertion fails, it may mean number has a dot but +** locale accepts something else. In that case, the code copies 's' +** to a buffer (because 's' is read-only), changes the dot to the +** current locale radix mark, and tries to convert again. +*/ +static const char *l_str2d (const char *s, lua_Number *result) { + const char *endptr; + const char *pmode = strpbrk(s, ".xXnN"); + int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0; + if (mode == 'n') /* reject 'inf' and 'nan' */ + return NULL; + endptr = l_str2dloc(s, result, mode); /* try to convert */ + if (endptr == NULL) { /* failed? may be a different locale */ + char buff[L_MAXLENNUM + 1]; + char *pdot = strchr(s, '.'); + if (strlen(s) > L_MAXLENNUM || pdot == NULL) + return NULL; /* string too long or no dot; fail */ + strcpy(buff, s); /* copy string to buffer */ + buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ + endptr = l_str2dloc(buff, result, mode); /* try again */ + if (endptr != NULL) + endptr = s + (endptr - buff); /* make relative to 's' */ + } + return endptr; +} + + +#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10) +#define MAXLASTD cast_int(LUA_MAXINTEGER % 10) + +static const char *l_str2int (const char *s, lua_Integer *result) { + lua_Unsigned a = 0; + int empty = 1; + int neg; + while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ + neg = isneg(&s); + if (s[0] == '0' && + (s[1] == 'x' || s[1] == 'X')) { /* hex? */ + s += 2; /* skip '0x' */ + for (; lisxdigit(cast_uchar(*s)); s++) { + a = a * 16 + luaO_hexavalue(*s); + empty = 0; + } + } + else { /* decimal */ + for (; lisdigit(cast_uchar(*s)); s++) { + int d = *s - '0'; + if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */ + return NULL; /* do not accept it (as integer) */ + a = a * 10 + d; + empty = 0; + } + } + while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ + if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ + else { + *result = l_castU2S((neg) ? 0u - a : a); + return s; + } +} + + +size_t luaO_str2num (const char *s, TValue *o) { + lua_Integer i; lua_Number n; + const char *e; + if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */ + setivalue(o, i); + } + else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */ + setfltvalue(o, n); + } else - *result = lua_str2number(s, &endptr); - if (endptr == s) return 0; /* nothing recognized */ - while (lisspace(cast_uchar(*endptr))) endptr++; - return (endptr == s + len); /* OK if no trailing characters */ + return 0; /* conversion failed */ + return (e - s) + 1; /* success; return string size */ +} + + +int luaO_utf8esc (char *buff, unsigned long x) { + int n = 1; /* number of bytes put in buffer (backwards) */ + lua_assert(x <= 0x10FFFF); + if (x < 0x80) /* ascii? */ + buff[UTF8BUFFSZ - 1] = cast(char, x); + else { /* need continuation bytes */ + unsigned int mfb = 0x3f; /* maximum that fits in first byte */ + do { /* add continuation bytes */ + buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f)); + x >>= 6; /* remove added bits */ + mfb >>= 1; /* now there is one less bit available in first byte */ + } while (x > mfb); /* still needs continuation byte? */ + buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x); /* add first byte */ + } + return n; } +/* maximum length of the conversion of a number to a string */ +#define MAXNUMBER2STR 50 + + +/* +** Convert a number object to a string +*/ +void luaO_tostring (lua_State *L, StkId obj) { + char buff[MAXNUMBER2STR]; + size_t len; + lua_assert(ttisnumber(obj)); + if (ttisinteger(obj)) + len = lua_integer2str(buff, sizeof(buff), ivalue(obj)); + else { + len = lua_number2str(buff, sizeof(buff), fltvalue(obj)); +#if !defined(LUA_COMPAT_FLOATSTRING) + if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ + buff[len++] = lua_getlocaledecpoint(); + buff[len++] = '0'; /* adds '.0' to result */ + } +#endif + } + setsvalue2s(L, obj, luaS_newlstr(L, buff, len)); +} + 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)); + luaD_inctop(L); } -/* this function handles only `%d', `%c', %f, %p, and `%s' formats */ +/* +** this function handles only '%d', '%c', '%f', '%p', and '%s' + conventional formats, plus Lua-specific '%I' and '%U' +*/ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { int n = 0; for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; - luaD_checkstack(L, 2); /* fmt + item */ pushstr(L, fmt, e - fmt); switch (*(e+1)) { - case 's': { + case 's': { /* zero-terminated string */ const char *s = va_arg(argp, char *); if (s == NULL) s = "(null)"; pushstr(L, s, strlen(s)); break; } - case 'c': { - char buff; - buff = cast(char, va_arg(argp, int)); - pushstr(L, &buff, 1); + case 'c': { /* an 'int' as a character */ + char buff = cast(char, va_arg(argp, int)); + if (lisprint(cast_uchar(buff))) + pushstr(L, &buff, 1); + else /* non-printable character; print its code */ + luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); break; } - case 'd': { - setnvalue(L->top++, cast_num(va_arg(argp, int))); - break; + case 'd': { /* an 'int' */ + setivalue(L->top, va_arg(argp, int)); + goto top2str; + } + case 'I': { /* a 'lua_Integer' */ + setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); + goto top2str; } - case 'f': { - setnvalue(L->top++, cast_num(va_arg(argp, l_uacNumber))); + case 'f': { /* a 'lua_Number' */ + setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); + top2str: /* convert the top element to a string */ + luaD_inctop(L); + luaO_tostring(L, L->top - 1); break; } - case 'p': { - char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ - int l = sprintf(buff, "%p", va_arg(argp, void *)); + case 'p': { /* a pointer */ + char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ + int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *)); pushstr(L, buff, l); break; } + case 'U': { /* an 'int' as a UTF-8 sequence */ + char buff[UTF8BUFFSZ]; + int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); + pushstr(L, buff + UTF8BUFFSZ - l, l); + break; + } case '%': { pushstr(L, "%", 1); break; } default: { - luaG_runerror(L, - "invalid option " LUA_QL("%%%c") " to " LUA_QL("lua_pushfstring"), - *(e + 1)); + luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", + *(e + 1)); } } n += 2; diff --git a/depends/lua/src/lopcodes.c b/depends/lua/src/lopcodes.c index 4190dc762..a1cbef857 100644 --- a/depends/lua/src/lopcodes.c +++ b/depends/lua/src/lopcodes.c @@ -1,13 +1,16 @@ /* -** $Id: lopcodes.c,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lopcodes.c,v 1.55 2015/01/05 13:48:33 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ - #define lopcodes_c #define LUA_CORE +#include "lprefix.h" + + +#include #include "lopcodes.h" @@ -31,10 +34,17 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "ADD", "SUB", "MUL", - "DIV", "MOD", "POW", + "DIV", + "IDIV", + "BAND", + "BOR", + "BXOR", + "SHL", + "SHR", "UNM", + "BNOT", "NOT", "LEN", "CONCAT", @@ -79,10 +89,17 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ - ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */ + ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ + ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ diff --git a/depends/lua/src/loslib.c b/depends/lua/src/loslib.c index 052ba1744..481065550 100644 --- a/depends/lua/src/loslib.c +++ b/depends/lua/src/loslib.c @@ -1,9 +1,14 @@ /* -** $Id: loslib.c,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: loslib.c,v 1.64 2016/04/18 13:06:55 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ +#define loslib_c +#define LUA_LIB + +#include "lprefix.h" + #include #include @@ -11,9 +16,6 @@ #include #include -#define loslib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -21,60 +23,119 @@ /* -** list of valid conversion specifiers for the 'strftime' function +** {================================================================== +** List of valid conversion specifiers for the 'strftime' function; +** options are grouped by length; group of length 2 start with '||'. +** =================================================================== */ -#if !defined(LUA_STRFTIMEOPTIONS) - -#if !defined(LUA_USE_POSIX) -#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } -#else -#define LUA_STRFTIMEOPTIONS \ - { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \ - "", "E", "cCxXyY", \ - "O", "deHImMSuUVwWy" } -#endif +#if !defined(LUA_STRFTIMEOPTIONS) /* { */ +/* options for ANSI C 89 */ +#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%" + +/* options for ISO C 99 and POSIX */ +#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \ + "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" + +/* options for Windows */ +#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \ + "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" + +#if defined(LUA_USE_WINDOWS) +#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN +#elif defined(LUA_USE_C89) +#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89 +#else /* C99 specification */ +#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99 #endif +#endif /* } */ +/* }================================================================== */ /* -** By default, Lua uses tmpnam except when POSIX is available, where it -** uses mkstemp. +** {================================================================== +** Configuration for time-related stuff +** =================================================================== */ -#if defined(LUA_USE_MKSTEMP) -#include -#define LUA_TMPNAMBUFSIZE 32 -#define lua_tmpnam(b,e) { \ - strcpy(b, "/tmp/lua_XXXXXX"); \ - e = mkstemp(b); \ - if (e != -1) close(e); \ - e = (e == -1); } -#elif !defined(lua_tmpnam) +#if !defined(l_time_t) /* { */ +/* +** type to represent time_t in Lua +*/ +#define l_timet lua_Integer +#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) -#define LUA_TMPNAMBUFSIZE L_tmpnam -#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } +static time_t l_checktime (lua_State *L, int arg) { + lua_Integer t = luaL_checkinteger(L, arg); + luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); + return (time_t)t; +} -#endif +#endif /* } */ +#if !defined(l_gmtime) /* { */ /* ** By default, Lua uses gmtime/localtime, except when POSIX is available, ** where it uses gmtime_r/localtime_r */ -#if defined(LUA_USE_GMTIME_R) + +#if defined(LUA_USE_POSIX) /* { */ #define l_gmtime(t,r) gmtime_r(t,r) #define l_localtime(t,r) localtime_r(t,r) -#elif !defined(l_gmtime) +#else /* }{ */ + +/* ISO C definitions */ +#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t)) +#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t)) + +#endif /* } */ + +#endif /* } */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Configuration for 'tmpnam': +** By default, Lua uses tmpnam except when POSIX is available, where +** it uses mkstemp. +** =================================================================== +*/ +#if !defined(lua_tmpnam) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include -#define l_gmtime(t,r) ((void)r, gmtime(t)) -#define l_localtime(t,r) ((void)r, localtime(t)) +#define LUA_TMPNAMBUFSIZE 32 +#if !defined(LUA_TMPNAMTEMPLATE) +#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX" #endif +#define lua_tmpnam(b,e) { \ + strcpy(b, LUA_TMPNAMTEMPLATE); \ + e = mkstemp(b); \ + if (e != -1) close(e); \ + e = (e == -1); } + +#else /* }{ */ + +/* ISO C definitions */ +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } + +#endif /* } */ + +#endif /* } */ +/* }================================================================== */ + + static int os_execute (lua_State *L) { @@ -145,45 +206,67 @@ static void setboolfield (lua_State *L, const char *key, int value) { lua_setfield(L, -2, key); } + +/* +** Set all fields from structure 'tm' in the table on top of the stack +*/ +static void setallfields (lua_State *L, struct tm *stm) { + setfield(L, "sec", stm->tm_sec); + setfield(L, "min", stm->tm_min); + setfield(L, "hour", stm->tm_hour); + setfield(L, "day", stm->tm_mday); + setfield(L, "month", stm->tm_mon + 1); + setfield(L, "year", stm->tm_year + 1900); + setfield(L, "wday", stm->tm_wday + 1); + setfield(L, "yday", stm->tm_yday + 1); + setboolfield(L, "isdst", stm->tm_isdst); +} + + static int getboolfield (lua_State *L, const char *key) { int res; - lua_getfield(L, -1, key); - res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); + res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); lua_pop(L, 1); return res; } -static int getfield (lua_State *L, const char *key, int d) { - int res, isnum; - lua_getfield(L, -1, key); - res = (int)lua_tointegerx(L, -1, &isnum); - if (!isnum) { - if (d < 0) - return luaL_error(L, "field " LUA_QS " missing in date table", key); +/* maximum value for date fields (to avoid arithmetic overflows with 'int') */ +#if !defined(L_MAXDATEFIELD) +#define L_MAXDATEFIELD (INT_MAX / 2) +#endif + +static int getfield (lua_State *L, const char *key, int d, int delta) { + int isnum; + int t = lua_getfield(L, -1, key); /* get field and its type */ + lua_Integer res = lua_tointegerx(L, -1, &isnum); + if (!isnum) { /* field is not an integer? */ + if (t != LUA_TNIL) /* some other value? */ + return luaL_error(L, "field '%s' is not an integer", key); + else if (d < 0) /* absent field; no default? */ + return luaL_error(L, "field '%s' missing in date table", key); res = d; } + else { + if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) + return luaL_error(L, "field '%s' is out-of-bound", key); + res -= delta; + } lua_pop(L, 1); - return res; + return (int)res; } static const char *checkoption (lua_State *L, const char *conv, char *buff) { - static const char *const options[] = LUA_STRFTIMEOPTIONS; - unsigned int i; - for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) { - if (*conv != '\0' && strchr(options[i], *conv) != NULL) { - buff[1] = *conv; - if (*options[i + 1] == '\0') { /* one-char conversion specifier? */ - buff[2] = '\0'; /* end buffer */ - return conv + 1; - } - else if (*(conv + 1) != '\0' && - strchr(options[i + 1], *(conv + 1)) != NULL) { - buff[2] = *(conv + 1); /* valid two-char conversion specifier */ - buff[3] = '\0'; /* end buffer */ - return conv + 2; - } + const char *option; + int oplen = 1; + for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) { + if (*option == '|') /* next block? */ + oplen++; /* next length */ + else if (memcmp(conv, option, oplen) == 0) { /* match? */ + memcpy(buff, conv, oplen); /* copy valid option to buffer */ + buff[oplen] = '\0'; + return conv + oplen; /* return next item */ } } luaL_argerror(L, 1, @@ -192,44 +275,40 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) { } +/* maximum size for an individual 'strftime' item */ +#define SIZETIMEFMT 250 + + static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); - time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); + time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); struct tm tmr, *stm; if (*s == '!') { /* UTC? */ stm = l_gmtime(&t, &tmr); - s++; /* skip `!' */ + s++; /* skip '!' */ } else stm = l_localtime(&t, &tmr); if (stm == NULL) /* invalid date? */ - lua_pushnil(L); - else if (strcmp(s, "*t") == 0) { + luaL_error(L, "time result cannot be represented in this installation"); + if (strcmp(s, "*t") == 0) { lua_createtable(L, 0, 9); /* 9 = number of fields */ - setfield(L, "sec", stm->tm_sec); - setfield(L, "min", stm->tm_min); - setfield(L, "hour", stm->tm_hour); - setfield(L, "day", stm->tm_mday); - setfield(L, "month", stm->tm_mon+1); - setfield(L, "year", stm->tm_year+1900); - setfield(L, "wday", stm->tm_wday+1); - setfield(L, "yday", stm->tm_yday+1); - setboolfield(L, "isdst", stm->tm_isdst); + setallfields(L, stm); } else { - char cc[4]; + char cc[4]; /* buffer for individual conversion specifiers */ luaL_Buffer b; cc[0] = '%'; luaL_buffinit(L, &b); while (*s) { - if (*s != '%') /* no conversion specifier? */ + if (*s != '%') /* not a conversion specifier? */ luaL_addchar(&b, *s++); else { size_t reslen; - char buff[200]; /* should be big enough for any conversion result */ - s = checkoption(L, s + 1, cc); - reslen = strftime(buff, sizeof(buff), cc, stm); - luaL_addlstring(&b, buff, reslen); + char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); + s = checkoption(L, s + 1, cc + 1); /* copy specifier to 'cc' */ + reslen = strftime(buff, SIZETIMEFMT, cc, stm); + luaL_addsize(&b, reslen); } } luaL_pushresult(&b); @@ -246,26 +325,27 @@ static int os_time (lua_State *L) { struct tm ts; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); /* make sure table is at the top */ - ts.tm_sec = getfield(L, "sec", 0); - ts.tm_min = getfield(L, "min", 0); - ts.tm_hour = getfield(L, "hour", 12); - ts.tm_mday = getfield(L, "day", -1); - ts.tm_mon = getfield(L, "month", -1) - 1; - ts.tm_year = getfield(L, "year", -1) - 1900; + ts.tm_sec = getfield(L, "sec", 0, 0); + ts.tm_min = getfield(L, "min", 0, 0); + ts.tm_hour = getfield(L, "hour", 12, 0); + ts.tm_mday = getfield(L, "day", -1, 0); + ts.tm_mon = getfield(L, "month", -1, 1); + ts.tm_year = getfield(L, "year", -1, 1900); ts.tm_isdst = getboolfield(L, "isdst"); t = mktime(&ts); + setallfields(L, &ts); /* update fields with normalized values */ } - if (t == (time_t)(-1)) - lua_pushnil(L); - else - lua_pushnumber(L, (lua_Number)t); + if (t != (time_t)(l_timet)t || t == (time_t)(-1)) + luaL_error(L, "time result cannot be represented in this installation"); + l_pushtime(L, t); return 1; } static int os_difftime (lua_State *L) { - lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), - (time_t)(luaL_optnumber(L, 2, 0)))); + time_t t1 = l_checktime(L, 1); + time_t t2 = l_checktime(L, 2); + lua_pushnumber(L, (lua_Number)difftime(t1, t2)); return 1; } @@ -289,7 +369,7 @@ static int os_exit (lua_State *L) { if (lua_isboolean(L, 1)) status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); else - status = luaL_optint(L, 1, EXIT_SUCCESS); + status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); if (lua_toboolean(L, 2)) lua_close(L); if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ diff --git a/depends/lua/src/lparser.c b/depends/lua/src/lparser.c index 9e1a9ca2c..22530a57b 100644 --- a/depends/lua/src/lparser.c +++ b/depends/lua/src/lparser.c @@ -1,15 +1,17 @@ /* -** $Id: lparser.c,v 2.130.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lparser.c,v 2.153 2016/05/13 19:10:16 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ - -#include - #define lparser_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "lcode.h" @@ -35,17 +37,21 @@ #define hasmultret(k) ((k) == VCALL || (k) == VVARARG) +/* because all strings are unified by the scanner, the parser + can use pointer equality for string equality */ +#define eqstr(a,b) ((a) == (b)) + /* ** nodes for block list (list of active blocks) */ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ - short firstlabel; /* index of first label in this block */ - short firstgoto; /* index of first pending goto in this block */ + int firstlabel; /* index of first label in this block */ + int firstgoto; /* index of first pending goto in this block */ lu_byte nactvar; /* # active locals outside the block */ lu_byte upval; /* true if some variable in the block is an upvalue */ - lu_byte isloop; /* true if `block' is a loop */ + lu_byte isloop; /* true if 'block' is a loop */ } BlockCnt; @@ -57,19 +63,9 @@ static void statement (LexState *ls); static void expr (LexState *ls, expdesc *v); -static void anchor_token (LexState *ls) { - /* last token from outer function must be EOS */ - lua_assert(ls->fs != NULL || ls->t.token == TK_EOS); - if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { - TString *ts = ls->t.seminfo.ts; - luaX_newstring(ls, getstr(ts), ts->tsv.len); - } -} - - /* semantic error */ static l_noret semerror (LexState *ls, const char *msg) { - ls->t.token = 0; /* remove 'near to' from final message */ + ls->t.token = 0; /* remove "near " from final message */ luaX_syntaxerror(ls, msg); } @@ -168,7 +164,8 @@ static int registerlocalvar (LexState *ls, TString *varname) { int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, LocVar, SHRT_MAX, "local variables"); - while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; + while (oldsize < f->sizelocvars) + f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; luaC_objbarrier(ls->L, f, varname); return fs->nlocvars++; @@ -222,7 +219,7 @@ static int searchupvalue (FuncState *fs, TString *name) { int i; Upvaldesc *up = fs->f->upvalues; for (i = 0; i < fs->nups; i++) { - if (luaS_eqstr(up[i].name, name)) return i; + if (eqstr(up[i].name, name)) return i; } return -1; /* not found */ } @@ -234,7 +231,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, Upvaldesc, MAXUPVAL, "upvalues"); - while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; + while (oldsize < f->sizeupvalues) + f->upvalues[oldsize++].name = NULL; f->upvalues[fs->nups].instack = (v->k == VLOCAL); f->upvalues[fs->nups].idx = cast_byte(v->u.info); f->upvalues[fs->nups].name = name; @@ -246,7 +244,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { static int searchvar (FuncState *fs, TString *n) { int i; for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { - if (luaS_eqstr(n, getlocvar(fs, i)->varname)) + if (eqstr(n, getlocvar(fs, i)->varname)) return i; } return -1; /* not found */ @@ -259,7 +257,8 @@ static int searchvar (FuncState *fs, TString *n) { */ static void markupval (FuncState *fs, int level) { BlockCnt *bl = fs->bl; - while (bl->nactvar > level) bl = bl->previous; + while (bl->nactvar > level) + bl = bl->previous; bl->upval = 1; } @@ -268,27 +267,26 @@ static void markupval (FuncState *fs, int level) { Find variable with given name 'n'. If it is an upvalue, add this upvalue into all intermediate functions. */ -static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { +static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { if (fs == NULL) /* no more levels? */ - return VVOID; /* default is global */ + init_exp(var, VVOID, 0); /* default is global */ else { int v = searchvar(fs, n); /* look up locals at current level */ if (v >= 0) { /* found? */ init_exp(var, VLOCAL, v); /* variable is local */ if (!base) markupval(fs, v); /* local will be used as an upval */ - return VLOCAL; } else { /* not found as local at current level; try upvalues */ int idx = searchupvalue(fs, n); /* try existing upvalues */ if (idx < 0) { /* not found? */ - if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ - return VVOID; /* not found; is a global */ + singlevaraux(fs->prev, n, var, 0); /* try upper levels */ + if (var->k == VVOID) /* not found? */ + return; /* it is a global */ /* else was LOCAL or UPVAL */ idx = newupvalue(fs, n, var); /* will be a new upvalue */ } - init_exp(var, VUPVAL, idx); - return VUPVAL; + init_exp(var, VUPVAL, idx); /* new or old upvalue */ } } } @@ -297,10 +295,11 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; - if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ + singlevaraux(fs, varname, var, 1); + if (var->k == VVOID) { /* global name? */ expdesc key; singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ - lua_assert(var->k == VLOCAL || var->k == VUPVAL); + lua_assert(var->k != VVOID); /* this one must exist */ codestring(ls, &key, varname); /* key is variable name */ luaK_indexed(fs, var, &key); /* env[varname] */ } @@ -342,11 +341,11 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) { FuncState *fs = ls->fs; Labellist *gl = &ls->dyd->gt; Labeldesc *gt = &gl->arr[g]; - lua_assert(luaS_eqstr(gt->name, label->name)); + lua_assert(eqstr(gt->name, label->name)); if (gt->nactvar < label->nactvar) { TString *vname = getlocvar(fs, gt->nactvar)->varname; const char *msg = luaO_pushfstring(ls->L, - " at line %d jumps into the scope of local " LUA_QS, + " at line %d jumps into the scope of local '%s'", getstr(gt->name), gt->line, getstr(vname)); semerror(ls, msg); } @@ -369,7 +368,7 @@ static int findlabel (LexState *ls, int g) { /* check labels in current block for a match */ for (i = bl->firstlabel; i < dyd->label.n; i++) { Labeldesc *lb = &dyd->label.arr[i]; - if (luaS_eqstr(lb->name, gt->name)) { /* correct label? */ + if (eqstr(lb->name, gt->name)) { /* correct label? */ if (gt->nactvar > lb->nactvar && (bl->upval || dyd->label.n > bl->firstlabel)) luaK_patchclose(ls->fs, gt->pc, lb->nactvar); @@ -390,7 +389,7 @@ static int newlabelentry (LexState *ls, Labellist *l, TString *name, l->arr[n].line = line; l->arr[n].nactvar = ls->fs->nactvar; l->arr[n].pc = pc; - l->n++; + l->n = n + 1; return n; } @@ -403,7 +402,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) { Labellist *gl = &ls->dyd->gt; int i = ls->fs->bl->firstgoto; while (i < gl->n) { - if (luaS_eqstr(gl->arr[i].name, lb->name)) + if (eqstr(gl->arr[i].name, lb->name)) closegoto(ls, i, lb); else i++; @@ -412,7 +411,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) { /* -** "export" pending gotos to outer level, to check them against +** export pending gotos to outer level, to check them against ** outer labels; if the block being exited has upvalues, and ** the goto exits the scope of any variable (which can be the ** upvalue), close those variables being exited. @@ -448,7 +447,7 @@ static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { /* -** create a label named "break" to resolve break statements +** create a label named 'break' to resolve break statements */ static void breaklabel (LexState *ls) { TString *n = luaS_new(ls->L, "break"); @@ -463,7 +462,7 @@ static void breaklabel (LexState *ls) { static l_noret undefgoto (LexState *ls, Labeldesc *gt) { const char *msg = isreserved(gt->name) ? "<%s> at line %d not inside a loop" - : "no visible label " LUA_QS " for at line %d"; + : "no visible label '%s' for at line %d"; msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); semerror(ls, msg); } @@ -503,7 +502,8 @@ static Proto *addprototype (LexState *ls) { if (fs->np >= f->sizep) { int oldsize = f->sizep; luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); - while (oldsize < f->sizep) f->p[oldsize++] = NULL; + while (oldsize < f->sizep) + f->p[oldsize++] = NULL; } f->p[fs->np++] = clp = luaF_newproto(L); luaC_objbarrier(L, f, clp); @@ -525,7 +525,6 @@ static void codeclosure (LexState *ls, expdesc *v) { static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { - lua_State *L = ls->L; Proto *f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; @@ -544,10 +543,6 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { f = fs->f; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ - fs->h = luaH_new(L); - /* anchor table of constants (to avoid being collected) */ - sethvalue2s(L, L->top, fs->h); - incr_top(L); enterblock(fs, bl, 0); } @@ -572,9 +567,6 @@ static void close_func (LexState *ls) { f->sizeupvalues = fs->nups; lua_assert(fs->bl == NULL); ls->fs = fs->prev; - /* last token read was anchored in defunct function; must re-anchor it */ - anchor_token(ls); - L->top--; /* pop table of constants */ luaC_checkGC(L); } @@ -588,7 +580,7 @@ static void close_func (LexState *ls) { /* ** check whether current token is in the follow set of a block. ** 'until' closes syntactical blocks, but do not close scope, -** so it handled in separate. +** so it is handled in separate. */ static int block_follow (LexState *ls, int withuntil) { switch (ls->t.token) { @@ -602,7 +594,7 @@ static int block_follow (LexState *ls, int withuntil) { static void statlist (LexState *ls) { - /* statlist -> { stat [`;'] } */ + /* statlist -> { stat [';'] } */ while (!block_follow(ls, 1)) { if (ls->t.token == TK_RETURN) { statement(ls); @@ -643,14 +635,14 @@ static void yindex (LexState *ls, expdesc *v) { struct ConsControl { expdesc v; /* last list item read */ expdesc *t; /* table descriptor */ - int nh; /* total number of `record' elements */ + int nh; /* total number of 'record' elements */ int na; /* total number of array elements */ int tostore; /* number of array elements pending to be stored */ }; static void recfield (LexState *ls, struct ConsControl *cc) { - /* recfield -> (NAME | `['exp1`]') = exp1 */ + /* recfield -> (NAME | '['exp1']') = exp1 */ FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc key, val; @@ -757,12 +749,12 @@ static void constructor (LexState *ls, expdesc *t) { static void parlist (LexState *ls) { - /* parlist -> [ param { `,' param } ] */ + /* parlist -> [ param { ',' param } ] */ FuncState *fs = ls->fs; Proto *f = fs->f; int nparams = 0; f->is_vararg = 0; - if (ls->t.token != ')') { /* is `parlist' not empty? */ + if (ls->t.token != ')') { /* is 'parlist' not empty? */ do { switch (ls->t.token) { case TK_NAME: { /* param -> NAME */ @@ -770,12 +762,12 @@ static void parlist (LexState *ls) { nparams++; break; } - case TK_DOTS: { /* param -> `...' */ + case TK_DOTS: { /* param -> '...' */ luaX_next(ls); - f->is_vararg = 1; + f->is_vararg = 2; /* declared vararg */ break; } - default: luaX_syntaxerror(ls, " or " LUA_QL("...") " expected"); + default: luaX_syntaxerror(ls, " or '...' expected"); } } while (!f->is_vararg && testnext(ls, ',')); } @@ -786,7 +778,7 @@ static void parlist (LexState *ls) { static void body (LexState *ls, expdesc *e, int ismethod, int line) { - /* body -> `(' parlist `)' block END */ + /* body -> '(' parlist ')' block END */ FuncState new_fs; BlockCnt bl; new_fs.f = addprototype(ls); @@ -808,7 +800,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) { static int explist (LexState *ls, expdesc *v) { - /* explist -> expr { `,' expr } */ + /* explist -> expr { ',' expr } */ int n = 1; /* at least one expression */ expr(ls, v); while (testnext(ls, ',')) { @@ -825,7 +817,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) { expdesc args; int base, nparams; switch (ls->t.token) { - case '(': { /* funcargs -> `(' [ explist ] `)' */ + case '(': { /* funcargs -> '(' [ explist ] ')' */ luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; @@ -842,7 +834,7 @@ static void funcargs (LexState *ls, expdesc *f, int line) { } case TK_STRING: { /* funcargs -> STRING */ codestring(ls, &args, ls->t.seminfo.ts); - luaX_next(ls); /* must use `seminfo' before `next' */ + luaX_next(ls); /* must use 'seminfo' before 'next' */ break; } default: { @@ -908,14 +900,14 @@ static void suffixedexp (LexState *ls, expdesc *v) { fieldsel(ls, v); break; } - case '[': { /* `[' exp1 `]' */ + case '[': { /* '[' exp1 ']' */ expdesc key; luaK_exp2anyregup(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; } - case ':': { /* `:' NAME funcargs */ + case ':': { /* ':' NAME funcargs */ expdesc key; luaX_next(ls); checkname(ls, &key); @@ -935,14 +927,19 @@ static void suffixedexp (LexState *ls, expdesc *v) { static void simpleexp (LexState *ls, expdesc *v) { - /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | + /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | constructor | FUNCTION body | suffixedexp */ switch (ls->t.token) { - case TK_NUMBER: { - init_exp(v, VKNUM, 0); + case TK_FLT: { + init_exp(v, VKFLT, 0); v->u.nval = ls->t.seminfo.r; break; } + case TK_INT: { + init_exp(v, VKINT, 0); + v->u.ival = ls->t.seminfo.i; + break; + } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); break; @@ -962,7 +959,8 @@ static void simpleexp (LexState *ls, expdesc *v) { case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, - "cannot use " LUA_QL("...") " outside a vararg function"); + "cannot use '...' outside a vararg function"); + fs->f->is_vararg = 1; /* function actually uses vararg */ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } @@ -988,6 +986,7 @@ static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; + case '~': return OPR_BNOT; case '#': return OPR_LEN; default: return OPR_NOUNOPR; } @@ -999,9 +998,15 @@ static BinOpr getbinopr (int op) { case '+': return OPR_ADD; case '-': return OPR_SUB; case '*': return OPR_MUL; - case '/': return OPR_DIV; case '%': return OPR_MOD; case '^': return OPR_POW; + case '/': return OPR_DIV; + case TK_IDIV: return OPR_IDIV; + case '&': return OPR_BAND; + case '|': return OPR_BOR; + case '~': return OPR_BXOR; + case TK_SHL: return OPR_SHL; + case TK_SHR: return OPR_SHR; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; case TK_EQ: return OPR_EQ; @@ -1020,19 +1025,24 @@ static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ - {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `*' `/' `%' */ - {10, 9}, {5, 4}, /* ^, .. (right associative) */ - {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ - {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ - {2, 2}, {1, 1} /* and, or */ + {10, 10}, {10, 10}, /* '+' '-' */ + {11, 11}, {11, 11}, /* '*' '%' */ + {14, 13}, /* '^' (right associative) */ + {11, 11}, {11, 11}, /* '/' '//' */ + {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ + {7, 7}, {7, 7}, /* '<<' '>>' */ + {9, 8}, /* '..' (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ + {2, 2}, {1, 1} /* and, or */ }; -#define UNARY_PRIORITY 8 /* priority for unary operators */ +#define UNARY_PRIORITY 12 /* priority for unary operators */ /* ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } -** where `binop' is any binary operator with a priority higher than `limit' +** where 'binop' is any binary operator with a priority higher than 'limit' */ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { BinOpr op; @@ -1046,7 +1056,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { luaK_prefix(ls->fs, uop, v, line); } else simpleexp(ls, v); - /* expand while operators have priorities higher than `limit' */ + /* expand while operators have priorities higher than 'limit' */ op = getbinopr(ls->t.token); while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; @@ -1146,7 +1156,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { "C levels"); assignment(ls, &nv, nvars+1); } - else { /* assignment -> `=' explist */ + else { /* assignment -> '=' explist */ int nexps; checknext(ls, '='); nexps = explist(ls, &e); @@ -1170,7 +1180,7 @@ static int cond (LexState *ls) { /* cond -> exp */ expdesc v; expr(ls, &v); /* read condition */ - if (v.k == VNIL) v.k = VFALSE; /* `falses' are all equal here */ + if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ luaK_goiftrue(ls->fs, &v); return v.f; } @@ -1195,9 +1205,9 @@ static void gotostat (LexState *ls, int pc) { static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { int i; for (i = fs->bl->firstlabel; i < ll->n; i++) { - if (luaS_eqstr(label, ll->arr[i].name)) { + if (eqstr(label, ll->arr[i].name)) { const char *msg = luaO_pushfstring(fs->ls->L, - "label " LUA_QS " already defined on line %d", + "label '%s' already defined on line %d", getstr(label), ll->arr[i].line); semerror(fs->ls, msg); } @@ -1220,7 +1230,7 @@ static void labelstat (LexState *ls, TString *label, int line) { checkrepeated(fs, ll, label); /* check for repeated labels */ checknext(ls, TK_DBCOLON); /* skip double colon */ /* create new entry for this label */ - l = newlabelentry(ls, ll, label, line, fs->pc); + l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs)); skipnoopstat(ls); /* skip other no-op statements */ if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ /* assume that locals are already out of scope */ @@ -1321,7 +1331,7 @@ static void fornum (LexState *ls, TString *varname, int line) { if (testnext(ls, ',')) exp1(ls); /* optional step */ else { /* default step = 1 */ - luaK_codek(fs, fs->freereg, luaK_numberK(fs, 1)); + luaK_codek(fs, fs->freereg, luaK_intK(fs, 1)); luaK_reserveregs(fs, 1); } forbody(ls, base, line, 1, 1); @@ -1359,15 +1369,15 @@ static void forstat (LexState *ls, int line) { TString *varname; BlockCnt bl; enterblock(fs, &bl, 1); /* scope for loop and control variables */ - luaX_next(ls); /* skip `for' */ + luaX_next(ls); /* skip 'for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { case '=': fornum(ls, varname, line); break; case ',': case TK_IN: forlist(ls, varname); break; - default: luaX_syntaxerror(ls, LUA_QL("=") " or " LUA_QL("in") " expected"); + default: luaX_syntaxerror(ls, "'=' or 'in' expected"); } check_match(ls, TK_END, TK_FOR, line); - leaveblock(fs); /* loop scope (`break' jumps to this point) */ + leaveblock(fs); /* loop scope ('break' jumps to this point) */ } @@ -1397,7 +1407,7 @@ static void test_then_block (LexState *ls, int *escapelist) { enterblock(fs, &bl, 0); jf = v.f; } - statlist(ls); /* `then' part */ + statlist(ls); /* 'then' part */ leaveblock(fs); if (ls->t.token == TK_ELSE || ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ @@ -1414,7 +1424,7 @@ static void ifstat (LexState *ls, int line) { while (ls->t.token == TK_ELSEIF) test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ if (testnext(ls, TK_ELSE)) - block(ls); /* `else' part */ + block(ls); /* 'else' part */ check_match(ls, TK_END, TK_IF, line); luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ } @@ -1432,7 +1442,7 @@ static void localfunc (LexState *ls) { static void localstat (LexState *ls) { - /* stat -> LOCAL NAME {`,' NAME} [`=' explist] */ + /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ int nvars = 0; int nexps; expdesc e; @@ -1452,7 +1462,7 @@ static void localstat (LexState *ls) { static int funcname (LexState *ls, expdesc *v) { - /* funcname -> NAME {fieldsel} [`:' NAME] */ + /* funcname -> NAME {fieldsel} [':' NAME] */ int ismethod = 0; singlevar(ls, v); while (ls->t.token == '.') @@ -1473,7 +1483,7 @@ static void funcstat (LexState *ls, int line) { ismethod = funcname(ls, &v); body(ls, &b, ismethod, line); luaK_storevar(ls->fs, &v, &b); - luaK_fixline(ls->fs, line); /* definition `happens' in the first line */ + luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ } @@ -1488,7 +1498,7 @@ static void exprstat (LexState *ls) { } else { /* stat -> func */ check_condition(ls, v.v.k == VCALL, "syntax error"); - SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ + SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */ } } @@ -1505,8 +1515,8 @@ static void retstat (LexState *ls) { if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ - SET_OPCODE(getcode(fs,&e), OP_TAILCALL); - lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); + SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL); + lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar); } first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ @@ -1515,8 +1525,8 @@ static void retstat (LexState *ls) { if (nret == 1) /* only one single value? */ first = luaK_exp2anyreg(fs, &e); else { - luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ - first = fs->nactvar; /* return all `active' values */ + luaK_exp2nextreg(fs, &e); /* values must go to the stack */ + first = fs->nactvar; /* return all active values */ lua_assert(nret == fs->freereg - first); } } @@ -1605,7 +1615,7 @@ static void mainfunc (LexState *ls, FuncState *fs) { BlockCnt bl; expdesc v; open_func(ls, fs, &bl); - fs->f->is_vararg = 1; /* main function is always vararg */ + fs->f->is_vararg = 2; /* main function is always declared vararg */ init_exp(&v, VLOCAL, 0); /* create and... */ newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ luaX_next(ls); /* read first token */ @@ -1615,16 +1625,19 @@ static void mainfunc (LexState *ls, FuncState *fs) { } -Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar) { +LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar) { LexState lexstate; FuncState funcstate; - Closure *cl = luaF_newLclosure(L, 1); /* create main closure */ - /* anchor closure (to avoid being collected) */ - setclLvalue(L, L->top, cl); - incr_top(L); - funcstate.f = cl->l.p = luaF_newproto(L); + LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ + setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ + luaD_inctop(L); + lexstate.h = luaH_new(L); /* create table for scanner */ + sethvalue(L, L->top, lexstate.h); /* anchor it */ + luaD_inctop(L); + funcstate.f = cl->p = luaF_newproto(L); funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ + lua_assert(iswhite(funcstate.f)); /* do not need barrier here */ lexstate.buff = buff; lexstate.dyd = dyd; dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; @@ -1633,6 +1646,7 @@ Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); /* all scopes should be correctly finished */ lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); - return cl; /* it's on the stack too */ + L->top--; /* remove scanner's table */ + return cl; /* closure is on the stack, too */ } diff --git a/depends/lua/src/lstate.c b/depends/lua/src/lstate.c index c7f2672be..9194ac341 100644 --- a/depends/lua/src/lstate.c +++ b/depends/lua/src/lstate.c @@ -1,16 +1,18 @@ /* -** $Id: lstate.c,v 2.99.1.2 2013/11/08 17:45:31 roberto Exp $ +** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ +#define lstate_c +#define LUA_CORE + +#include "lprefix.h" + #include #include -#define lstate_c -#define LUA_CORE - #include "lua.h" #include "lapi.h" @@ -30,18 +32,11 @@ #define LUAI_GCPAUSE 200 /* 200% */ #endif -#if !defined(LUAI_GCMAJOR) -#define LUAI_GCMAJOR 200 /* 200% */ -#endif - #if !defined(LUAI_GCMUL) #define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ #endif -#define MEMERRMSG "not enough memory" - - /* ** a macro to help the creation of a unique random seed when a state is ** created; the seed is used to randomize hashes. @@ -57,9 +52,7 @@ ** thread state + extra space */ typedef struct LX { -#if defined(LUAI_EXTRASPACE) - char buff[LUAI_EXTRASPACE]; -#endif + lu_byte extra_[LUA_EXTRASPACE]; lua_State l; } LX; @@ -78,13 +71,12 @@ typedef struct LG { /* -** Compute an initial seed as random as possible. In ANSI, rely on -** Address Space Layout Randomization (if present) to increase -** randomness.. +** Compute an initial seed as random as possible. Rely on Address Space +** Layout Randomization (if present) to increase randomness.. */ #define addbuff(b,p,e) \ { size_t t = cast(size_t, e); \ - memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); } + memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } static unsigned int makeseed (lua_State *L) { char buff[4 * sizeof(size_t)]; @@ -101,10 +93,14 @@ static unsigned int makeseed (lua_State *L) { /* ** set GCdebt to a new value keeping the value (totalbytes + GCdebt) -** invariant +** invariant (and avoiding underflows in 'totalbytes') */ void luaE_setdebt (global_State *g, l_mem debt) { - g->totalbytes -= (debt - g->GCdebt); + l_mem tb = gettotalbytes(g); + lua_assert(tb > 0); + if (debt < tb - MAX_LMEM) + debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ + g->totalbytes = tb - debt; g->GCdebt = debt; } @@ -115,10 +111,14 @@ CallInfo *luaE_extendCI (lua_State *L) { L->ci->next = ci; ci->previous = L->ci; ci->next = NULL; + L->nci++; return ci; } +/* +** free all CallInfo structures not in use by a thread +*/ void luaE_freeCI (lua_State *L) { CallInfo *ci = L->ci; CallInfo *next = ci->next; @@ -126,6 +126,24 @@ void luaE_freeCI (lua_State *L) { while ((ci = next) != NULL) { next = ci->next; luaM_free(L, ci); + L->nci--; + } +} + + +/* +** free half of the CallInfo structures not in use by a thread +*/ +void luaE_shrinkCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next2; /* next's next */ + /* while there are two nexts */ + while (ci->next != NULL && (next2 = ci->next->next) != NULL) { + luaM_free(L, ci->next); /* free next */ + L->nci--; + ci->next = next2; /* remove 'next' from the list */ + next2->previous = ci; + ci = next2; /* keep next's next */ } } @@ -155,6 +173,7 @@ static void freestack (lua_State *L) { return; /* stack not completely built yet */ L->ci = &L->base_ci; /* free the entire 'ci' list */ luaE_freeCI(L); + lua_assert(L->nci == 0); luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ } @@ -163,34 +182,32 @@ static void freestack (lua_State *L) { ** Create registry table and its predefined values */ static void init_registry (lua_State *L, global_State *g) { - TValue mt; + TValue temp; /* create registry */ Table *registry = luaH_new(L); sethvalue(L, &g->l_registry, registry); luaH_resize(L, registry, LUA_RIDX_LAST, 0); /* registry[LUA_RIDX_MAINTHREAD] = L */ - setthvalue(L, &mt, L); - luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &mt); + setthvalue(L, &temp, L); /* temp = L */ + luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); /* registry[LUA_RIDX_GLOBALS] = table of globals */ - sethvalue(L, &mt, luaH_new(L)); - luaH_setint(L, registry, LUA_RIDX_GLOBALS, &mt); + sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ + luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); } /* -** open parts of the state that may cause memory-allocation errors +** open parts of the state that may cause memory-allocation errors. +** ('g->version' != NULL flags that the state was completely build) */ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ init_registry(L, g); - luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + luaS_init(L); luaT_init(L); luaX_init(L); - /* pre-create memory-error message */ - g->memerrmsg = luaS_newliteral(L, MEMERRMSG); - luaS_fix(g->memerrmsg); /* it should never be collected */ g->gcrunning = 1; /* allow gc */ g->version = lua_version(NULL); luai_userstateopen(L); @@ -198,14 +215,16 @@ static void f_luaopen (lua_State *L, void *ud) { /* -** preinitialize a state with consistent values without allocating +** preinitialize a thread with consistent values without allocating ** any memory (to avoid errors) */ -static void preinit_state (lua_State *L, global_State *g) { +static void preinit_thread (lua_State *L, global_State *g) { G(L) = g; L->stack = NULL; L->ci = NULL; + L->nci = 0; L->stacksize = 0; + L->twups = L; /* thread has no upvalues */ L->errorJmp = NULL; L->nCcalls = 0; L->hook = NULL; @@ -227,7 +246,6 @@ static void close_state (lua_State *L) { if (g->version) /* closing a fully built state? */ luai_userstateclose(L); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); - luaZ_freebuffer(L, &g->buff); freestack(L); lua_assert(gettotalbytes(g) == sizeof(LG)); (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ @@ -235,17 +253,28 @@ static void close_state (lua_State *L) { LUA_API lua_State *lua_newthread (lua_State *L) { + global_State *g = G(L); lua_State *L1; lua_lock(L); luaC_checkGC(L); - L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), NULL, offsetof(LX, l))->th; + /* create new thread */ + L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; + L1->marked = luaC_white(g); + L1->tt = LUA_TTHREAD; + /* link it on list 'allgc' */ + L1->next = g->allgc; + g->allgc = obj2gco(L1); + /* anchor it on L stack */ setthvalue(L, L->top, L1); api_incr_top(L); - preinit_state(L1, G(L)); + preinit_thread(L1, g); L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; resethookcount(L1); + /* initialize L1 extra space */ + memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), + LUA_EXTRASPACE); luai_userstatethread(L, L1); stack_init(L1, L); /* init stack */ lua_unlock(L); @@ -273,36 +302,31 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g = &l->g; L->next = NULL; L->tt = LUA_TTHREAD; - g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); + g->currentwhite = bitmask(WHITE0BIT); L->marked = luaC_white(g); - g->gckind = KGC_NORMAL; - preinit_state(L, g); + preinit_thread(L, g); g->frealloc = f; g->ud = ud; g->mainthread = L; g->seed = makeseed(L); - g->uvhead.u.l.prev = &g->uvhead; - g->uvhead.u.l.next = &g->uvhead; g->gcrunning = 0; /* no GC while building state */ g->GCestimate = 0; - g->strt.size = 0; - g->strt.nuse = 0; + g->strt.size = g->strt.nuse = 0; g->strt.hash = NULL; setnilvalue(&g->l_registry); - luaZ_initbuffer(L, &g->buff); g->panic = NULL; g->version = NULL; g->gcstate = GCSpause; - g->allgc = NULL; - g->finobj = NULL; - g->tobefnz = NULL; - g->sweepgc = g->sweepfin = NULL; + g->gckind = KGC_NORMAL; + g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; + g->sweepgc = NULL; g->gray = g->grayagain = NULL; g->weak = g->ephemeron = g->allweak = NULL; + g->twups = NULL; g->totalbytes = sizeof(LG); g->GCdebt = 0; + g->gcfinnum = 0; g->gcpause = LUAI_GCPAUSE; - g->gcmajorinc = LUAI_GCMAJOR; g->gcstepmul = LUAI_GCMUL; for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { diff --git a/depends/lua/src/lstring.c b/depends/lua/src/lstring.c index af96c89c1..9351766fd 100644 --- a/depends/lua/src/lstring.c +++ b/depends/lua/src/lstring.c @@ -1,23 +1,30 @@ /* -** $Id: lstring.c,v 2.26.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ - -#include - #define lstring_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" +#include "ldebug.h" +#include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" +#define MEMERRMSG "not enough memory" + + /* ** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to ** compute its hash @@ -31,99 +38,126 @@ ** equality for long strings */ int luaS_eqlngstr (TString *a, TString *b) { - size_t len = a->tsv.len; - lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR); + size_t len = a->u.lnglen; + lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); return (a == b) || /* same instance or... */ - ((len == b->tsv.len) && /* equal length and ... */ + ((len == b->u.lnglen) && /* equal length and ... */ (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ } -/* -** equality for strings -*/ -int luaS_eqstr (TString *a, TString *b) { - return (a->tsv.tt == b->tsv.tt) && - (a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b)); -} - - unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { unsigned int h = seed ^ cast(unsigned int, l); - size_t l1; size_t step = (l >> LUAI_HASHLIMIT) + 1; - for (l1 = l; l1 >= step; l1 -= step) - h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1])); + for (; l >= step; l -= step) + h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); return h; } +unsigned int luaS_hashlongstr (TString *ts) { + lua_assert(ts->tt == LUA_TLNGSTR); + if (ts->extra == 0) { /* no hash? */ + ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash); + ts->extra = 1; /* now it has its hash */ + } + return ts->hash; +} + + /* ** resizes the string table */ void luaS_resize (lua_State *L, int newsize) { int i; stringtable *tb = &G(L)->strt; - /* cannot resize while GC is traversing strings */ - luaC_runtilstate(L, ~bitmask(GCSsweepstring)); - if (newsize > tb->size) { - luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *); - for (i = tb->size; i < newsize; i++) tb->hash[i] = NULL; + if (newsize > tb->size) { /* grow table if needed */ + luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); + for (i = tb->size; i < newsize; i++) + tb->hash[i] = NULL; } - /* rehash */ - for (i=0; isize; i++) { - GCObject *p = tb->hash[i]; + for (i = 0; i < tb->size; i++) { /* rehash */ + TString *p = tb->hash[i]; tb->hash[i] = NULL; while (p) { /* for each node in the list */ - GCObject *next = gch(p)->next; /* save next */ - unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */ - gch(p)->next = tb->hash[h]; /* chain it */ + TString *hnext = p->u.hnext; /* save next */ + unsigned int h = lmod(p->hash, newsize); /* new position */ + p->u.hnext = tb->hash[h]; /* chain it */ tb->hash[h] = p; - resetoldbit(p); /* see MOVE OLD rule */ - p = next; + p = hnext; } } - if (newsize < tb->size) { - /* shrinking slice must be empty */ + if (newsize < tb->size) { /* shrink table if needed */ + /* vanishing slice should be empty */ lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); - luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *); + luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); } tb->size = newsize; } +/* +** Clear API string cache. (Entries cannot be empty, so fill them with +** a non-collectable string.) +*/ +void luaS_clearcache (global_State *g) { + int i, j; + for (i = 0; i < STRCACHE_N; i++) + for (j = 0; j < STRCACHE_M; j++) { + if (iswhite(g->strcache[i][j])) /* will entry be collected? */ + g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ + } +} + + +/* +** Initialize the string table and the string cache +*/ +void luaS_init (lua_State *L) { + global_State *g = G(L); + int i, j; + luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + /* pre-create memory-error message */ + g->memerrmsg = luaS_newliteral(L, MEMERRMSG); + luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ + for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ + for (j = 0; j < STRCACHE_M; j++) + g->strcache[i][j] = g->memerrmsg; +} + + + /* ** creates a new string object */ -static TString *createstrobj (lua_State *L, const char *str, size_t l, - int tag, unsigned int h, GCObject **list) { +static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { TString *ts; + GCObject *o; size_t totalsize; /* total size of TString object */ - totalsize = sizeof(TString) + ((l + 1) * sizeof(char)); - ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts; - ts->tsv.len = l; - ts->tsv.hash = h; - ts->tsv.extra = 0; - memcpy(ts+1, str, l*sizeof(char)); - ((char *)(ts+1))[l] = '\0'; /* ending 0 */ + totalsize = sizelstring(l); + o = luaC_newobj(L, tag, totalsize); + ts = gco2ts(o); + ts->hash = h; + ts->extra = 0; + getstr(ts)[l] = '\0'; /* ending 0 */ return ts; } -/* -** creates a new short string, inserting it into string table -*/ -static TString *newshrstr (lua_State *L, const char *str, size_t l, - unsigned int h) { - GCObject **list; /* (pointer to) list where it will be inserted */ +TString *luaS_createlngstrobj (lua_State *L, size_t l) { + TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed); + ts->u.lnglen = l; + return ts; +} + + +void luaS_remove (lua_State *L, TString *ts) { stringtable *tb = &G(L)->strt; - TString *s; - if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) - luaS_resize(L, tb->size*2); /* too crowded */ - list = &tb->hash[lmod(h, tb->size)]; - s = createstrobj(L, str, l, LUA_TSHRSTR, h, list); - tb->nuse++; - return s; + TString **p = &tb->hash[lmod(ts->hash, tb->size)]; + while (*p != ts) /* find previous element */ + p = &(*p)->u.hnext; + *p = (*p)->u.hnext; /* remove element from its list */ + tb->nuse--; } @@ -131,22 +165,31 @@ static TString *newshrstr (lua_State *L, const char *str, size_t l, ** checks whether short string exists and reuses it or creates a new one */ static TString *internshrstr (lua_State *L, const char *str, size_t l) { - GCObject *o; + TString *ts; global_State *g = G(L); unsigned int h = luaS_hash(str, l, g->seed); - for (o = g->strt.hash[lmod(h, g->strt.size)]; - o != NULL; - o = gch(o)->next) { - TString *ts = rawgco2ts(o); - if (h == ts->tsv.hash && - l == ts->tsv.len && + TString **list = &g->strt.hash[lmod(h, g->strt.size)]; + lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ + for (ts = *list; ts != NULL; ts = ts->u.hnext) { + if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { - if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */ - changewhite(o); /* resurrect it */ + /* found! */ + if (isdead(g, ts)) /* dead (but not collected yet)? */ + changewhite(ts); /* resurrect it */ return ts; } } - return newshrstr(L, str, l, h); /* not found; create a new string */ + if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { + luaS_resize(L, g->strt.size * 2); + list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ + } + ts = createstrobj(L, l, LUA_TSHRSTR, h); + memcpy(getstr(ts), str, l * sizeof(char)); + ts->shrlen = cast_byte(l); + ts->u.hnext = *list; + *list = ts; + g->strt.nuse++; + return ts; } @@ -157,29 +200,49 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { if (l <= LUAI_MAXSHORTLEN) /* short string? */ return internshrstr(L, str, l); else { - if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) + TString *ts; + if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char)) luaM_toobig(L); - return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL); + ts = luaS_createlngstrobj(L, l); + memcpy(getstr(ts), str, l * sizeof(char)); + return ts; } } /* -** new zero-terminated string +** Create or reuse a zero-terminated string, first checking in the +** cache (using the string address as a key). The cache can contain +** only zero-terminated strings, so it is safe to use 'strcmp' to +** check hits. */ TString *luaS_new (lua_State *L, const char *str) { - return luaS_newlstr(L, str, strlen(str)); + unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ + int j; + TString **p = G(L)->strcache[i]; + for (j = 0; j < STRCACHE_M; j++) { + if (strcmp(str, getstr(p[j])) == 0) /* hit? */ + return p[j]; /* that is it */ + } + /* normal route */ + for (j = STRCACHE_M - 1; j > 0; j--) + p[j] = p[j - 1]; /* move out last element */ + /* new element is first in the list */ + p[0] = luaS_newlstr(L, str, strlen(str)); + return p[0]; } -Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { +Udata *luaS_newudata (lua_State *L, size_t s) { Udata *u; - if (s > MAX_SIZET - sizeof(Udata)) + GCObject *o; + if (s > MAX_SIZE - sizeof(Udata)) luaM_toobig(L); - u = &luaC_newobj(L, LUA_TUSERDATA, sizeof(Udata) + s, NULL, 0)->u; - u->uv.len = s; - u->uv.metatable = NULL; - u->uv.env = e; + o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s)); + u = gco2u(o); + u->len = s; + u->metatable = NULL; + setuservalue(L, u, luaO_nilobject); return u; } diff --git a/depends/lua/src/lstrlib.c b/depends/lua/src/lstrlib.c index 9261fd220..12264f881 100644 --- a/depends/lua/src/lstrlib.c +++ b/depends/lua/src/lstrlib.c @@ -1,19 +1,24 @@ /* -** $Id: lstrlib.c,v 1.178.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lstrlib.c,v 1.251 2016/05/20 14:13:21 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ +#define lstrlib_c +#define LUA_LIB + +#include "lprefix.h" + #include +#include +#include +#include #include #include #include #include -#define lstrlib_c -#define LUA_LIB - #include "lua.h" #include "lauxlib.h" @@ -22,17 +27,29 @@ /* ** maximum number of captures that a pattern can do during -** pattern-matching. This limit is arbitrary. +** pattern-matching. This limit is arbitrary, but must fit in +** an unsigned char. */ #if !defined(LUA_MAXCAPTURES) #define LUA_MAXCAPTURES 32 #endif -/* macro to `unsign' a character */ +/* macro to 'unsign' a character */ #define uchar(c) ((unsigned char)(c)) +/* +** Some sizes are better limited to fit in 'int', but must also fit in +** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) +*/ +#define MAX_SIZET ((size_t)(~(size_t)0)) + +#define MAXSIZE \ + (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) + + + static int str_len (lua_State *L) { size_t l; @@ -43,22 +60,22 @@ static int str_len (lua_State *L) { /* translate a relative string position: negative means back from end */ -static size_t posrelat (ptrdiff_t pos, size_t len) { - if (pos >= 0) return (size_t)pos; +static lua_Integer posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; else if (0u - (size_t)pos > len) return 0; - else return len - ((size_t)-pos) + 1; + else return (lua_Integer)len + pos + 1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - size_t start = posrelat(luaL_checkinteger(L, 2), l); - size_t end = posrelat(luaL_optinteger(L, 3, -1), l); + lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); + lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; - if (end > l) end = l; + if (end > (lua_Integer)l) end = l; if (start <= end) - lua_pushlstring(L, s + start - 1, end - start + 1); + lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); else lua_pushliteral(L, ""); return 1; } @@ -102,25 +119,23 @@ static int str_upper (lua_State *L) { } -/* reasonable limit to avoid arithmetic overflow */ -#define MAXSIZE ((~(size_t)0) >> 1) - static int str_rep (lua_State *L) { size_t l, lsep; const char *s = luaL_checklstring(L, 1, &l); - int n = luaL_checkint(L, 2); + lua_Integer n = luaL_checkinteger(L, 2); const char *sep = luaL_optlstring(L, 3, "", &lsep); if (n <= 0) lua_pushliteral(L, ""); - else if (l + lsep < l || l + lsep >= MAXSIZE / n) /* may overflow? */ + else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */ return luaL_error(L, "resulting string too large"); else { - size_t totallen = n * l + (n - 1) * lsep; + size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, totallen); while (n-- > 1) { /* first n-1 copies (followed by separator) */ memcpy(p, s, l * sizeof(char)); p += l; - if (lsep > 0) { /* avoid empty 'memcpy' (may be expensive) */ - memcpy(p, sep, lsep * sizeof(char)); p += lsep; + if (lsep > 0) { /* empty 'memcpy' is not that cheap */ + memcpy(p, sep, lsep * sizeof(char)); + p += lsep; } } memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ @@ -133,15 +148,15 @@ static int str_rep (lua_State *L) { static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); - size_t posi = posrelat(luaL_optinteger(L, 2, 1), l); - size_t pose = posrelat(luaL_optinteger(L, 3, posi), l); + lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); + lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; if (posi < 1) posi = 1; - if (pose > l) pose = l; + if (pose > (lua_Integer)l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ - n = (int)(pose - posi + 1); - if (posi + n <= pose) /* (size_t -> int) overflow? */ + if (pose - posi >= INT_MAX) /* arithmetic overflow? */ return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; luaL_checkstack(L, n, "string slice too long"); for (i=0; ip_end) - luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")"); + luaL_error(ms->L, "malformed pattern (ends with '%%')"); return p+1; } case '[': { if (*p == '^') p++; - do { /* look for a `]' */ + do { /* look for a ']' */ if (p == ms->p_end) - luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")"); + luaL_error(ms->L, "malformed pattern (missing ']')"); if (*(p++) == L_ESC && p < ms->p_end) - p++; /* skip escapes (e.g. `%]') */ + p++; /* skip escapes (e.g. '%]') */ } while (*p != ']'); return p+1; } @@ -287,7 +303,7 @@ static int matchbracketclass (int c, const char *p, const char *ec) { int sig = 1; if (*(p+1) == '^') { sig = 0; - p++; /* skip the `^' */ + p++; /* skip the '^' */ } while (++p < ec) { if (*p == L_ESC) { @@ -325,8 +341,7 @@ static int singlematch (MatchState *ms, const char *s, const char *p, static const char *matchbalance (MatchState *ms, const char *s, const char *p) { if (p >= ms->p_end - 1) - luaL_error(ms->L, "malformed pattern " - "(missing arguments to " LUA_QL("%%b") ")"); + luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); if (*s != *p) return NULL; else { int b = *p; @@ -425,7 +440,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { break; } 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? */ goto dflt; /* no; go to default */ s = (s == ms->src_end) ? s : NULL; /* check end of string */ break; @@ -443,8 +458,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { const char *ep; char previous; p += 2; if (*p != '[') - luaL_error(ms->L, "missing " LUA_QL("[") " after " - LUA_QL("%%f") " in pattern"); + luaL_error(ms->L, "missing '[' after '%%f' in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s - 1); if (!matchbracketclass(uchar(previous), p, ep - 1) && @@ -490,7 +504,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { } case '+': /* 1 or more repetitions */ s++; /* 1 match already done */ - /* go through */ + /* FALLTHROUGH */ case '*': /* 0 or more repetitions */ s = max_expand(ms, s, p, ep); break; @@ -514,16 +528,16 @@ static const char *match (MatchState *ms, const char *s, const char *p) { static const char *lmemfind (const char *s1, size_t l1, const char *s2, size_t l2) { if (l2 == 0) return s1; /* empty strings are everywhere */ - else if (l2 > l1) return NULL; /* avoids a negative `l1' */ + else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ else { - const char *init; /* to search for a `*s2' inside `s1' */ - l2--; /* 1st char will be checked by `memchr' */ - l1 = l1-l2; /* `s2' cannot be found after that */ + const char *init; /* to search for a '*s2' inside 's1' */ + l2--; /* 1st char will be checked by 'memchr' */ + l1 = l1-l2; /* 's2' cannot be found after that */ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { init++; /* 1st char is already checked */ if (memcmp(init, s2+1, l2) == 0) return init-1; - else { /* correct `l1' and `s1' to try again */ + else { /* correct 'l1' and 's1' to try again */ l1 -= init-s1; s1 = init; } @@ -539,13 +553,13 @@ static void push_onecapture (MatchState *ms, int i, const char *s, if (i == 0) /* ms->level == 0, too */ lua_pushlstring(ms->L, s, e - s); /* add whole match */ else - luaL_error(ms->L, "invalid capture index"); + luaL_error(ms->L, "invalid capture index %%%d", i + 1); } else { ptrdiff_t l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) - lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1); + lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); else lua_pushlstring(ms->L, ms->capture[i].init, l); } @@ -574,23 +588,39 @@ static int nospecials (const char *p, size_t l) { } +static void prepstate (MatchState *ms, lua_State *L, + const char *s, size_t ls, const char *p, size_t lp) { + ms->L = L; + ms->matchdepth = MAXCCALLS; + ms->src_init = s; + ms->src_end = s + ls; + ms->p_end = p + lp; +} + + +static void reprepstate (MatchState *ms) { + ms->level = 0; + lua_assert(ms->matchdepth == MAXCCALLS); +} + + static int str_find_aux (lua_State *L, int find) { size_t ls, lp; const char *s = luaL_checklstring(L, 1, &ls); const char *p = luaL_checklstring(L, 2, &lp); - size_t init = posrelat(luaL_optinteger(L, 3, 1), ls); + lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); if (init < 1) init = 1; - else if (init > ls + 1) { /* start after string's end? */ + else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ lua_pushnil(L); /* cannot find anything */ return 1; } /* explicit request or no special characters? */ if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { /* do a plain search */ - const char *s2 = lmemfind(s + init - 1, ls - init + 1, p, lp); + const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); if (s2) { - lua_pushinteger(L, s2 - s + 1); - lua_pushinteger(L, s2 - s + lp); + lua_pushinteger(L, (s2 - s) + 1); + lua_pushinteger(L, (s2 - s) + lp); return 2; } } @@ -601,18 +631,13 @@ static int str_find_aux (lua_State *L, int find) { if (anchor) { p++; lp--; /* skip anchor character */ } - ms.L = L; - ms.matchdepth = MAXCCALLS; - ms.src_init = s; - ms.src_end = s + ls; - ms.p_end = p + lp; + prepstate(&ms, L, s, ls, p, lp); do { const char *res; - ms.level = 0; - lua_assert(ms.matchdepth == MAXCCALLS); + reprepstate(&ms); if ((res=match(&ms, s1, p)) != NULL) { if (find) { - lua_pushinteger(L, s1 - s + 1); /* start */ + lua_pushinteger(L, (s1 - s) + 1); /* start */ lua_pushinteger(L, res - s); /* end */ return push_captures(&ms, NULL, 0) + 2; } @@ -636,29 +661,25 @@ static int str_match (lua_State *L) { } +/* state for 'gmatch' */ +typedef struct GMatchState { + const char *src; /* current position */ + const char *p; /* pattern */ + const char *lastmatch; /* end of last match */ + MatchState ms; /* match state */ +} GMatchState; + + static int gmatch_aux (lua_State *L) { - MatchState ms; - size_t ls, lp; - const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls); - const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); + GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); const char *src; - ms.L = L; - ms.matchdepth = MAXCCALLS; - ms.src_init = s; - ms.src_end = s+ls; - ms.p_end = p + lp; - for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3)); - src <= ms.src_end; - src++) { + gm->ms.L = L; + for (src = gm->src; src <= gm->ms.src_end; src++) { const char *e; - ms.level = 0; - lua_assert(ms.matchdepth == MAXCCALLS); - if ((e = match(&ms, src, p)) != NULL) { - lua_Integer newstart = e-s; - if (e == src) newstart++; /* empty match? go at least one position */ - lua_pushinteger(L, newstart); - lua_replace(L, lua_upvalueindex(3)); - return push_captures(&ms, src, e); + reprepstate(&gm->ms); + if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) { + gm->src = gm->lastmatch = e; + return push_captures(&gm->ms, src, e); } } return 0; /* not found */ @@ -666,10 +687,14 @@ static int gmatch_aux (lua_State *L) { static int gmatch (lua_State *L) { - luaL_checkstring(L, 1); - luaL_checkstring(L, 2); - lua_settop(L, 2); - lua_pushinteger(L, 0); + size_t ls, lp; + const char *s = luaL_checklstring(L, 1, &ls); + const char *p = luaL_checklstring(L, 2, &lp); + GMatchState *gm; + lua_settop(L, 2); /* keep them on closure to avoid being collected */ + gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); + prepstate(&gm->ms, L, s, ls, p, lp); + gm->src = s; gm->p = p; gm->lastmatch = NULL; lua_pushcclosure(L, gmatch_aux, 3); return 1; } @@ -678,7 +703,8 @@ static int gmatch (lua_State *L) { static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { size_t l, i; - const char *news = lua_tolstring(ms->L, 3, &l); + lua_State *L = ms->L; + const char *news = lua_tolstring(L, 3, &l); for (i = 0; i < l; i++) { if (news[i] != L_ESC) luaL_addchar(b, news[i]); @@ -686,14 +712,15 @@ static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, i++; /* skip ESC */ if (!isdigit(uchar(news[i]))) { if (news[i] != L_ESC) - luaL_error(ms->L, "invalid use of " LUA_QL("%c") - " in replacement string", L_ESC); + luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); luaL_addchar(b, news[i]); } else if (news[i] == '0') luaL_addlstring(b, s, e - s); else { push_onecapture(ms, news[i] - '1', s, e); + luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ + lua_remove(L, -2); /* remove original value */ luaL_addvalue(b); /* add capture to accumulated result */ } } @@ -734,12 +761,13 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, static int str_gsub (lua_State *L) { size_t srcl, lp; - const char *src = luaL_checklstring(L, 1, &srcl); - const char *p = luaL_checklstring(L, 2, &lp); - int tr = lua_type(L, 3); - size_t max_s = luaL_optinteger(L, 4, srcl+1); + const char *src = luaL_checklstring(L, 1, &srcl); /* subject */ + const char *p = luaL_checklstring(L, 2, &lp); /* pattern */ + const char *lastmatch = NULL; /* end of last match */ + int tr = lua_type(L, 3); /* replacement type */ + lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */ int anchor = (*p == '^'); - size_t n = 0; + lua_Integer n = 0; /* replacement count */ MatchState ms; luaL_Buffer b; luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || @@ -749,25 +777,18 @@ static int str_gsub (lua_State *L) { if (anchor) { p++; lp--; /* skip anchor character */ } - ms.L = L; - ms.matchdepth = MAXCCALLS; - ms.src_init = src; - ms.src_end = src+srcl; - ms.p_end = p + lp; + prepstate(&ms, L, src, srcl, p, lp); while (n < max_s) { const char *e; - ms.level = 0; - lua_assert(ms.matchdepth == MAXCCALLS); - e = match(&ms, src, p); - if (e) { + reprepstate(&ms); /* (re)prepare state for new match */ + if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */ n++; - add_value(&ms, &b, src, e, tr); + add_value(&ms, &b, src, e, tr); /* add replacement to buffer */ + src = lastmatch = e; } - if (e && e>src) /* non empty match? */ - src = e; /* skip it */ - else if (src < ms.src_end) + else if (src < ms.src_end) /* otherwise, skip one character */ luaL_addchar(&b, *src++); - else break; + else break; /* end of subject */ if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); @@ -786,65 +807,116 @@ static int str_gsub (lua_State *L) { ** ======================================================= */ +#if !defined(lua_number2strx) /* { */ + /* -** LUA_INTFRMLEN is the length modifier for integer conversions in -** 'string.format'; LUA_INTFRM_T is the integer type corresponding to -** the previous length +** Hexadecimal floating-point formatter */ -#if !defined(LUA_INTFRMLEN) /* { */ -#if defined(LUA_USE_LONGLONG) -#define LUA_INTFRMLEN "ll" -#define LUA_INTFRM_T long long +#include -#else +#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) -#define LUA_INTFRMLEN "l" -#define LUA_INTFRM_T long -#endif -#endif /* } */ +/* +** Number of bits that goes into the first digit. It can be any value +** between 1 and 4; the following definition tries to align the number +** to nibble boundaries by making what is left after that first digit a +** multiple of 4. +*/ +#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) /* -** LUA_FLTFRMLEN is the length modifier for float conversions in -** 'string.format'; LUA_FLTFRM_T is the float type corresponding to -** the previous length +** Add integer part of 'x' to buffer and return new 'x' */ -#if !defined(LUA_FLTFRMLEN) +static lua_Number adddigit (char *buff, int n, lua_Number x) { + lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ + int d = (int)dd; + buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ + return x - dd; /* return what is left */ +} -#define LUA_FLTFRMLEN "" -#define LUA_FLTFRM_T double -#endif +static int num2straux (char *buff, int sz, lua_Number x) { + if (x != x || x == HUGE_VAL || x == -HUGE_VAL) /* inf or NaN? */ + return l_sprintf(buff, sz, LUA_NUMBER_FMT, x); /* equal to '%g' */ + else if (x == 0) { /* can be -0... */ + /* create "0" or "-0" followed by exponent */ + return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", x); + } + else { + int e; + lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ + int n = 0; /* character count */ + if (m < 0) { /* is number negative? */ + buff[n++] = '-'; /* add signal */ + m = -m; /* make it positive */ + } + buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ + m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ + e -= L_NBFD; /* this digit goes before the radix point */ + if (m > 0) { /* more digits? */ + buff[n++] = lua_getlocaledecpoint(); /* add radix point */ + do { /* add as many digits as needed */ + m = adddigit(buff, n++, m * 16); + } while (m > 0); + } + n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ + lua_assert(n < sz); + return n; + } +} + + +static int lua_number2strx (lua_State *L, char *buff, int sz, + const char *fmt, lua_Number x) { + int n = num2straux(buff, sz, x); + if (fmt[SIZELENMOD] == 'A') { + int i; + for (i = 0; i < n; i++) + buff[i] = toupper(uchar(buff[i])); + } + else if (fmt[SIZELENMOD] != 'a') + luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); + return n; +} + +#endif /* } */ + + +/* +** Maximum size of each formatted item. This maximum size is produced +** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', +** and '\0') + number of decimal digits to represent maxfloat (which +** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra +** expenses", such as locale-dependent stuff) +*/ +#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) -/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ -#define MAX_ITEM 512 /* valid flags in a format specification */ #define FLAGS "-+ #0" + /* -** maximum size of each format specification (such as '%-099.99d') -** (+10 accounts for %99.99x plus margin of error) +** maximum size of each format specification (such as "%-099.99d") */ -#define MAX_FORMAT (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10) +#define MAX_FORMAT 32 -static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { - size_t l; - const char *s = luaL_checklstring(L, arg, &l); +static void addquoted (luaL_Buffer *b, const char *s, size_t len) { luaL_addchar(b, '"'); - while (l--) { + while (len--) { if (*s == '"' || *s == '\\' || *s == '\n') { luaL_addchar(b, '\\'); luaL_addchar(b, *s); } - else if (*s == '\0' || iscntrl(uchar(*s))) { + else if (iscntrl(uchar(*s))) { char buff[10]; if (!isdigit(uchar(*(s+1)))) - sprintf(buff, "\\%d", (int)uchar(*s)); + l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); else - sprintf(buff, "\\%03d", (int)uchar(*s)); + l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); luaL_addstring(b, buff); } else @@ -854,6 +926,57 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { luaL_addchar(b, '"'); } + +/* +** Ensures the 'buff' string uses a dot as the radix character. +*/ +static void checkdp (char *buff, int nb) { + if (memchr(buff, '.', nb) == NULL) { /* no dot? */ + char point = lua_getlocaledecpoint(); /* try locale point */ + char *ppoint = memchr(buff, point, nb); + if (ppoint) *ppoint = '.'; /* change it to a dot */ + } +} + + +static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { + switch (lua_type(L, arg)) { + case LUA_TSTRING: { + size_t len; + const char *s = lua_tolstring(L, arg, &len); + addquoted(b, s, len); + break; + } + case LUA_TNUMBER: { + char *buff = luaL_prepbuffsize(b, MAX_ITEM); + int nb; + if (!lua_isinteger(L, arg)) { /* float? */ + lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */ + nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n); + checkdp(buff, nb); /* ensure it uses a dot */ + } + else { /* integers */ + lua_Integer n = lua_tointeger(L, arg); + const char *format = (n == LUA_MININTEGER) /* corner case? */ + ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ + : LUA_INTEGER_FMT; /* else use default format */ + nb = l_sprintf(buff, MAX_ITEM, format, n); + } + luaL_addsize(b, nb); + break; + } + case LUA_TNIL: case LUA_TBOOLEAN: { + luaL_tolstring(L, arg, NULL); + luaL_addvalue(b); + break; + } + default: { + luaL_argerror(L, arg, "value has no literal form"); + } + } +} + + static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ @@ -869,8 +992,8 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; - memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char)); - form += p - strfrmt + 1; + memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); + form += (p - strfrmt) + 1; *form = '\0'; return p; } @@ -903,7 +1026,7 @@ static int str_format (lua_State *L) { else if (*++strfrmt == L_ESC) luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ - char form[MAX_FORMAT]; /* to store the format (`%...') */ + char form[MAX_FORMAT]; /* to store the format ('%...') */ char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ int nb = 0; /* number of bytes in added item */ if (++arg > top) @@ -911,62 +1034,55 @@ static int str_format (lua_State *L) { strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { - nb = sprintf(buff, form, luaL_checkint(L, arg)); - break; - } - case 'd': case 'i': { - lua_Number n = luaL_checknumber(L, arg); - LUA_INTFRM_T ni = (LUA_INTFRM_T)n; - lua_Number diff = n - (lua_Number)ni; - luaL_argcheck(L, -1 < diff && diff < 1, arg, - "not a number in proper range"); - addlenmod(form, LUA_INTFRMLEN); - nb = sprintf(buff, form, ni); + nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); break; } + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { - lua_Number n = luaL_checknumber(L, arg); - unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n; - lua_Number diff = n - (lua_Number)ni; - luaL_argcheck(L, -1 < diff && diff < 1, arg, - "not a non-negative number in proper range"); - addlenmod(form, LUA_INTFRMLEN); - nb = sprintf(buff, form, ni); + lua_Integer n = luaL_checkinteger(L, arg); + addlenmod(form, LUA_INTEGER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, n); break; } - case 'e': case 'E': case 'f': -#if defined(LUA_USE_AFORMAT) case 'a': case 'A': -#endif + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = lua_number2strx(L, buff, MAX_ITEM, form, + luaL_checknumber(L, arg)); + break; + case 'e': case 'E': case 'f': case 'g': case 'G': { - addlenmod(form, LUA_FLTFRMLEN); - nb = sprintf(buff, form, (LUA_FLTFRM_T)luaL_checknumber(L, arg)); + addlenmod(form, LUA_NUMBER_FRMLEN); + nb = l_sprintf(buff, MAX_ITEM, form, luaL_checknumber(L, arg)); break; } case 'q': { - addquoted(L, &b, arg); + addliteral(L, &b, arg); break; } case 's': { size_t l; const char *s = luaL_tolstring(L, arg, &l); - if (!strchr(form, '.') && l >= 100) { - /* no precision and string is too long to be formatted; - keep original string */ - luaL_addvalue(&b); - break; - } + if (form[2] == '\0') /* no modifiers? */ + luaL_addvalue(&b); /* keep entire string */ else { - nb = sprintf(buff, form, s); - lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ - break; + luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); + if (!strchr(form, '.') && l >= 100) { + /* no precision and string is too long to be formatted */ + luaL_addvalue(&b); /* keep entire string */ + } + else { /* format the string into 'buff' */ + nb = l_sprintf(buff, MAX_ITEM, form, s); + lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ + } } + break; } - default: { /* also treat cases `pnLlh' */ - return luaL_error(L, "invalid option " LUA_QL("%%%c") " to " - LUA_QL("format"), *(strfrmt - 1)); + default: { /* also treat cases 'pnLlh' */ + return luaL_error(L, "invalid option '%%%c' to 'format'", + *(strfrmt - 1)); } } + lua_assert(nb < MAX_ITEM); luaL_addsize(&b, nb); } } @@ -977,6 +1093,450 @@ static int str_format (lua_State *L) { /* }====================================================== */ +/* +** {====================================================== +** PACK/UNPACK +** ======================================================= +*/ + + +/* value used for padding */ +#if !defined(LUAL_PACKPADBYTE) +#define LUAL_PACKPADBYTE 0x00 +#endif + +/* maximum size for the binary representation of an integer */ +#define MAXINTSIZE 16 + +/* number of bits in a character */ +#define NB CHAR_BIT + +/* mask for one character (NB 1's) */ +#define MC ((1 << NB) - 1) + +/* size of a lua_Integer */ +#define SZINT ((int)sizeof(lua_Integer)) + + +/* dummy union to get native endianness */ +static const union { + int dummy; + char little; /* true iff machine is little endian */ +} nativeendian = {1}; + + +/* dummy structure to get native alignment requirements */ +struct cD { + char c; + union { double d; void *p; lua_Integer i; lua_Number n; } u; +}; + +#define MAXALIGN (offsetof(struct cD, u)) + + +/* +** Union for serializing floats +*/ +typedef union Ftypes { + float f; + double d; + lua_Number n; + char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ +} Ftypes; + + +/* +** information to pack/unpack stuff +*/ +typedef struct Header { + lua_State *L; + int islittle; + int maxalign; +} Header; + + +/* +** options for pack/unpack +*/ +typedef enum KOption { + Kint, /* signed integers */ + Kuint, /* unsigned integers */ + Kfloat, /* floating-point numbers */ + Kchar, /* fixed-length strings */ + Kstring, /* strings with prefixed length */ + Kzstr, /* zero-terminated strings */ + Kpadding, /* padding */ + Kpaddalign, /* padding for alignment */ + Knop /* no-op (configuration or spaces) */ +} KOption; + + +/* +** Read an integer numeral from string 'fmt' or return 'df' if +** there is no numeral +*/ +static int digit (int c) { return '0' <= c && c <= '9'; } + +static int getnum (const char **fmt, int df) { + if (!digit(**fmt)) /* no number? */ + return df; /* return default value */ + else { + int a = 0; + do { + a = a*10 + (*((*fmt)++) - '0'); + } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); + return a; + } +} + + +/* +** Read an integer numeral and raises an error if it is larger +** than the maximum size for integers. +*/ +static int getnumlimit (Header *h, const char **fmt, int df) { + int sz = getnum(fmt, df); + if (sz > MAXINTSIZE || sz <= 0) + luaL_error(h->L, "integral size (%d) out of limits [1,%d]", + sz, MAXINTSIZE); + return sz; +} + + +/* +** Initialize Header +*/ +static void initheader (lua_State *L, Header *h) { + h->L = L; + h->islittle = nativeendian.little; + h->maxalign = 1; +} + + +/* +** Read and classify next option. 'size' is filled with option's size. +*/ +static KOption getoption (Header *h, const char **fmt, int *size) { + int opt = *((*fmt)++); + *size = 0; /* default */ + switch (opt) { + case 'b': *size = sizeof(char); return Kint; + case 'B': *size = sizeof(char); return Kuint; + case 'h': *size = sizeof(short); return Kint; + case 'H': *size = sizeof(short); return Kuint; + case 'l': *size = sizeof(long); return Kint; + case 'L': *size = sizeof(long); return Kuint; + case 'j': *size = sizeof(lua_Integer); return Kint; + case 'J': *size = sizeof(lua_Integer); return Kuint; + case 'T': *size = sizeof(size_t); return Kuint; + case 'f': *size = sizeof(float); return Kfloat; + case 'd': *size = sizeof(double); return Kfloat; + case 'n': *size = sizeof(lua_Number); return Kfloat; + case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; + case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; + case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; + case 'c': + *size = getnum(fmt, -1); + if (*size == -1) + luaL_error(h->L, "missing size for format option 'c'"); + return Kchar; + case 'z': return Kzstr; + case 'x': *size = 1; return Kpadding; + case 'X': return Kpaddalign; + case ' ': break; + case '<': h->islittle = 1; break; + case '>': h->islittle = 0; break; + case '=': h->islittle = nativeendian.little; break; + case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; + default: luaL_error(h->L, "invalid format option '%c'", opt); + } + return Knop; +} + + +/* +** Read, classify, and fill other details about the next option. +** 'psize' is filled with option's size, 'notoalign' with its +** alignment requirements. +** Local variable 'size' gets the size to be aligned. (Kpadal option +** always gets its full alignment, other options are limited by +** the maximum alignment ('maxalign'). Kchar option needs no alignment +** despite its size. +*/ +static KOption getdetails (Header *h, size_t totalsize, + const char **fmt, int *psize, int *ntoalign) { + KOption opt = getoption(h, fmt, psize); + int align = *psize; /* usually, alignment follows size */ + if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ + if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) + luaL_argerror(h->L, 1, "invalid next option for option 'X'"); + } + if (align <= 1 || opt == Kchar) /* need no alignment? */ + *ntoalign = 0; + else { + if (align > h->maxalign) /* enforce maximum alignment */ + align = h->maxalign; + if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ + luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); + *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); + } + return opt; +} + + +/* +** Pack integer 'n' with 'size' bytes and 'islittle' endianness. +** The final 'if' handles the case when 'size' is larger than +** the size of a Lua integer, correcting the extra sign-extension +** bytes if necessary (by default they would be zeros). +*/ +static void packint (luaL_Buffer *b, lua_Unsigned n, + int islittle, int size, int neg) { + char *buff = luaL_prepbuffsize(b, size); + int i; + buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ + for (i = 1; i < size; i++) { + n >>= NB; + buff[islittle ? i : size - 1 - i] = (char)(n & MC); + } + if (neg && size > SZINT) { /* negative number need sign extension? */ + for (i = SZINT; i < size; i++) /* correct extra bytes */ + buff[islittle ? i : size - 1 - i] = (char)MC; + } + luaL_addsize(b, size); /* add result to buffer */ +} + + +/* +** Copy 'size' bytes from 'src' to 'dest', correcting endianness if +** given 'islittle' is different from native endianness. +*/ +static void copywithendian (volatile char *dest, volatile const char *src, + int size, int islittle) { + if (islittle == nativeendian.little) { + while (size-- != 0) + *(dest++) = *(src++); + } + else { + dest += size - 1; + while (size-- != 0) + *(dest--) = *(src++); + } +} + + +static int str_pack (lua_State *L) { + luaL_Buffer b; + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + int arg = 1; /* current argument to pack */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + lua_pushnil(L); /* mark to separate arguments from string buffer */ + luaL_buffinit(L, &b); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + totalsize += ntoalign + size; + while (ntoalign-- > 0) + luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */ + arg++; + switch (opt) { + case Kint: { /* signed integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) { /* need overflow check? */ + lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); + luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); + } + packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); + break; + } + case Kuint: { /* unsigned integers */ + lua_Integer n = luaL_checkinteger(L, arg); + if (size < SZINT) /* need overflow check? */ + luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), + arg, "unsigned overflow"); + packint(&b, (lua_Unsigned)n, h.islittle, size, 0); + break; + } + case Kfloat: { /* floating-point options */ + volatile Ftypes u; + char *buff = luaL_prepbuffsize(&b, size); + lua_Number n = luaL_checknumber(L, arg); /* get argument */ + if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ + else if (size == sizeof(u.d)) u.d = (double)n; + else u.n = n; + /* move 'u' to final result, correcting endianness if needed */ + copywithendian(buff, u.buff, size, h.islittle); + luaL_addsize(&b, size); + break; + } + case Kchar: { /* fixed-size string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, len <= (size_t)size, arg, + "string longer than given size"); + luaL_addlstring(&b, s, len); /* add string */ + while (len++ < (size_t)size) /* pad extra space */ + luaL_addchar(&b, LUAL_PACKPADBYTE); + break; + } + case Kstring: { /* strings with length count */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, size >= (int)sizeof(size_t) || + len < ((size_t)1 << (size * NB)), + arg, "string length does not fit in given size"); + packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ + luaL_addlstring(&b, s, len); + totalsize += len; + break; + } + case Kzstr: { /* zero-terminated string */ + size_t len; + const char *s = luaL_checklstring(L, arg, &len); + luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); + luaL_addlstring(&b, s, len); + luaL_addchar(&b, '\0'); /* add zero at the end */ + totalsize += len + 1; + break; + } + case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */ + case Kpaddalign: case Knop: + arg--; /* undo increment */ + break; + } + } + luaL_pushresult(&b); + return 1; +} + + +static int str_packsize (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); /* format string */ + size_t totalsize = 0; /* accumulate total size of result */ + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); + size += ntoalign; /* total space used by option */ + luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, + "format result too large"); + totalsize += size; + switch (opt) { + case Kstring: /* strings with length count */ + case Kzstr: /* zero-terminated string */ + luaL_argerror(L, 1, "variable-length format"); + /* call never return, but to avoid warnings: *//* FALLTHROUGH */ + default: break; + } + } + lua_pushinteger(L, (lua_Integer)totalsize); + return 1; +} + + +/* +** Unpack an integer with 'size' bytes and 'islittle' endianness. +** If size is smaller than the size of a Lua integer and integer +** is signed, must do sign extension (propagating the sign to the +** higher bits); if size is larger than the size of a Lua integer, +** it must check the unread bytes to see whether they do not cause an +** overflow. +*/ +static lua_Integer unpackint (lua_State *L, const char *str, + int islittle, int size, int issigned) { + lua_Unsigned res = 0; + int i; + int limit = (size <= SZINT) ? size : SZINT; + for (i = limit - 1; i >= 0; i--) { + res <<= NB; + res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; + } + if (size < SZINT) { /* real size smaller than lua_Integer? */ + if (issigned) { /* needs sign extension? */ + lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); + res = ((res ^ mask) - mask); /* do sign extension */ + } + } + else if (size > SZINT) { /* must check unread bytes */ + int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; + for (i = limit; i < size; i++) { + if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) + luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); + } + } + return (lua_Integer)res; +} + + +static int str_unpack (lua_State *L) { + Header h; + const char *fmt = luaL_checkstring(L, 1); + size_t ld; + const char *data = luaL_checklstring(L, 2, &ld); + size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; + int n = 0; /* number of results */ + luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + initheader(L, &h); + while (*fmt != '\0') { + int size, ntoalign; + KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); + if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) + luaL_argerror(L, 2, "data string too short"); + pos += ntoalign; /* skip alignment */ + /* stack space for item + next position */ + luaL_checkstack(L, 2, "too many results"); + n++; + switch (opt) { + case Kint: + case Kuint: { + lua_Integer res = unpackint(L, data + pos, h.islittle, size, + (opt == Kint)); + lua_pushinteger(L, res); + break; + } + case Kfloat: { + volatile Ftypes u; + lua_Number num; + copywithendian(u.buff, data + pos, size, h.islittle); + if (size == sizeof(u.f)) num = (lua_Number)u.f; + else if (size == sizeof(u.d)) num = (lua_Number)u.d; + else num = u.n; + lua_pushnumber(L, num); + break; + } + case Kchar: { + lua_pushlstring(L, data + pos, size); + break; + } + case Kstring: { + size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); + luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); + lua_pushlstring(L, data + pos + size, len); + pos += len; /* skip string */ + break; + } + case Kzstr: { + size_t len = (int)strlen(data + pos); + lua_pushlstring(L, data + pos, len); + pos += len + 1; /* skip string plus final '\0' */ + break; + } + case Kpaddalign: case Kpadding: case Knop: + n--; /* undo increment */ + break; + } + pos += size; + } + lua_pushinteger(L, pos + 1); /* next position */ + return n + 1; +} + +/* }====================================================== */ + + static const luaL_Reg strlib[] = { {"byte", str_byte}, {"char", str_char}, @@ -992,6 +1552,9 @@ static const luaL_Reg strlib[] = { {"reverse", str_reverse}, {"sub", str_sub}, {"upper", str_upper}, + {"pack", str_pack}, + {"packsize", str_packsize}, + {"unpack", str_unpack}, {NULL, NULL} }; diff --git a/depends/lua/src/ltable.c b/depends/lua/src/ltable.c index 5d76f97ec..7e15b71ba 100644 --- a/depends/lua/src/ltable.c +++ b/depends/lua/src/ltable.c @@ -1,27 +1,30 @@ /* -** $Id: ltable.c,v 2.72.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ltable.c,v 2.117 2015/11/19 19:16:22 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ +#define ltable_c +#define LUA_CORE + +#include "lprefix.h" + /* ** Implementation of tables (aka arrays, objects, or hash tables). ** Tables keep its elements in two parts: an array part and a hash part. ** Non-negative integer keys are all candidates to be kept in the array -** part. The actual size of the array is the largest `n' such that at -** least half the slots between 0 and n are in use. +** part. The actual size of the array is the largest 'n' such that +** more than half the slots between 1 and n are in use. ** Hash uses a mix of chained scatter table with Brent's variation. ** A main invariant of these tables is that, if an element is not -** in its main position (i.e. the `original' position that its hash gives +** in its main position (i.e. the 'original' position that its hash gives ** to it), then the colliding element is in its own main position. ** Hence even when the load factor reaches 100%, performance remains good. */ -#include - -#define ltable_c -#define LUA_CORE +#include +#include #include "lua.h" @@ -37,21 +40,26 @@ /* -** max size of array part is 2^MAXBITS +** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is +** the largest integer such that MAXASIZE fits in an unsigned int. */ -#if LUAI_BITSINT >= 32 -#define MAXBITS 30 -#else -#define MAXBITS (LUAI_BITSINT-2) -#endif +#define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) +#define MAXASIZE (1u << MAXABITS) -#define MAXASIZE (1 << MAXBITS) +/* +** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest +** integer such that 2^MAXHBITS fits in a signed int. (Note that the +** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still +** fits comfortably in an unsigned int.) +*/ +#define MAXHBITS (MAXABITS - 1) #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) -#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) +#define hashstr(t,str) hashpow2(t, (str)->hash) #define hashboolean(t,p) hashpow2(t, p) +#define hashint(t,i) hashpow2(t, i) /* @@ -61,7 +69,7 @@ #define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) -#define hashpointer(t,p) hashmod(t, IntPoint(p)) +#define hashpointer(t,p) hashmod(t, point2uint(p)) #define dummynode (&dummynode_) @@ -70,44 +78,54 @@ static const Node dummynode_ = { {NILCONSTANT}, /* value */ - {{NILCONSTANT, NULL}} /* key */ + {{NILCONSTANT, 0}} /* key */ }; /* -** hash for lua_Numbers +** Hash for floating-point numbers. +** The main computation should be just +** n = frexp(n, &i); return (n * INT_MAX) + i +** but there are some numerical subtleties. +** In a two-complement representation, INT_MAX does not has an exact +** representation as a float, but INT_MIN does; because the absolute +** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the +** absolute value of the product 'frexp * -INT_MIN' is smaller or equal +** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when +** adding 'i'; the use of '~u' (instead of '-u') avoids problems with +** INT_MIN. */ -static Node *hashnum (const Table *t, lua_Number n) { +#if !defined(l_hashfloat) +static int l_hashfloat (lua_Number n) { int i; - luai_hashnum(i, n); - if (i < 0) { - if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */ - i = 0; /* handle INT_MIN */ - i = -i; /* must be a positive value */ + lua_Integer ni; + n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); + if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */ + lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL)); + return 0; + } + else { /* normal case */ + unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni); + return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u); } - return hashmod(t, i); } - +#endif /* -** returns the `main' position of an element in a table (that is, the index +** returns the 'main' position of an element in a table (that is, the index ** of its hash value) */ static Node *mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { - case LUA_TNUMBER: - return hashnum(t, nvalue(key)); - case LUA_TLNGSTR: { - TString *s = rawtsvalue(key); - if (s->tsv.extra == 0) { /* no hash? */ - s->tsv.hash = luaS_hash(getstr(s), s->tsv.len, s->tsv.hash); - s->tsv.extra = 1; /* now it has its hash */ - } - return hashstr(t, rawtsvalue(key)); - } + case LUA_TNUMINT: + return hashint(t, ivalue(key)); + case LUA_TNUMFLT: + return hashmod(t, l_hashfloat(fltvalue(key))); case LUA_TSHRSTR: - return hashstr(t, rawtsvalue(key)); + return hashstr(t, tsvalue(key)); + case LUA_TLNGSTR: + return hashpow2(t, luaS_hashlongstr(tsvalue(key))); case LUA_TBOOLEAN: return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: @@ -115,67 +133,68 @@ static Node *mainposition (const Table *t, const TValue *key) { case LUA_TLCF: return hashpointer(t, fvalue(key)); default: + lua_assert(!ttisdeadkey(key)); return hashpointer(t, gcvalue(key)); } } /* -** returns the index for `key' if `key' is an appropriate key to live in -** the array part of the table, -1 otherwise. +** returns the index for 'key' if 'key' is an appropriate key to live in +** the array part of the table, 0 otherwise. */ -static int arrayindex (const TValue *key) { - if (ttisnumber(key)) { - lua_Number n = nvalue(key); - int k; - lua_number2int(k, n); - if (luai_numeq(cast_num(k), n)) - return k; +static unsigned int arrayindex (const TValue *key) { + if (ttisinteger(key)) { + lua_Integer k = ivalue(key); + if (0 < k && (lua_Unsigned)k <= MAXASIZE) + return cast(unsigned int, k); /* 'key' is an appropriate array index */ } - return -1; /* `key' did not match some condition */ + return 0; /* 'key' did not match some condition */ } /* -** returns the index of a `key' for table traversals. First goes all +** returns the index of a 'key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The -** beginning of a traversal is signaled by -1. +** beginning of a traversal is signaled by 0. */ -static int findindex (lua_State *L, Table *t, StkId key) { - int i; - if (ttisnil(key)) return -1; /* first iteration */ +static unsigned int findindex (lua_State *L, Table *t, StkId key) { + unsigned int i; + if (ttisnil(key)) return 0; /* first iteration */ i = arrayindex(key); - if (0 < i && i <= t->sizearray) /* is `key' inside array part? */ - return i-1; /* yes; that's the index (corrected to C) */ + if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ + return i; /* yes; that's the index */ else { + int nx; Node *n = mainposition(t, key); - for (;;) { /* check whether `key' is somewhere in the chain */ - /* key may be dead already, but it is ok to use it in `next' */ + for (;;) { /* check whether 'key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in 'next' */ if (luaV_rawequalobj(gkey(n), key) || (ttisdeadkey(gkey(n)) && iscollectable(key) && deadvalue(gkey(n)) == gcvalue(key))) { i = cast_int(n - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ - return i + t->sizearray; + return (i + 1) + t->sizearray; } - else n = gnext(n); - if (n == NULL) - luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */ + nx = gnext(n); + if (nx == 0) + luaG_runerror(L, "invalid key to 'next'"); /* key not found */ + else n += nx; } } } int luaH_next (lua_State *L, Table *t, StkId key) { - int i = findindex(L, t, key); /* find original element */ - for (i++; i < t->sizearray; i++) { /* try first array part */ + unsigned int i = findindex(L, t, key); /* find original element */ + for (; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ - setnvalue(key, cast_num(i+1)); + setivalue(key, i + 1); setobj2s(L, key+1, &t->array[i]); return 1; } } - for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */ + for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ setobj2s(L, key, gkey(gnode(t, i))); setobj2s(L, key+1, gval(gnode(t, i))); @@ -192,32 +211,38 @@ int luaH_next (lua_State *L, Table *t, StkId key) { ** ============================================================== */ - -static int computesizes (int nums[], int *narray) { +/* +** Compute the optimal size for the array part of table 't'. 'nums' is a +** "count array" where 'nums[i]' is the number of integers in the table +** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of +** integer keys in the table and leaves with the number of keys that +** will go to the array part; return the optimal size. +*/ +static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { int i; - int twotoi; /* 2^i */ - int a = 0; /* number of elements smaller than 2^i */ - int na = 0; /* number of elements to go to array part */ - int n = 0; /* optimal size for array part */ - for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) { + unsigned int twotoi; /* 2^i (candidate for optimal size) */ + unsigned int a = 0; /* number of elements smaller than 2^i */ + unsigned int na = 0; /* number of elements to go to array part */ + unsigned int optimal = 0; /* optimal size for array part */ + /* loop while keys can fill more than half of total size */ + for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) { if (nums[i] > 0) { a += nums[i]; if (a > twotoi/2) { /* more than half elements present? */ - n = twotoi; /* optimal size (till now) */ - na = a; /* all elements smaller than n will go to array part */ + optimal = twotoi; /* optimal size (till now) */ + na = a; /* all elements up to 'optimal' will go to array part */ } } - if (a == *narray) break; /* all elements already counted */ } - *narray = n; - lua_assert(*narray/2 <= na && na <= *narray); - return na; + lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal); + *pna = na; + return optimal; } -static int countint (const TValue *key, int *nums) { - int k = arrayindex(key); - if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ +static int countint (const TValue *key, unsigned int *nums) { + unsigned int k = arrayindex(key); + if (k != 0) { /* is 'key' an appropriate array index? */ nums[luaO_ceillog2(k)]++; /* count as such */ return 1; } @@ -226,20 +251,26 @@ static int countint (const TValue *key, int *nums) { } -static int numusearray (const Table *t, int *nums) { +/* +** Count keys in array part of table 't': Fill 'nums[i]' with +** number of keys that will go into corresponding slice and return +** total number of non-nil keys. +*/ +static unsigned int numusearray (const Table *t, unsigned int *nums) { int lg; - int ttlg; /* 2^lg */ - int ause = 0; /* summation of `nums' */ - int i = 1; /* count to traverse all array keys */ - for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ - int lc = 0; /* counter */ - int lim = ttlg; + unsigned int ttlg; /* 2^lg */ + unsigned int ause = 0; /* summation of 'nums' */ + unsigned int i = 1; /* count to traverse all array keys */ + /* traverse each slice */ + for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { + unsigned int lc = 0; /* counter */ + unsigned int lim = ttlg; if (lim > t->sizearray) { lim = t->sizearray; /* adjust upper limit */ if (i > lim) break; /* no more elements to count */ } - /* count elements in range (2^(lg-1), 2^lg] */ + /* count elements in range (2^(lg - 1), 2^lg] */ for (; i <= lim; i++) { if (!ttisnil(&t->array[i-1])) lc++; @@ -251,9 +282,9 @@ static int numusearray (const Table *t, int *nums) { } -static int numusehash (const Table *t, int *nums, int *pnasize) { +static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { int totaluse = 0; /* total number of elements */ - int ause = 0; /* summation of `nums' */ + int ause = 0; /* elements added to 'nums' (can go to array part) */ int i = sizenode(t); while (i--) { Node *n = &t->node[i]; @@ -262,13 +293,13 @@ static int numusehash (const Table *t, int *nums, int *pnasize) { totaluse++; } } - *pnasize += ause; + *pna += ause; return totaluse; } -static void setarrayvector (lua_State *L, Table *t, int size) { - int i; +static void setarrayvector (lua_State *L, Table *t, unsigned int size) { + unsigned int i; luaM_reallocvector(L, t->array, t->sizearray, size, TValue); for (i=t->sizearray; iarray[i]); @@ -276,23 +307,23 @@ static void setarrayvector (lua_State *L, Table *t, int size) { } -static void setnodevector (lua_State *L, Table *t, int size) { +static void setnodevector (lua_State *L, Table *t, unsigned int size) { int lsize; if (size == 0) { /* no elements to hash part? */ - t->node = cast(Node *, dummynode); /* use common `dummynode' */ + t->node = cast(Node *, dummynode); /* use common 'dummynode' */ lsize = 0; } else { int i; lsize = luaO_ceillog2(size); - if (lsize > MAXBITS) + if (lsize > MAXHBITS) luaG_runerror(L, "table overflow"); size = twoto(lsize); t->node = luaM_newvector(L, size, Node); - for (i=0; isizearray; +void luaH_resize (lua_State *L, Table *t, unsigned int nasize, + unsigned int nhsize) { + unsigned int i; + int j; + unsigned int oldasize = t->sizearray; int oldhsize = t->lsizenode; Node *nold = t->node; /* save old hash ... */ if (nasize > oldasize) /* array part must grow? */ @@ -321,8 +354,8 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { luaM_reallocvector(L, t->array, oldasize, nasize, TValue); } /* re-insert elements from hash part */ - for (i = twoto(oldhsize) - 1; i >= 0; i--) { - Node *old = nold+i; + for (j = twoto(oldhsize) - 1; j >= 0; j--) { + Node *old = nold + j; if (!ttisnil(gval(old))) { /* doesn't need barrier/invalidate cache, as entry was already present in the table */ @@ -330,32 +363,35 @@ void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize) { } } if (!isdummy(nold)) - luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old array */ + luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old hash */ } -void luaH_resizearray (lua_State *L, Table *t, int nasize) { +void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { int nsize = isdummy(t->node) ? 0 : sizenode(t); luaH_resize(L, t, nasize, nsize); } - +/* +** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i +*/ static void rehash (lua_State *L, Table *t, const TValue *ek) { - int nasize, na; - int nums[MAXBITS+1]; /* nums[i] = number of keys with 2^(i-1) < k <= 2^i */ + unsigned int asize; /* optimal size for array part */ + unsigned int na; /* number of keys in the array part */ + unsigned int nums[MAXABITS + 1]; int i; int totaluse; - for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ - nasize = numusearray(t, nums); /* count keys in array part */ - totaluse = nasize; /* all those keys are integer keys */ - totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */ + for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ + na = numusearray(t, nums); /* count keys in array part */ + totaluse = na; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, &na); /* count keys in hash part */ /* count extra key */ - nasize += countint(ek, nums); + na += countint(ek, nums); totaluse++; /* compute new size for array part */ - na = computesizes(nums, &nasize); + asize = computesizes(nums, &na); /* resize the table to new computed sizes */ - luaH_resize(L, t, nasize, totaluse - na); + luaH_resize(L, t, asize, totaluse - na); } @@ -366,7 +402,8 @@ static void rehash (lua_State *L, Table *t, const TValue *ek) { Table *luaH_new (lua_State *L) { - Table *t = &luaC_newobj(L, LUA_TTABLE, sizeof(Table), NULL, 0)->h; + GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table)); + Table *t = gco2t(o); t->metatable = NULL; t->flags = cast_byte(~0); t->array = NULL; @@ -404,37 +441,51 @@ static Node *getfreepos (Table *t) { */ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { Node *mp; + TValue aux; if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && luai_numisnan(L, nvalue(key))) - luaG_runerror(L, "table index is NaN"); + else if (ttisfloat(key)) { + lua_Integer k; + if (luaV_tointeger(key, &k, 0)) { /* index is int? */ + setivalue(&aux, k); + key = &aux; /* insert it as an integer */ + } + else if (luai_numisnan(fltvalue(key))) + luaG_runerror(L, "table index is NaN"); + } mp = mainposition(t, key); if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ Node *othern; - Node *n = getfreepos(t); /* get a free place */ - if (n == NULL) { /* cannot find a free place? */ + Node *f = getfreepos(t); /* get a free place */ + if (f == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ - /* whatever called 'newkey' take care of TM cache and GC barrier */ + /* whatever called 'newkey' takes care of TM cache */ return luaH_set(L, t, key); /* insert key into grown table */ } - lua_assert(!isdummy(n)); + lua_assert(!isdummy(f)); othern = mainposition(t, gkey(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ - while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ - gnext(othern) = n; /* redo the chain with `n' in place of `mp' */ - *n = *mp; /* copy colliding node into free pos. (mp->next also goes) */ - gnext(mp) = NULL; /* now `mp' is free */ + while (othern + gnext(othern) != mp) /* find previous */ + othern += gnext(othern); + gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ + *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ + if (gnext(mp) != 0) { + gnext(f) += cast_int(mp - f); /* correct 'next' */ + gnext(mp) = 0; /* now 'mp' is free */ + } setnilvalue(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ - gnext(n) = gnext(mp); /* chain new position */ - gnext(mp) = n; - mp = n; + if (gnext(mp) != 0) + gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ + else lua_assert(gnext(f) == 0); + gnext(mp) = cast_int(f - mp); + mp = f; } } - setobj2t(L, gkey(mp), key); - luaC_barrierback(L, obj2gco(t), key); + setnodekey(L, &mp->i_key, key); + luaC_barrierback(L, t, key); lua_assert(ttisnil(gval(mp))); return gval(mp); } @@ -443,18 +494,21 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { /* ** search function for integers */ -const TValue *luaH_getint (Table *t, int key) { +const TValue *luaH_getint (Table *t, lua_Integer key) { /* (1 <= key && key <= t->sizearray) */ - if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) - return &t->array[key-1]; + if (l_castS2U(key) - 1 < t->sizearray) + return &t->array[key - 1]; else { - lua_Number nk = cast_num(key); - Node *n = hashnum(t, nk); - do { /* check whether `key' is somewhere in the chain */ - if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) + Node *n = hashint(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key) return gval(n); /* that's it */ - else n = gnext(n); - } while (n); + else { + int nx = gnext(n); + if (nx == 0) break; + n += nx; + } + } return luaO_nilobject; } } @@ -463,15 +517,50 @@ const TValue *luaH_getint (Table *t, int key) { /* ** search function for short strings */ -const TValue *luaH_getstr (Table *t, TString *key) { +const TValue *luaH_getshortstr (Table *t, TString *key) { Node *n = hashstr(t, key); - lua_assert(key->tsv.tt == LUA_TSHRSTR); - do { /* check whether `key' is somewhere in the chain */ - if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key)) + lua_assert(key->tt == LUA_TSHRSTR); + for (;;) { /* check whether 'key' is somewhere in the chain */ + const TValue *k = gkey(n); + if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) + return gval(n); /* that's it */ + else { + int nx = gnext(n); + if (nx == 0) + return luaO_nilobject; /* not found */ + n += nx; + } + } +} + + +/* +** "Generic" get version. (Not that generic: not valid for integers, +** which may be in array part, nor for floats with integral values.) +*/ +static const TValue *getgeneric (Table *t, const TValue *key) { + Node *n = mainposition(t, key); + for (;;) { /* check whether 'key' is somewhere in the chain */ + if (luaV_rawequalobj(gkey(n), key)) return gval(n); /* that's it */ - else n = gnext(n); - } while (n); - return luaO_nilobject; + else { + int nx = gnext(n); + if (nx == 0) + return luaO_nilobject; /* not found */ + n += nx; + } + } +} + + +const TValue *luaH_getstr (Table *t, TString *key) { + if (key->tt == LUA_TSHRSTR) + return luaH_getshortstr(t, key); + else { /* for long strings, use generic case */ + TValue ko; + setsvalue(cast(lua_State *, NULL), &ko, key); + return getgeneric(t, &ko); + } } @@ -480,25 +569,17 @@ const TValue *luaH_getstr (Table *t, TString *key) { */ const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { - case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key)); + case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key)); + case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); case LUA_TNIL: return luaO_nilobject; - case LUA_TNUMBER: { - int k; - lua_Number n = nvalue(key); - lua_number2int(k, n); - if (luai_numeq(cast_num(k), n)) /* index is int? */ + case LUA_TNUMFLT: { + lua_Integer k; + if (luaV_tointeger(key, &k, 0)) /* index is int? */ return luaH_getint(t, k); /* use specialized version */ - /* else go through */ - } - default: { - Node *n = mainposition(t, key); - do { /* check whether `key' is somewhere in the chain */ - if (luaV_rawequalobj(gkey(n), key)) - return gval(n); /* that's it */ - else n = gnext(n); - } while (n); - return luaO_nilobject; - } + /* else... */ + } /* FALLTHROUGH */ + default: + return getgeneric(t, key); } } @@ -515,14 +596,14 @@ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { } -void luaH_setint (lua_State *L, Table *t, int key, TValue *value) { +void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { const TValue *p = luaH_getint(t, key); TValue *cell; if (p != luaO_nilobject) cell = cast(TValue *, p); else { TValue k; - setnvalue(&k, cast_num(key)); + setivalue(&k, key); cell = luaH_newkey(L, t, &k); } setobj2t(L, cell, value); @@ -532,16 +613,16 @@ void luaH_setint (lua_State *L, Table *t, int key, TValue *value) { static int unbound_search (Table *t, unsigned int j) { unsigned int i = j; /* i is zero or a present index */ j++; - /* find `i' and `j' such that i is present and j is not */ + /* find 'i' and 'j' such that i is present and j is not */ while (!ttisnil(luaH_getint(t, j))) { i = j; - j *= 2; - if (j > cast(unsigned int, MAX_INT)) { /* overflow? */ + if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; while (!ttisnil(luaH_getint(t, i))) i++; return i - 1; } + j *= 2; } /* now do a binary search between them */ while (j - i > 1) { @@ -554,7 +635,7 @@ static int unbound_search (Table *t, unsigned int j) { /* -** Try to find a boundary in table `t'. A `boundary' is an integer index +** Try to find a boundary in table 't'. A 'boundary' is an integer index ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). */ int luaH_getn (Table *t) { diff --git a/depends/lua/src/ltablib.c b/depends/lua/src/ltablib.c index 6001224e3..98b2f8713 100644 --- a/depends/lua/src/ltablib.c +++ b/depends/lua/src/ltablib.c @@ -1,23 +1,61 @@ /* -** $Id: ltablib.c,v 1.65.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ - -#include - #define ltablib_c #define LUA_LIB +#include "lprefix.h" + + +#include +#include +#include + #include "lua.h" #include "lauxlib.h" #include "lualib.h" -#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n)) +/* +** Operations that an object must define to mimic a table +** (some functions only need some of them) +*/ +#define TAB_R 1 /* read */ +#define TAB_W 2 /* write */ +#define TAB_L 4 /* length */ +#define TAB_RW (TAB_R | TAB_W) /* read/write */ + + +#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) + +static int checkfield (lua_State *L, const char *key, int n) { + lua_pushstring(L, key); + return (lua_rawget(L, -n) != LUA_TNIL); +} + + +/* +** Check that 'arg' either is a table or can behave like one (that is, +** has a metatable with the required metamethods) +*/ +static void checktab (lua_State *L, int arg, int what) { + if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ + int n = 1; /* number of elements to pop */ + if (lua_getmetatable(L, arg) && /* must have metatable */ + (!(what & TAB_R) || checkfield(L, "__index", ++n)) && + (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && + (!(what & TAB_L) || checkfield(L, "__len", ++n))) { + lua_pop(L, n); /* pop metatable and tested metamethods */ + } + else + luaL_checktype(L, arg, LUA_TTABLE); /* force an error */ + } +} #if defined(LUA_COMPAT_MAXN) @@ -39,65 +77,102 @@ static int maxn (lua_State *L) { static int tinsert (lua_State *L) { - int e = aux_getn(L, 1) + 1; /* first empty element */ - int pos; /* where to insert new element */ + lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ + lua_Integer pos; /* where to insert new element */ switch (lua_gettop(L)) { case 2: { /* called with only 2 arguments */ pos = e; /* insert new element at the end */ break; } case 3: { - int i; - pos = luaL_checkint(L, 2); /* 2nd argument is the position */ + lua_Integer i; + pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); for (i = e; i > pos; i--) { /* move up elements */ - lua_rawgeti(L, 1, i-1); - lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ + lua_geti(L, 1, i - 1); + lua_seti(L, 1, i); /* t[i] = t[i - 1] */ } break; } default: { - return luaL_error(L, "wrong number of arguments to " LUA_QL("insert")); + return luaL_error(L, "wrong number of arguments to 'insert'"); } } - lua_rawseti(L, 1, pos); /* t[pos] = v */ + lua_seti(L, 1, pos); /* t[pos] = v */ return 0; } static int tremove (lua_State *L) { - int size = aux_getn(L, 1); - int pos = luaL_optint(L, 2, size); + lua_Integer size = aux_getn(L, 1, TAB_RW); + lua_Integer pos = luaL_optinteger(L, 2, size); if (pos != size) /* validate 'pos' if given */ luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); - lua_rawgeti(L, 1, pos); /* result = t[pos] */ + lua_geti(L, 1, pos); /* result = t[pos] */ for ( ; pos < size; pos++) { - lua_rawgeti(L, 1, pos+1); - lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */ + lua_geti(L, 1, pos + 1); + lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ } lua_pushnil(L); - lua_rawseti(L, 1, pos); /* t[pos] = nil */ + lua_seti(L, 1, pos); /* t[pos] = nil */ return 1; } -static void addfield (lua_State *L, luaL_Buffer *b, int i) { - lua_rawgeti(L, 1, i); +/* +** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever +** possible, copy in increasing order, which is better for rehashing. +** "possible" means destination after original range, or smaller +** than origin, or copying to another table. +*/ +static int tmove (lua_State *L) { + lua_Integer f = luaL_checkinteger(L, 2); + lua_Integer e = luaL_checkinteger(L, 3); + lua_Integer t = luaL_checkinteger(L, 4); + int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + checktab(L, 1, TAB_R); + checktab(L, tt, TAB_W); + if (e >= f) { /* otherwise, nothing to move */ + lua_Integer n, i; + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, + "too many elements to move"); + n = e - f + 1; /* number of elements to move */ + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, + "destination wrap around"); + if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { + for (i = 0; i < n; i++) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + else { + for (i = n - 1; i >= 0; i--) { + lua_geti(L, 1, f + i); + lua_seti(L, tt, t + i); + } + } + } + lua_pushvalue(L, tt); /* return destination table */ + return 1; +} + + +static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { + lua_geti(L, 1, i); if (!lua_isstring(L, -1)) - luaL_error(L, "invalid value (%s) at index %d in table for " - LUA_QL("concat"), luaL_typename(L, -1), i); + luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", + luaL_typename(L, -1), i); luaL_addvalue(b); } static int tconcat (lua_State *L) { luaL_Buffer b; + lua_Integer last = aux_getn(L, 1, TAB_R); size_t lsep; - int i, last; const char *sep = luaL_optlstring(L, 2, "", &lsep); - luaL_checktype(L, 1, LUA_TTABLE); - i = luaL_optint(L, 3, 1); - last = luaL_opt(L, luaL_checkint, 4, luaL_len(L, 1)); + lua_Integer i = luaL_optinteger(L, 3, 1); + last = luaL_optinteger(L, 4, last); luaL_buffinit(L, &b); for (; i < last; i++) { addfield(L, &b, i); @@ -117,35 +192,31 @@ static int tconcat (lua_State *L) { */ static int pack (lua_State *L) { + int i; int n = lua_gettop(L); /* number of elements to pack */ lua_createtable(L, n, 1); /* create result table */ + lua_insert(L, 1); /* put it at index 1 */ + for (i = n; i >= 1; i--) /* assign elements */ + lua_seti(L, 1, i); lua_pushinteger(L, n); - lua_setfield(L, -2, "n"); /* t.n = number of elements */ - if (n > 0) { /* at least one element? */ - int i; - lua_pushvalue(L, 1); - lua_rawseti(L, -2, 1); /* insert first element */ - lua_replace(L, 1); /* move table into index 1 */ - for (i = n; i >= 2; i--) /* assign other elements */ - lua_rawseti(L, 1, i); - } + lua_setfield(L, 1, "n"); /* t.n = number of elements */ return 1; /* return table */ } static int unpack (lua_State *L) { - int i, e, n; - luaL_checktype(L, 1, LUA_TTABLE); - i = luaL_optint(L, 2, 1); - e = luaL_opt(L, luaL_checkint, 3, luaL_len(L, 1)); + lua_Unsigned n; + lua_Integer i = luaL_optinteger(L, 2, 1); + lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); if (i > e) return 0; /* empty range */ - n = e - i + 1; /* number of elements */ - if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */ + n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ + if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) return luaL_error(L, "too many results to unpack"); - lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ - while (i++ < e) /* push arg[i + 1...e] */ - lua_rawgeti(L, 1, i); - return n; + for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ + lua_geti(L, 1, i); + } + lua_geti(L, 1, e); /* push last element */ + return (int)n; } /* }====================================================== */ @@ -155,102 +226,197 @@ static int unpack (lua_State *L) { /* ** {====================================================== ** Quicksort -** (based on `Algorithms in MODULA-3', Robert Sedgewick; +** (based on 'Algorithms in MODULA-3', Robert Sedgewick; ** Addison-Wesley, 1993.) ** ======================================================= */ -static void set2 (lua_State *L, int i, int j) { - lua_rawseti(L, 1, i); - lua_rawseti(L, 1, j); +/* type for array indices */ +typedef unsigned int IdxT; + + +/* +** Produce a "random" 'unsigned int' to randomize pivot choice. This +** macro is used only when 'sort' detects a big imbalance in the result +** of a partition. (If you don't want/need this "randomness", ~0 is a +** good choice.) +*/ +#if !defined(l_randomizePivot) /* { */ + +#include + +/* size of 'e' measured in number of 'unsigned int's */ +#define sof(e) (sizeof(e) / sizeof(unsigned int)) + +/* +** Use 'time' and 'clock' as sources of "randomness". Because we don't +** know the types 'clock_t' and 'time_t', we cannot cast them to +** anything without risking overflows. A safe way to use their values +** is to copy them to an array of a known type and use the array values. +*/ +static unsigned int l_randomizePivot (void) { + clock_t c = clock(); + time_t t = time(NULL); + unsigned int buff[sof(c) + sof(t)]; + unsigned int i, rnd = 0; + memcpy(buff, &c, sof(c) * sizeof(unsigned int)); + memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); + for (i = 0; i < sof(buff); i++) + rnd += buff[i]; + return rnd; +} + +#endif /* } */ + + +/* arrays larger than 'RANLIMIT' may use randomized pivots */ +#define RANLIMIT 100u + + +static void set2 (lua_State *L, IdxT i, IdxT j) { + lua_seti(L, 1, i); + lua_seti(L, 1, j); } + +/* +** Return true iff value at stack index 'a' is less than the value at +** index 'b' (according to the order of the sort). +*/ static int sort_comp (lua_State *L, int a, int b) { - if (!lua_isnil(L, 2)) { /* function? */ + if (lua_isnil(L, 2)) /* no function? */ + return lua_compare(L, a, b, LUA_OPLT); /* a < b */ + else { /* function */ int res; - lua_pushvalue(L, 2); + lua_pushvalue(L, 2); /* push function */ lua_pushvalue(L, a-1); /* -1 to compensate function */ - lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */ - lua_call(L, 2, 1); - res = lua_toboolean(L, -1); - lua_pop(L, 1); + lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ + lua_call(L, 2, 1); /* call function */ + res = lua_toboolean(L, -1); /* get result */ + lua_pop(L, 1); /* pop result */ return res; } - else /* a < b? */ - return lua_compare(L, a, b, LUA_OPLT); } -static void auxsort (lua_State *L, int l, int u) { - while (l < u) { /* for tail recursion */ - int i, j; - /* sort elements a[l], a[(l+u)/2] and a[u] */ - lua_rawgeti(L, 1, l); - lua_rawgeti(L, 1, u); - if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */ - set2(L, l, u); /* swap a[l] - a[u] */ + +/* +** Does the partition: Pivot P is at the top of the stack. +** precondition: a[lo] <= P == a[up-1] <= a[up], +** so it only needs to do the partition from lo + 1 to up - 2. +** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] +** returns 'i'. +*/ +static IdxT partition (lua_State *L, IdxT lo, IdxT up) { + IdxT i = lo; /* will be incremented before first use */ + IdxT j = up - 1; /* will be decremented before first use */ + /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ + for (;;) { + /* next loop: repeat ++i while a[i] < P */ + while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { + if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ + /* next loop: repeat --j while P < a[j] */ + while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { + if (j < i) /* j < i but a[j] > P ?? */ + luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[j] */ + } + /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ + if (j < i) { /* no elements out of place? */ + /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ + lua_pop(L, 1); /* pop a[j] */ + /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ + set2(L, up - 1, i); + return i; + } + /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ + set2(L, i, j); + } +} + + +/* +** Choose an element in the middle (2nd-3th quarters) of [lo,up] +** "randomized" by 'rnd' +*/ +static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) { + IdxT r4 = (up - lo) / 4; /* range/4 */ + IdxT p = rnd % (r4 * 2) + (lo + r4); + lua_assert(lo + r4 <= p && p <= up - r4); + return p; +} + + +/* +** QuickSort algorithm (recursive function) +*/ +static void auxsort (lua_State *L, IdxT lo, IdxT up, + unsigned int rnd) { + while (lo < up) { /* loop for tail recursion */ + IdxT p; /* Pivot index */ + IdxT n; /* to be used later */ + /* sort elements 'lo', 'p', and 'up' */ + lua_geti(L, 1, lo); + lua_geti(L, 1, up); + if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ + set2(L, lo, up); /* swap a[lo] - a[up] */ else - lua_pop(L, 2); - if (u-l == 1) break; /* only 2 elements */ - i = (l+u)/2; - lua_rawgeti(L, 1, i); - lua_rawgeti(L, 1, l); - if (sort_comp(L, -2, -1)) /* a[i]= P */ - while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i>=u) luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[i] */ - } - /* repeat --j until a[j] <= P */ - while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j<=l) luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[j] */ - } - if (j n) /* partition too imbalanced? */ + rnd = l_randomizePivot(); /* try a new randomization */ + } /* tail call auxsort(L, lo, up, rnd) */ } + static int sort (lua_State *L) { - int n = aux_getn(L, 1); - luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */ - if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ - luaL_checktype(L, 2, LUA_TFUNCTION); - lua_settop(L, 2); /* make sure there is two arguments */ - auxsort(L, 1, n); + lua_Integer n = aux_getn(L, 1, TAB_RW); + if (n > 1) { /* non-trivial interval? */ + luaL_argcheck(L, n < INT_MAX, 1, "array too big"); + if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ + luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ + lua_settop(L, 2); /* make sure there are two arguments */ + auxsort(L, 1, (IdxT)n, 0); + } return 0; } @@ -266,6 +432,7 @@ static const luaL_Reg tab_funcs[] = { {"pack", pack}, {"unpack", unpack}, {"remove", tremove}, + {"move", tmove}, {"sort", sort}, {NULL, NULL} }; diff --git a/depends/lua/src/ltm.c b/depends/lua/src/ltm.c index 69b4ed772..4650cc293 100644 --- a/depends/lua/src/ltm.c +++ b/depends/lua/src/ltm.c @@ -1,22 +1,27 @@ /* -** $Id: ltm.c,v 2.14.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: ltm.c,v 2.37 2016/02/26 19:20:15 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ - -#include - #define ltm_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" +#include "ldebug.h" +#include "ldo.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" +#include "lvm.h" static const char udatatypename[] = "userdata"; @@ -25,7 +30,7 @@ LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { "no value", "nil", "boolean", udatatypename, "number", "string", "table", "function", udatatypename, "thread", - "proto", "upval" /* these last two cases are used for tests only */ + "proto" /* this last case is used for tests only */ }; @@ -33,14 +38,16 @@ void luaT_init (lua_State *L) { static const char *const luaT_eventname[] = { /* ORDER TM */ "__index", "__newindex", "__gc", "__mode", "__len", "__eq", - "__add", "__sub", "__mul", "__div", "__mod", - "__pow", "__unm", "__lt", "__le", + "__add", "__sub", "__mul", "__mod", "__pow", + "__div", "__idiv", + "__band", "__bor", "__bxor", "__shl", "__shr", + "__unm", "__bnot", "__lt", "__le", "__concat", "__call" }; int i; for (i=0; itmname[i] = luaS_new(L, luaT_eventname[i]); - luaS_fix(G(L)->tmname[i]); /* never collect these names */ + luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ } } @@ -50,7 +57,7 @@ void luaT_init (lua_State *L) { ** tag methods */ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { - const TValue *tm = luaH_getstr(events, ename); + const TValue *tm = luaH_getshortstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ events->flags |= cast_byte(1u<metatable; break; @@ -70,8 +77,89 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { mt = uvalue(o)->metatable; break; default: - mt = G(L)->mt[ttypenv(o)]; + mt = G(L)->mt[ttnov(o)]; + } + return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); +} + + +/* +** Return the name of the type of an object. For tables and userdata +** with metatable, use their '__name' metafield, if present. +*/ +const char *luaT_objtypename (lua_State *L, const TValue *o) { + Table *mt; + if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) || + (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) { + const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name")); + if (ttisstring(name)) /* is '__name' a string? */ + return getstr(tsvalue(name)); /* use it as type name */ } - return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject); + return ttypename(ttnov(o)); /* else use standard type name */ +} + + +void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, + const TValue *p2, TValue *p3, int hasres) { + ptrdiff_t result = savestack(L, p3); + StkId func = L->top; + setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ + setobj2s(L, func + 1, p1); /* 1st argument */ + setobj2s(L, func + 2, p2); /* 2nd argument */ + L->top += 3; + if (!hasres) /* no result? 'p3' is third argument */ + setobj2s(L, L->top++, p3); /* 3rd argument */ + /* metamethod may yield only when called from Lua code */ + if (isLua(L->ci)) + luaD_call(L, func, hasres); + else + luaD_callnoyield(L, func, hasres); + if (hasres) { /* if has result, move it to its place */ + p3 = restorestack(L, result); + setobjs2s(L, p3, --L->top); + } +} + + +int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ + if (ttisnil(tm)) + tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ + if (ttisnil(tm)) return 0; + luaT_callTM(L, tm, p1, p2, res, 1); + return 1; +} + + +void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, TMS event) { + if (!luaT_callbinTM(L, p1, p2, res, event)) { + switch (event) { + case TM_CONCAT: + luaG_concaterror(L, p1, p2); + /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ + case TM_BAND: case TM_BOR: case TM_BXOR: + case TM_SHL: case TM_SHR: case TM_BNOT: { + lua_Number dummy; + if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) + luaG_tointerror(L, p1, p2); + else + luaG_opinterror(L, p1, p2, "perform bitwise operation on"); + } + /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ + default: + luaG_opinterror(L, p1, p2, "perform arithmetic on"); + } + } +} + + +int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, + TMS event) { + if (!luaT_callbinTM(L, p1, p2, L->top, event)) + return -1; /* no metamethod */ + else + return !l_isfalse(L->top); } diff --git a/depends/lua/src/lua.c b/depends/lua/src/lua.c index 4345e554e..545d23d49 100644 --- a/depends/lua/src/lua.c +++ b/depends/lua/src/lua.c @@ -1,17 +1,19 @@ /* -** $Id: lua.c,v 1.206.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lua.c,v 1.226 2015/08/14 19:11:20 roberto Exp $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ +#define lua_c + +#include "lprefix.h" + #include #include #include #include -#define lua_c - #include "lua.h" #include "lauxlib.h" @@ -31,28 +33,38 @@ #define LUA_MAXINPUT 512 #endif -#if !defined(LUA_INIT) -#define LUA_INIT "LUA_INIT" +#if !defined(LUA_INIT_VAR) +#define LUA_INIT_VAR "LUA_INIT" #endif -#define LUA_INITVERSION \ - LUA_INIT "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR +#define LUA_INITVARVERSION \ + LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR /* ** lua_stdin_is_tty detects whether the standard input is a 'tty' (that ** is, whether we're running lua interactively). */ -#if defined(LUA_USE_ISATTY) +#if !defined(lua_stdin_is_tty) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + #include #define lua_stdin_is_tty() isatty(0) -#elif defined(LUA_WIN) + +#elif defined(LUA_USE_WINDOWS) /* }{ */ + #include -#include #define lua_stdin_is_tty() _isatty(_fileno(stdin)) -#else + +#else /* }{ */ + +/* ISO C definition */ #define lua_stdin_is_tty() 1 /* assume stdin is a tty */ -#endif + +#endif /* } */ + +#endif /* } */ /* @@ -61,26 +73,27 @@ ** lua_saveline defines how to "save" a read line in a "history". ** lua_freeline defines how to free a line read by lua_readline. */ -#if defined(LUA_USE_READLINE) +#if !defined(lua_readline) /* { */ + +#if defined(LUA_USE_READLINE) /* { */ -#include #include #include #define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) -#define lua_saveline(L,idx) \ - if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \ - add_history(lua_tostring(L, idx)); /* add it to history */ +#define lua_saveline(L,line) ((void)L, add_history(line)) #define lua_freeline(L,b) ((void)L, free(b)) -#elif !defined(lua_readline) +#else /* }{ */ #define lua_readline(L,b,p) \ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ -#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_saveline(L,line) { (void)L; (void)line; } #define lua_freeline(L,b) { (void)L; (void)b; } -#endif +#endif /* } */ + +#endif /* } */ @@ -90,33 +103,40 @@ static lua_State *globalL = NULL; static const char *progname = LUA_PROGNAME; - +/* +** Hook set by signal function to stop the interpreter. +*/ static void lstop (lua_State *L, lua_Debug *ar) { (void)ar; /* unused arg. */ - lua_sethook(L, NULL, 0, 0); + lua_sethook(L, NULL, 0, 0); /* reset hook */ luaL_error(L, "interrupted!"); } +/* +** Function to be called at a C signal. Because a C signal cannot +** just change a Lua state (as there is no proper synchronization), +** this function only sets a hook that, when called, will stop the +** interpreter. +*/ static void laction (int i) { - signal(i, SIG_DFL); /* if another SIGINT happens before lstop, - terminate process (default action) */ + signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */ lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } static void print_usage (const char *badoption) { - luai_writestringerror("%s: ", progname); + lua_writestringerror("%s: ", progname); if (badoption[1] == 'e' || badoption[1] == 'l') - luai_writestringerror("'%s' needs argument\n", badoption); + lua_writestringerror("'%s' needs argument\n", badoption); else - luai_writestringerror("unrecognized option '%s'\n", badoption); - luai_writestringerror( + lua_writestringerror("unrecognized option '%s'\n", badoption); + lua_writestringerror( "usage: %s [options] [script [args]]\n" "Available options are:\n" - " -e stat execute string " LUA_QL("stat") "\n" - " -i enter interactive mode after executing " LUA_QL("script") "\n" - " -l name require library " LUA_QL("name") "\n" + " -e stat execute string 'stat'\n" + " -i enter interactive mode after executing 'script'\n" + " -l name require library 'name'\n" " -v show version information\n" " -E ignore environment variables\n" " -- stop handling options\n" @@ -126,101 +146,114 @@ static void print_usage (const char *badoption) { } +/* +** Prints an error message, adding the program name in front of it +** (if present) +*/ static void l_message (const char *pname, const char *msg) { - if (pname) luai_writestringerror("%s: ", pname); - luai_writestringerror("%s\n", msg); + if (pname) lua_writestringerror("%s: ", pname); + lua_writestringerror("%s\n", msg); } +/* +** Check whether 'status' is not OK and, if so, prints the error +** message on the top of the stack. It assumes that the error object +** is a string, as it was either generated by Lua or by 'msghandler'. +*/ static int report (lua_State *L, int status) { - if (status != LUA_OK && !lua_isnil(L, -1)) { + if (status != LUA_OK) { const char *msg = lua_tostring(L, -1); - if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); - lua_pop(L, 1); - /* force a complete garbage collection in case of errors */ - lua_gc(L, LUA_GCCOLLECT, 0); + lua_pop(L, 1); /* remove message */ } return status; } -/* the next function is called unprotected, so it must avoid errors */ -static void finalreport (lua_State *L, int status) { - if (status != LUA_OK) { - const char *msg = (lua_type(L, -1) == LUA_TSTRING) ? lua_tostring(L, -1) - : NULL; - if (msg == NULL) msg = "(error object is not a string)"; - l_message(progname, msg); - lua_pop(L, 1); - } -} - - -static int traceback (lua_State *L) { +/* +** Message handler used to run all chunks +*/ +static int msghandler (lua_State *L) { const char *msg = lua_tostring(L, 1); - if (msg) - luaL_traceback(L, L, msg, 1); - else if (!lua_isnoneornil(L, 1)) { /* is there an error object? */ - if (!luaL_callmeta(L, 1, "__tostring")) /* try its 'tostring' metamethod */ - lua_pushliteral(L, "(no error message)"); + if (msg == NULL) { /* is error object not a string? */ + if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ + lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ + return 1; /* that is the message */ + else + msg = lua_pushfstring(L, "(error object is a %s value)", + luaL_typename(L, 1)); } - return 1; + luaL_traceback(L, L, msg, 1); /* append a standard traceback */ + return 1; /* return the traceback */ } +/* +** Interface to 'lua_pcall', which sets appropriate message function +** and C-signal handler. Used to run all chunks. +*/ static int docall (lua_State *L, int narg, int nres) { int status; int base = lua_gettop(L) - narg; /* function index */ - lua_pushcfunction(L, traceback); /* push traceback function */ - lua_insert(L, base); /* put it under chunk and args */ + lua_pushcfunction(L, msghandler); /* push message handler */ + lua_insert(L, base); /* put it under function and args */ globalL = L; /* to be available to 'laction' */ - signal(SIGINT, laction); + signal(SIGINT, laction); /* set C-signal handler */ status = lua_pcall(L, narg, nres, base); - signal(SIGINT, SIG_DFL); - lua_remove(L, base); /* remove traceback function */ + signal(SIGINT, SIG_DFL); /* reset C-signal handler */ + lua_remove(L, base); /* remove message handler from the stack */ return status; } static void print_version (void) { - luai_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); - luai_writeline(); + lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); + lua_writeline(); } -static int getargs (lua_State *L, char **argv, int n) { - int narg; - int i; - int argc = 0; - while (argv[argc]) argc++; /* count total number of arguments */ - narg = argc - (n + 1); /* number of arguments to the script */ - luaL_checkstack(L, narg + 3, "too many arguments to script"); - for (i=n+1; i < argc; i++) - lua_pushstring(L, argv[i]); - lua_createtable(L, narg, n + 1); - for (i=0; i < argc; i++) { +/* +** Create the 'arg' table, which stores all arguments from the +** command line ('argv'). It should be aligned so that, at index 0, +** it has 'argv[script]', which is the script name. The arguments +** to the script (everything after 'script') go to positive indices; +** other arguments (before the script name) go to negative indices. +** If there is no script name, assume interpreter's name as base. +*/ +static void createargtable (lua_State *L, char **argv, int argc, int script) { + int i, narg; + if (script == argc) script = 0; /* no script name? */ + narg = argc - (script + 1); /* number of positive indices */ + lua_createtable(L, narg, script + 1); + for (i = 0; i < argc; i++) { lua_pushstring(L, argv[i]); - lua_rawseti(L, -2, i - n); + lua_rawseti(L, -2, i - script); } - return narg; + lua_setglobal(L, "arg"); } -static int dofile (lua_State *L, const char *name) { - int status = luaL_loadfile(L, name); +static int dochunk (lua_State *L, int status) { if (status == LUA_OK) status = docall(L, 0, 0); return report(L, status); } +static int dofile (lua_State *L, const char *name) { + return dochunk(L, luaL_loadfile(L, name)); +} + + static int dostring (lua_State *L, const char *s, const char *name) { - int status = luaL_loadbuffer(L, s, strlen(s), name); - if (status == LUA_OK) status = docall(L, 0, 0); - return report(L, status); + return dochunk(L, luaL_loadbuffer(L, s, strlen(s), name)); } +/* +** Calls 'require(name)' and stores the result in a global variable +** with the given name. +*/ static int dolibrary (lua_State *L, const char *name) { int status; lua_getglobal(L, "require"); @@ -232,6 +265,9 @@ static int dolibrary (lua_State *L, const char *name) { } +/* +** Returns the string to be used as a prompt by the interpreter. +*/ static const char *get_prompt (lua_State *L, int firstline) { const char *p; lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); @@ -244,6 +280,12 @@ static const char *get_prompt (lua_State *L, int firstline) { #define EOFMARK "" #define marklen (sizeof(EOFMARK)/sizeof(char) - 1) + +/* +** Check whether 'status' signals a syntax error and the error +** message at the top of the stack ends with the above mark for +** incomplete statements. +*/ static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; @@ -257,163 +299,230 @@ static int incomplete (lua_State *L, int status) { } +/* +** Prompt the user, read a line, and push it into the Lua stack. +*/ static int pushline (lua_State *L, int firstline) { char buffer[LUA_MAXINPUT]; char *b = buffer; size_t l; const char *prmt = get_prompt(L, firstline); 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 (prompt will be popped by caller) */ + lua_pop(L, 1); /* remove prompt */ l = strlen(b); if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ - b[l-1] = '\0'; /* remove it */ - if (firstline && b[0] == '=') /* first line starts with `=' ? */ - lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ + b[--l] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */ + lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */ else - lua_pushstring(L, b); + lua_pushlstring(L, b, l); lua_freeline(L, b); return 1; } +/* +** Try to compile line on the stack as 'return ;'; on return, stack +** has either compiled chunk or original line (if compilation failed). +*/ +static int addreturn (lua_State *L) { + const char *line = lua_tostring(L, -1); /* original line */ + const char *retline = lua_pushfstring(L, "return %s;", line); + int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin"); + if (status == LUA_OK) { + lua_remove(L, -2); /* remove modified line */ + if (line[0] != '\0') /* non empty? */ + lua_saveline(L, line); /* keep history */ + } + else + lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */ + return status; +} + + +/* +** Read multiple lines until a complete Lua statement +*/ +static int multiline (lua_State *L) { + for (;;) { /* repeat until gets a complete statement */ + size_t len; + const char *line = lua_tolstring(L, 1, &len); /* get what it has */ + int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ + if (!incomplete(L, status) || !pushline(L, 0)) { + lua_saveline(L, line); /* keep history */ + return status; /* cannot or should not try to add continuation line */ + } + lua_pushliteral(L, "\n"); /* add newline... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } +} + + +/* +** Read a line and try to load (compile) it first as an expression (by +** adding "return " in front of it) and second as a statement. Return +** the final status of load/call with the resulting function (if any) +** in the top of the stack. +*/ static int loadline (lua_State *L) { int status; lua_settop(L, 0); if (!pushline(L, 1)) return -1; /* no input */ - for (;;) { /* repeat until gets a complete line */ - size_t l; - const char *line = lua_tolstring(L, 1, &l); - status = luaL_loadbuffer(L, line, l, "=stdin"); - if (!incomplete(L, status)) break; /* cannot try to add lines? */ - if (!pushline(L, 0)) /* no more input? */ - return -1; - lua_pushliteral(L, "\n"); /* add a new line... */ - lua_insert(L, -2); /* ...between the two lines */ - lua_concat(L, 3); /* join them */ - } - lua_saveline(L, 1); - lua_remove(L, 1); /* remove line */ + if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */ + status = multiline(L); /* try as command, maybe with continuation lines */ + lua_remove(L, 1); /* remove line from the stack */ + lua_assert(lua_gettop(L) == 1); return status; } -static void dotty (lua_State *L) { +/* +** Prints (calling the Lua 'print' function) any values on the stack +*/ +static void l_print (lua_State *L) { + int n = lua_gettop(L); + if (n > 0) { /* any result to be printed? */ + luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, n, 0, 0) != LUA_OK) + l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)", + lua_tostring(L, -1))); + } +} + + +/* +** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and +** print any results. +*/ +static void doREPL (lua_State *L) { int status; const char *oldprogname = progname; - progname = NULL; + progname = NULL; /* no 'progname' on errors in interactive mode */ while ((status = loadline(L)) != -1) { - if (status == LUA_OK) status = docall(L, 0, LUA_MULTRET); - report(L, status); - if (status == LUA_OK && lua_gettop(L) > 0) { /* any result to print? */ - luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); - lua_getglobal(L, "print"); - lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != LUA_OK) - l_message(progname, lua_pushfstring(L, - "error calling " LUA_QL("print") " (%s)", - lua_tostring(L, -1))); - } + if (status == LUA_OK) + status = docall(L, 0, LUA_MULTRET); + if (status == LUA_OK) l_print(L); + else report(L, status); } lua_settop(L, 0); /* clear stack */ - luai_writeline(); + lua_writeline(); progname = oldprogname; } -static int handle_script (lua_State *L, char **argv, int n) { +/* +** Push on the stack the contents of table 'arg' from 1 to #arg +*/ +static int pushargs (lua_State *L) { + int i, n; + if (lua_getglobal(L, "arg") != LUA_TTABLE) + luaL_error(L, "'arg' is not a table"); + n = (int)luaL_len(L, -1); + luaL_checkstack(L, n + 3, "too many arguments to script"); + for (i = 1; i <= n; i++) + lua_rawgeti(L, -i, i); + lua_remove(L, -i); /* remove table from the stack */ + return n; +} + + +static int handle_script (lua_State *L, char **argv) { int status; - const char *fname; - int narg = getargs(L, argv, n); /* collect arguments */ - lua_setglobal(L, "arg"); - fname = argv[n]; - if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) + const char *fname = argv[0]; + if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0) fname = NULL; /* stdin */ status = luaL_loadfile(L, fname); - lua_insert(L, -(narg+1)); - if (status == LUA_OK) - status = docall(L, narg, LUA_MULTRET); - else - lua_pop(L, narg); + if (status == LUA_OK) { + int n = pushargs(L); /* push arguments to script */ + status = docall(L, n, LUA_MULTRET); + } return report(L, status); } -/* check that argument has no extra characters at the end */ -#define noextrachars(x) {if ((x)[2] != '\0') return -1;} - - -/* indices of various argument indicators in array args */ -#define has_i 0 /* -i */ -#define has_v 1 /* -v */ -#define has_e 2 /* -e */ -#define has_E 3 /* -E */ - -#define num_has 4 /* number of 'has_*' */ +/* bits of various argument indicators in 'args' */ +#define has_error 1 /* bad option */ +#define has_i 2 /* -i */ +#define has_v 4 /* -v */ +#define has_e 8 /* -e */ +#define has_E 16 /* -E */ -static int collectargs (char **argv, int *args) { +/* +** Traverses all arguments from 'argv', returning a mask with those +** needed before running any Lua code (or an error code if it finds +** any invalid argument). 'first' returns the first not-handled argument +** (either the script name or a bad argument in case of error). +*/ +static int collectargs (char **argv, int *first) { + int args = 0; int i; for (i = 1; argv[i] != NULL; i++) { + *first = i; if (argv[i][0] != '-') /* not an option? */ - return i; - switch (argv[i][1]) { /* option */ - case '-': - noextrachars(argv[i]); - return (argv[i+1] != NULL ? i+1 : 0); - case '\0': - return i; + return args; /* stop handling options */ + switch (argv[i][1]) { /* else check option */ + case '-': /* '--' */ + if (argv[i][2] != '\0') /* extra characters after '--'? */ + return has_error; /* invalid option */ + *first = i + 1; + return args; + case '\0': /* '-' */ + return args; /* script "name" is '-' */ case 'E': - args[has_E] = 1; + if (argv[i][2] != '\0') /* extra characters after 1st? */ + return has_error; /* invalid option */ + args |= has_E; break; case 'i': - noextrachars(argv[i]); - args[has_i] = 1; /* go through */ + args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */ case 'v': - noextrachars(argv[i]); - args[has_v] = 1; + if (argv[i][2] != '\0') /* extra characters after 1st? */ + return has_error; /* invalid option */ + args |= has_v; break; case 'e': - args[has_e] = 1; /* go through */ + args |= has_e; /* FALLTHROUGH */ case 'l': /* both options need an argument */ if (argv[i][2] == '\0') { /* no concatenated argument? */ i++; /* try next 'argv' */ if (argv[i] == NULL || argv[i][0] == '-') - return -(i - 1); /* no next argument or it is another option */ + return has_error; /* no next argument or it is another option */ } break; - default: /* invalid option; return its index... */ - return -i; /* ...as a negative value */ + default: /* invalid option */ + return has_error; } } - return 0; + *first = i; /* no script name */ + return args; } +/* +** Processes options 'e' and 'l', which involve running Lua code. +** Returns 0 if some code raises an error. +*/ static int runargs (lua_State *L, char **argv, int n) { int i; for (i = 1; i < n; i++) { - lua_assert(argv[i][0] == '-'); - switch (argv[i][1]) { /* option */ - case 'e': { - const char *chunk = argv[i] + 2; - if (*chunk == '\0') chunk = argv[++i]; - lua_assert(chunk != NULL); - if (dostring(L, chunk, "=(command line)") != LUA_OK) - return 0; - break; - } - case 'l': { - const char *filename = argv[i] + 2; - if (*filename == '\0') filename = argv[++i]; - lua_assert(filename != NULL); - if (dolibrary(L, filename) != LUA_OK) - return 0; /* stop if file fails */ - break; - } - default: break; + int option = argv[i][1]; + lua_assert(argv[i][0] == '-'); /* already checked */ + if (option == 'e' || option == 'l') { + int status; + const char *extra = argv[i] + 2; /* both options need an argument */ + if (*extra == '\0') extra = argv[++i]; + lua_assert(extra != NULL); + status = (option == 'e') + ? dostring(L, extra, "=(command line)") + : dolibrary(L, extra); + if (status != LUA_OK) return 0; } } return 1; @@ -421,10 +530,10 @@ static int runargs (lua_State *L, char **argv, int n) { static int handle_luainit (lua_State *L) { - const char *name = "=" LUA_INITVERSION; + const char *name = "=" LUA_INITVARVERSION; const char *init = getenv(name + 1); if (init == NULL) { - name = "=" LUA_INIT; + name = "=" LUA_INIT_VAR; init = getenv(name + 1); /* try alternative name */ } if (init == NULL) return LUA_OK; @@ -435,40 +544,44 @@ static int handle_luainit (lua_State *L) { } +/* +** Main body of stand-alone interpreter (to be called in protected mode). +** Reads the options and handles them all. +*/ static int pmain (lua_State *L) { int argc = (int)lua_tointeger(L, 1); char **argv = (char **)lua_touserdata(L, 2); int script; - int args[num_has]; - args[has_i] = args[has_v] = args[has_e] = args[has_E] = 0; + int args = collectargs(argv, &script); + luaL_checkversion(L); /* check that interpreter has correct version */ if (argv[0] && argv[0][0]) progname = argv[0]; - script = collectargs(argv, args); - if (script < 0) { /* invalid arg? */ - print_usage(argv[-script]); + if (args == has_error) { /* bad arg? */ + print_usage(argv[script]); /* 'script' has index of bad arg. */ return 0; } - if (args[has_v]) print_version(); - if (args[has_E]) { /* option '-E'? */ + if (args & has_v) /* option '-v'? */ + print_version(); + if (args & has_E) { /* option '-E'? */ lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); } - /* open standard libraries */ - luaL_checkversion(L); - lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */ - luaL_openlibs(L); /* open libraries */ - lua_gc(L, LUA_GCRESTART, 0); - if (!args[has_E] && handle_luainit(L) != LUA_OK) - return 0; /* error running LUA_INIT */ - /* execute arguments -e and -l */ - if (!runargs(L, argv, (script > 0) ? script : argc)) return 0; - /* execute main script (if there is one) */ - if (script && handle_script(L, argv, script) != LUA_OK) return 0; - if (args[has_i]) /* -i option? */ - dotty(L); - else if (script == 0 && !args[has_e] && !args[has_v]) { /* no arguments? */ - if (lua_stdin_is_tty()) { + luaL_openlibs(L); /* open standard libraries */ + createargtable(L, argv, argc, script); /* create table 'arg' */ + if (!(args & has_E)) { /* no option '-E'? */ + if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ + return 0; /* error running LUA_INIT */ + } + if (!runargs(L, argv, script)) /* execute arguments -e and -l */ + return 0; /* something failed */ + if (script < argc && /* execute main script (if there is one) */ + handle_script(L, argv + script) != LUA_OK) + return 0; + if (args & has_i) /* -i option? */ + doREPL(L); /* do read-eval-print loop */ + else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */ + if (lua_stdin_is_tty()) { /* running in interactive mode? */ print_version(); - dotty(L); + doREPL(L); /* do read-eval-print loop */ } else dofile(L, NULL); /* executes stdin as a file */ } @@ -484,13 +597,12 @@ int main (int argc, char **argv) { l_message(argv[0], "cannot create state: not enough memory"); return EXIT_FAILURE; } - /* call 'pmain' in protected mode */ - lua_pushcfunction(L, &pmain); + lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ lua_pushinteger(L, argc); /* 1st argument */ lua_pushlightuserdata(L, argv); /* 2nd argument */ - status = lua_pcall(L, 2, 1, 0); + status = lua_pcall(L, 2, 1, 0); /* do the call */ result = lua_toboolean(L, -1); /* get result */ - finalreport(L, status); + report(L, status); lua_close(L); return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/depends/lua/src/luac.c b/depends/lua/src/luac.c index 7409706ec..c0c91d017 100644 --- a/depends/lua/src/luac.c +++ b/depends/lua/src/luac.c @@ -1,17 +1,20 @@ /* -** $Id: luac.c,v 1.69 2011/11/29 17:46:33 lhf Exp $ -** Lua compiler (saves bytecodes to files; also list bytecodes) +** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $ +** Lua compiler (saves bytecodes to files; also lists bytecodes) ** See Copyright Notice in lua.h */ +#define luac_c +#define LUA_CORE + +#include "lprefix.h" + +#include #include #include #include #include -#define luac_c -#define LUA_CORE - #include "lua.h" #include "lauxlib.h" @@ -47,14 +50,14 @@ static void cannot(const char* what) static void usage(const char* message) { if (*message=='-') - fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message); + fprintf(stderr,"%s: unrecognized option '%s'\n",progname,message); else fprintf(stderr,"%s: %s\n",progname,message); fprintf(stderr, "usage: %s [options] [filenames]\n" "Available options are:\n" " -l list (use -l -l for full listing)\n" - " -o name output to file " LUA_QL("name") " (default is \"%s\")\n" + " -o name output to file 'name' (default is \"%s\")\n" " -p parse only\n" " -s strip debug information\n" " -v show version information\n" @@ -89,7 +92,7 @@ static int doargs(int argc, char* argv[]) { output=argv[++i]; if (output==NULL || *output==0 || (*output=='-' && output[1]!=0)) - usage(LUA_QL("-o") " needs argument"); + usage("'-o' needs argument"); if (IS("-")) output=NULL; } else if (IS("-p")) /* parse only */ @@ -203,7 +206,7 @@ int main(int argc, char* argv[]) } /* -** $Id: print.c,v 1.69 2013/07/04 01:03:46 lhf Exp $ +** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $ ** print bytecodes ** See Copyright Notice in lua.h */ @@ -223,7 +226,7 @@ int main(int argc, char* argv[]) static void PrintString(const TString* ts) { const char* s=getstr(ts); - size_t i,n=ts->tsv.len; + size_t i,n=tsslen(ts); printf("%c",'"'); for (i=0; ik[i]; - switch (ttypenv(o)) + switch (ttype(o)) { case LUA_TNIL: printf("nil"); @@ -259,11 +262,19 @@ static void PrintConstant(const Proto* f, int i) case LUA_TBOOLEAN: printf(bvalue(o) ? "true" : "false"); break; - case LUA_TNUMBER: - printf(LUA_NUMBER_FMT,nvalue(o)); + case LUA_TNUMFLT: + { + char buff[100]; + sprintf(buff,LUA_NUMBER_FMT,fltvalue(o)); + printf("%s",buff); + if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0"); + break; + } + case LUA_TNUMINT: + printf(LUA_INTEGER_FMT,ivalue(o)); break; - case LUA_TSTRING: - PrintString(rawtsvalue(o)); + case LUA_TSHRSTR: case LUA_TLNGSTR: + PrintString(tsvalue(o)); break; default: /* cannot happen */ printf("? type=%d",ttype(o)); @@ -337,8 +348,14 @@ static void PrintCode(const Proto* f) case OP_ADD: case OP_SUB: case OP_MUL: - case OP_DIV: case OP_POW: + case OP_DIV: + case OP_IDIV: + case OP_BAND: + case OP_BOR: + case OP_BXOR: + case OP_SHL: + case OP_SHR: case OP_EQ: case OP_LT: case OP_LE: diff --git a/depends/lua/src/lundump.c b/depends/lua/src/lundump.c index 4163cb5d3..4080af9c0 100644 --- a/depends/lua/src/lundump.c +++ b/depends/lua/src/lundump.c @@ -1,14 +1,17 @@ /* -** $Id: lundump.c,v 2.22.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ -#include - #define lundump_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "ldebug.h" @@ -20,239 +23,257 @@ #include "lundump.h" #include "lzio.h" + +#if !defined(luai_verifycode) +#define luai_verifycode(L,b,f) /* empty */ +#endif + + typedef struct { - lua_State* L; - ZIO* Z; - Mbuffer* b; - const char* name; + lua_State *L; + ZIO *Z; + const char *name; } LoadState; -static l_noret error(LoadState* S, const char* why) -{ - luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why); - luaD_throw(S->L,LUA_ERRSYNTAX); + +static l_noret error(LoadState *S, const char *why) { + luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why); + luaD_throw(S->L, LUA_ERRSYNTAX); } -#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size)) -#define LoadByte(S) (lu_byte)LoadChar(S) -#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x)) -#define LoadVector(S,b,n,size) LoadMem(S,b,n,size) -#if !defined(luai_verifycode) -#define luai_verifycode(L,b,f) /* empty */ -#endif +/* +** All high-level loads go through LoadVector; you can change it to +** adapt to the endianness of the input +*/ +#define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0])) -static void LoadBlock(LoadState* S, void* b, size_t size) -{ - if (luaZ_read(S->Z,b,size)!=0) error(S,"truncated"); +static void LoadBlock (LoadState *S, void *b, size_t size) { + if (luaZ_read(S->Z, b, size) != 0) + error(S, "truncated"); } -static int LoadChar(LoadState* S) -{ - char x; - LoadVar(S,x); - return x; + +#define LoadVar(S,x) LoadVector(S,&x,1) + + +static lu_byte LoadByte (LoadState *S) { + lu_byte x; + LoadVar(S, x); + return x; } -static int LoadInt(LoadState* S) -{ - int x; - LoadVar(S,x); - if (x<0) error(S,"corrupted"); - return x; + +static int LoadInt (LoadState *S) { + int x; + LoadVar(S, x); + return x; } -static lua_Number LoadNumber(LoadState* S) -{ - lua_Number x; - LoadVar(S,x); - return x; + +static lua_Number LoadNumber (LoadState *S) { + lua_Number x; + LoadVar(S, x); + return x; } -static TString* LoadString(LoadState* S) -{ - size_t size; - LoadVar(S,size); - if (size==0) - return NULL; - else - { - char* s=luaZ_openspace(S->L,S->b,size); - LoadBlock(S,s,size*sizeof(char)); - return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */ - } + +static lua_Integer LoadInteger (LoadState *S) { + lua_Integer x; + LoadVar(S, x); + return x; } -static void LoadCode(LoadState* S, Proto* f) -{ - int n=LoadInt(S); - f->code=luaM_newvector(S->L,n,Instruction); - f->sizecode=n; - LoadVector(S,f->code,n,sizeof(Instruction)); + +static TString *LoadString (LoadState *S) { + size_t size = LoadByte(S); + if (size == 0xFF) + LoadVar(S, size); + if (size == 0) + return NULL; + else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ + char buff[LUAI_MAXSHORTLEN]; + LoadVector(S, buff, size); + return luaS_newlstr(S->L, buff, size); + } + else { /* long string */ + TString *ts = luaS_createlngstrobj(S->L, size); + LoadVector(S, getstr(ts), size); /* load directly in final place */ + return ts; + } } -static void LoadFunction(LoadState* S, Proto* f); - -static void LoadConstants(LoadState* S, Proto* f) -{ - int i,n; - n=LoadInt(S); - f->k=luaM_newvector(S->L,n,TValue); - f->sizek=n; - for (i=0; ik[i]); - for (i=0; ik[i]; - int t=LoadChar(S); - switch (t) - { - case LUA_TNIL: - setnilvalue(o); - break; - case LUA_TBOOLEAN: - setbvalue(o,LoadChar(S)); - break; - case LUA_TNUMBER: - setnvalue(o,LoadNumber(S)); - break; - case LUA_TSTRING: - setsvalue2n(S->L,o,LoadString(S)); - break; - default: lua_assert(0); + +static void LoadCode (LoadState *S, Proto *f) { + int n = LoadInt(S); + f->code = luaM_newvector(S->L, n, Instruction); + f->sizecode = n; + LoadVector(S, f->code, n); +} + + +static void LoadFunction(LoadState *S, Proto *f, TString *psource); + + +static void LoadConstants (LoadState *S, Proto *f) { + int i; + int n = LoadInt(S); + f->k = luaM_newvector(S->L, n, TValue); + f->sizek = n; + for (i = 0; i < n; i++) + setnilvalue(&f->k[i]); + for (i = 0; i < n; i++) { + TValue *o = &f->k[i]; + int t = LoadByte(S); + switch (t) { + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o, LoadByte(S)); + break; + case LUA_TNUMFLT: + setfltvalue(o, LoadNumber(S)); + break; + case LUA_TNUMINT: + setivalue(o, LoadInteger(S)); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + setsvalue2n(S->L, o, LoadString(S)); + break; + default: + lua_assert(0); + } } - } - n=LoadInt(S); - f->p=luaM_newvector(S->L,n,Proto*); - f->sizep=n; - for (i=0; ip[i]=NULL; - for (i=0; ip[i]=luaF_newproto(S->L); - LoadFunction(S,f->p[i]); - } } -static void LoadUpvalues(LoadState* S, Proto* f) -{ - int i,n; - n=LoadInt(S); - f->upvalues=luaM_newvector(S->L,n,Upvaldesc); - f->sizeupvalues=n; - for (i=0; iupvalues[i].name=NULL; - for (i=0; iupvalues[i].instack=LoadByte(S); - f->upvalues[i].idx=LoadByte(S); - } + +static void LoadProtos (LoadState *S, Proto *f) { + int i; + int n = LoadInt(S); + f->p = luaM_newvector(S->L, n, Proto *); + f->sizep = n; + for (i = 0; i < n; i++) + f->p[i] = NULL; + for (i = 0; i < n; i++) { + f->p[i] = luaF_newproto(S->L); + LoadFunction(S, f->p[i], f->source); + } } -static void LoadDebug(LoadState* S, Proto* f) -{ - int i,n; - f->source=LoadString(S); - n=LoadInt(S); - f->lineinfo=luaM_newvector(S->L,n,int); - f->sizelineinfo=n; - LoadVector(S,f->lineinfo,n,sizeof(int)); - n=LoadInt(S); - f->locvars=luaM_newvector(S->L,n,LocVar); - f->sizelocvars=n; - for (i=0; ilocvars[i].varname=NULL; - for (i=0; ilocvars[i].varname=LoadString(S); - f->locvars[i].startpc=LoadInt(S); - f->locvars[i].endpc=LoadInt(S); - } - n=LoadInt(S); - for (i=0; iupvalues[i].name=LoadString(S); + +static void LoadUpvalues (LoadState *S, Proto *f) { + int i, n; + n = LoadInt(S); + f->upvalues = luaM_newvector(S->L, n, Upvaldesc); + f->sizeupvalues = n; + for (i = 0; i < n; i++) + f->upvalues[i].name = NULL; + for (i = 0; i < n; i++) { + f->upvalues[i].instack = LoadByte(S); + f->upvalues[i].idx = LoadByte(S); + } } -static void LoadFunction(LoadState* S, Proto* f) -{ - f->linedefined=LoadInt(S); - f->lastlinedefined=LoadInt(S); - f->numparams=LoadByte(S); - f->is_vararg=LoadByte(S); - f->maxstacksize=LoadByte(S); - LoadCode(S,f); - LoadConstants(S,f); - LoadUpvalues(S,f); - LoadDebug(S,f); + +static void LoadDebug (LoadState *S, Proto *f) { + int i, n; + n = LoadInt(S); + f->lineinfo = luaM_newvector(S->L, n, int); + f->sizelineinfo = n; + LoadVector(S, f->lineinfo, n); + n = LoadInt(S); + f->locvars = luaM_newvector(S->L, n, LocVar); + f->sizelocvars = n; + for (i = 0; i < n; i++) + f->locvars[i].varname = NULL; + for (i = 0; i < n; i++) { + f->locvars[i].varname = LoadString(S); + f->locvars[i].startpc = LoadInt(S); + f->locvars[i].endpc = LoadInt(S); + } + n = LoadInt(S); + for (i = 0; i < n; i++) + f->upvalues[i].name = LoadString(S); } -/* the code below must be consistent with the code in luaU_header */ -#define N0 LUAC_HEADERSIZE -#define N1 (sizeof(LUA_SIGNATURE)-sizeof(char)) -#define N2 N1+2 -#define N3 N2+6 - -static void LoadHeader(LoadState* S) -{ - lu_byte h[LUAC_HEADERSIZE]; - lu_byte s[LUAC_HEADERSIZE]; - luaU_header(h); - memcpy(s,h,sizeof(char)); /* first char already read */ - LoadBlock(S,s+sizeof(char),LUAC_HEADERSIZE-sizeof(char)); - if (memcmp(h,s,N0)==0) return; - if (memcmp(h,s,N1)!=0) error(S,"not a"); - if (memcmp(h,s,N2)!=0) error(S,"version mismatch in"); - if (memcmp(h,s,N3)!=0) error(S,"incompatible"); else error(S,"corrupted"); + +static void LoadFunction (LoadState *S, Proto *f, TString *psource) { + f->source = LoadString(S); + if (f->source == NULL) /* no source in dump? */ + f->source = psource; /* reuse parent's source */ + f->linedefined = LoadInt(S); + f->lastlinedefined = LoadInt(S); + f->numparams = LoadByte(S); + f->is_vararg = LoadByte(S); + f->maxstacksize = LoadByte(S); + LoadCode(S, f); + LoadConstants(S, f); + LoadUpvalues(S, f); + LoadProtos(S, f); + LoadDebug(S, f); } -/* -** load precompiled chunk -*/ -Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) -{ - LoadState S; - Closure* cl; - if (*name=='@' || *name=='=') - S.name=name+1; - else if (*name==LUA_SIGNATURE[0]) - S.name="binary string"; - else - S.name=name; - S.L=L; - S.Z=Z; - S.b=buff; - LoadHeader(&S); - cl=luaF_newLclosure(L,1); - setclLvalue(L,L->top,cl); incr_top(L); - cl->l.p=luaF_newproto(L); - LoadFunction(&S,cl->l.p); - if (cl->l.p->sizeupvalues != 1) - { - Proto* p=cl->l.p; - cl=luaF_newLclosure(L,cl->l.p->sizeupvalues); - cl->l.p=p; - setclLvalue(L,L->top-1,cl); - } - luai_verifycode(L,buff,cl->l.p); - return cl; + +static void checkliteral (LoadState *S, const char *s, const char *msg) { + char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ + size_t len = strlen(s); + LoadVector(S, buff, len); + if (memcmp(s, buff, len) != 0) + error(S, msg); +} + + +static void fchecksize (LoadState *S, size_t size, const char *tname) { + if (LoadByte(S) != size) + error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname)); +} + + +#define checksize(S,t) fchecksize(S,sizeof(t),#t) + +static void checkHeader (LoadState *S) { + checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */ + if (LoadByte(S) != LUAC_VERSION) + error(S, "version mismatch in"); + if (LoadByte(S) != LUAC_FORMAT) + error(S, "format mismatch in"); + checkliteral(S, LUAC_DATA, "corrupted"); + checksize(S, int); + checksize(S, size_t); + checksize(S, Instruction); + checksize(S, lua_Integer); + checksize(S, lua_Number); + if (LoadInteger(S) != LUAC_INT) + error(S, "endianness mismatch in"); + if (LoadNumber(S) != LUAC_NUM) + error(S, "float format mismatch in"); } -#define MYINT(s) (s[0]-'0') -#define VERSION MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR) -#define FORMAT 0 /* this is the official format */ /* -* make header for precompiled chunks -* if you change the code below be sure to update LoadHeader and FORMAT above -* and LUAC_HEADERSIZE in lundump.h +** load precompiled chunk */ -void luaU_header (lu_byte* h) -{ - int x=1; - memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-sizeof(char)); - h+=sizeof(LUA_SIGNATURE)-sizeof(char); - *h++=cast_byte(VERSION); - *h++=cast_byte(FORMAT); - *h++=cast_byte(*(char*)&x); /* endianness */ - *h++=cast_byte(sizeof(int)); - *h++=cast_byte(sizeof(size_t)); - *h++=cast_byte(sizeof(Instruction)); - *h++=cast_byte(sizeof(lua_Number)); - *h++=cast_byte(((lua_Number)0.5)==0); /* is lua_Number integral? */ - memcpy(h,LUAC_TAIL,sizeof(LUAC_TAIL)-sizeof(char)); +LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { + LoadState S; + LClosure *cl; + if (*name == '@' || *name == '=') + S.name = name + 1; + else if (*name == LUA_SIGNATURE[0]) + S.name = "binary string"; + else + S.name = name; + S.L = L; + S.Z = Z; + checkHeader(&S); + cl = luaF_newLclosure(L, LoadByte(&S)); + setclLvalue(L, L->top, cl); + luaD_inctop(L); + cl->p = luaF_newproto(L); + LoadFunction(&S, cl->p, NULL); + lua_assert(cl->nupvalues == cl->p->sizeupvalues); + luai_verifycode(L, buff, cl->p); + return cl; } + diff --git a/depends/lua/src/lutf8lib.c b/depends/lua/src/lutf8lib.c new file mode 100644 index 000000000..9042582d1 --- /dev/null +++ b/depends/lua/src/lutf8lib.c @@ -0,0 +1,256 @@ +/* +** $Id: lutf8lib.c,v 1.15 2015/03/28 19:16:55 roberto Exp $ +** Standard library for UTF-8 manipulation +** See Copyright Notice in lua.h +*/ + +#define lutf8lib_c +#define LUA_LIB + +#include "lprefix.h" + + +#include +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + +#define MAXUNICODE 0x10FFFF + +#define iscont(p) ((*(p) & 0xC0) == 0x80) + + +/* from strlib */ +/* translate a relative string position: negative means back from end */ +static lua_Integer u_posrelat (lua_Integer pos, size_t len) { + if (pos >= 0) return pos; + else if (0u - (size_t)pos > len) return 0; + else return (lua_Integer)len + pos + 1; +} + + +/* +** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. +*/ +static const char *utf8_decode (const char *o, int *val) { + static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; + const unsigned char *s = (const unsigned char *)o; + unsigned int c = s[0]; + unsigned int res = 0; /* final result */ + if (c < 0x80) /* ascii? */ + res = c; + else { + int count = 0; /* to count number of continuation bytes */ + while (c & 0x40) { /* still have continuation bytes? */ + int cc = s[++count]; /* read next byte */ + if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ + return NULL; /* invalid byte sequence */ + res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ + c <<= 1; /* to test next bit */ + } + res |= ((c & 0x7F) << (count * 5)); /* add first byte */ + if (count > 3 || res > MAXUNICODE || res <= limits[count]) + return NULL; /* invalid byte sequence */ + s += count; /* skip continuation bytes read */ + } + if (val) *val = res; + return (const char *)s + 1; /* +1 to include first byte */ +} + + +/* +** utf8len(s [, i [, j]]) --> number of characters that start in the +** range [i,j], or nil + current position if 's' is not well formed in +** that interval +*/ +static int utflen (lua_State *L) { + int n = 0; + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, + "initial position out of string"); + luaL_argcheck(L, --posj < (lua_Integer)len, 3, + "final position out of string"); + while (posi <= posj) { + const char *s1 = utf8_decode(s + posi, NULL); + if (s1 == NULL) { /* conversion error? */ + lua_pushnil(L); /* return nil ... */ + lua_pushinteger(L, posi + 1); /* ... and current position */ + return 2; + } + posi = s1 - s; + n++; + } + lua_pushinteger(L, n); + return 1; +} + + +/* +** codepoint(s, [i, [j]]) -> returns codepoints for all characters +** that start in the range [i,j] +*/ +static int codepoint (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); + lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); + int n; + const char *se; + luaL_argcheck(L, posi >= 1, 2, "out of range"); + luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); + if (posi > pose) return 0; /* empty interval; return no values */ + if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ + return luaL_error(L, "string slice too long"); + n = (int)(pose - posi) + 1; + luaL_checkstack(L, n, "string slice too long"); + n = 0; + se = s + pose; + for (s += posi - 1; s < se;) { + int code; + s = utf8_decode(s, &code); + if (s == NULL) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, code); + n++; + } + return n; +} + + +static void pushutfchar (lua_State *L, int arg) { + lua_Integer code = luaL_checkinteger(L, arg); + luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); + lua_pushfstring(L, "%U", (long)code); +} + + +/* +** utfchar(n1, n2, ...) -> char(n1)..char(n2)... +*/ +static int utfchar (lua_State *L) { + int n = lua_gettop(L); /* number of arguments */ + if (n == 1) /* optimize common case of single char */ + pushutfchar(L, 1); + else { + int i; + luaL_Buffer b; + luaL_buffinit(L, &b); + for (i = 1; i <= n; i++) { + pushutfchar(L, i); + luaL_addvalue(&b); + } + luaL_pushresult(&b); + } + return 1; +} + + +/* +** offset(s, n, [i]) -> index where n-th character counting from +** position 'i' starts; 0 means character at 'i'. +*/ +static int byteoffset (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = luaL_checkinteger(L, 2); + lua_Integer posi = (n >= 0) ? 1 : len + 1; + posi = u_posrelat(luaL_optinteger(L, 3, posi), len); + luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, + "position out of range"); + if (n == 0) { + /* find beginning of current byte sequence */ + while (posi > 0 && iscont(s + posi)) posi--; + } + else { + if (iscont(s + posi)) + luaL_error(L, "initial position is a continuation byte"); + if (n < 0) { + while (n < 0 && posi > 0) { /* move back */ + do { /* find beginning of previous character */ + posi--; + } while (posi > 0 && iscont(s + posi)); + n++; + } + } + else { + n--; /* do not move for 1st character */ + while (n > 0 && posi < (lua_Integer)len) { + do { /* find beginning of next character */ + posi++; + } while (iscont(s + posi)); /* (cannot pass final '\0') */ + n--; + } + } + } + if (n == 0) /* did it find given character? */ + lua_pushinteger(L, posi + 1); + else /* no such character */ + lua_pushnil(L); + return 1; +} + + +static int iter_aux (lua_State *L) { + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + lua_Integer n = lua_tointeger(L, 2) - 1; + if (n < 0) /* first iteration? */ + n = 0; /* start from here */ + else if (n < (lua_Integer)len) { + n++; /* skip current byte */ + while (iscont(s + n)) n++; /* and its continuations */ + } + if (n >= (lua_Integer)len) + return 0; /* no more codepoints */ + else { + int code; + const char *next = utf8_decode(s + n, &code); + if (next == NULL || iscont(next)) + return luaL_error(L, "invalid UTF-8 code"); + lua_pushinteger(L, n + 1); + lua_pushinteger(L, code); + return 2; + } +} + + +static int iter_codes (lua_State *L) { + luaL_checkstring(L, 1); + lua_pushcfunction(L, iter_aux); + lua_pushvalue(L, 1); + lua_pushinteger(L, 0); + return 3; +} + + +/* pattern to match a single UTF-8 character */ +#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" + + +static const luaL_Reg funcs[] = { + {"offset", byteoffset}, + {"codepoint", codepoint}, + {"char", utfchar}, + {"len", utflen}, + {"codes", iter_codes}, + /* placeholders */ + {"charpattern", NULL}, + {NULL, NULL} +}; + + +LUAMOD_API int luaopen_utf8 (lua_State *L) { + luaL_newlib(L, funcs); + lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); + lua_setfield(L, -2, "charpattern"); + return 1; +} + diff --git a/depends/lua/src/lvm.c b/depends/lua/src/lvm.c index 141b9fd19..84ade6b2f 100644 --- a/depends/lua/src/lvm.c +++ b/depends/lua/src/lvm.c @@ -1,17 +1,21 @@ /* -** $Id: lvm.c,v 2.155.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ +#define lvm_c +#define LUA_CORE + +#include "lprefix.h" +#include +#include +#include #include #include #include -#define lvm_c -#define LUA_CORE - #include "lua.h" #include "ldebug.h" @@ -27,304 +31,479 @@ #include "lvm.h" - /* limit for table tag-method chains (to avoid loops) */ -#define MAXTAGLOOP 100 +#define MAXTAGLOOP 2000 -const TValue *luaV_tonumber (const TValue *obj, TValue *n) { - lua_Number num; - if (ttisnumber(obj)) return obj; - if (ttisstring(obj) && luaO_str2d(svalue(obj), tsvalue(obj)->len, &num)) { - setnvalue(n, num); - return n; - } - else - return NULL; -} +/* +** 'l_intfitsf' checks whether a given integer can be converted to a +** float without rounding. Used in comparisons. Left undefined if +** all integers fit in a float precisely. +*/ +#if !defined(l_intfitsf) -int luaV_tostring (lua_State *L, StkId obj) { - if (!ttisnumber(obj)) - return 0; - else { - char s[LUAI_MAXNUMBER2STR]; - lua_Number n = nvalue(obj); - int l = lua_number2str(s, n); - setsvalue2s(L, obj, luaS_newlstr(L, s, l)); +/* number of bits in the mantissa of a float */ +#define NBM (l_mathlim(MANT_DIG)) + +/* +** Check whether some integers may not fit in a float, that is, whether +** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger). +** (The shifts are done in parts to avoid shifting by more than the size +** of an integer. In a worst case, NBM == 113 for long double and +** sizeof(integer) == 32.) +*/ +#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \ + >> (NBM - (3 * (NBM / 4)))) > 0 + +#define l_intfitsf(i) \ + (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM)) + +#endif + +#endif + + + +/* +** Try to convert a value to a float. The float case is already handled +** by the macro 'tonumber'. +*/ +int luaV_tonumber_ (const TValue *obj, lua_Number *n) { + TValue v; + if (ttisinteger(obj)) { + *n = cast_num(ivalue(obj)); + return 1; + } + else if (cvt2num(obj) && /* string convertible to number? */ + luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { + *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ return 1; } + else + return 0; /* conversion failed */ } -static void traceexec (lua_State *L) { - CallInfo *ci = L->ci; - lu_byte mask = L->hookmask; - int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0); - if (counthook) - resethookcount(L); /* reset count */ - if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ - ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ - return; /* do not call hook again (VM yielded, so it did not move) */ +/* +** try to convert a value to an integer, rounding according to 'mode': +** mode == 0: accepts only integral values +** mode == 1: takes the floor of the number +** mode == 2: takes the ceil of the number +*/ +int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { + TValue v; + again: + if (ttisfloat(obj)) { + lua_Number n = fltvalue(obj); + lua_Number f = l_floor(n); + if (n != f) { /* not an integral value? */ + if (mode == 0) return 0; /* fails if mode demands integral value */ + else if (mode > 1) /* needs ceil? */ + f += 1; /* convert floor to ceil (remember: n != f) */ + } + return lua_numbertointeger(f, p); } - if (counthook) - luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ - if (mask & LUA_MASKLINE) { - Proto *p = ci_func(ci)->p; - int npc = pcRel(ci->u.l.savedpc, p); - int newline = getfuncline(p, npc); - if (npc == 0 || /* call linehook when enter a new function, */ - ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ - newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ - luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ + else if (ttisinteger(obj)) { + *p = ivalue(obj); + return 1; } - L->oldpc = ci->u.l.savedpc; - if (L->status == LUA_YIELD) { /* did hook yield? */ - if (counthook) - L->hookcount = 1; /* undo decrement to zero */ - ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ - ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ - ci->func = L->top - 1; /* protect stack below results */ - luaD_throw(L, LUA_YIELD); + else if (cvt2num(obj) && + luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { + obj = &v; + goto again; /* convert result from 'luaO_str2num' to an integer */ } + return 0; /* conversion failed */ } -static void callTM (lua_State *L, const TValue *f, const TValue *p1, - const TValue *p2, TValue *p3, int hasres) { - ptrdiff_t result = savestack(L, p3); - setobj2s(L, L->top++, f); /* push function */ - setobj2s(L, L->top++, p1); /* 1st argument */ - setobj2s(L, L->top++, p2); /* 2nd argument */ - if (!hasres) /* no result? 'p3' is third argument */ - setobj2s(L, L->top++, p3); /* 3rd argument */ - /* metamethod may yield only when called from Lua code */ - luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); - if (hasres) { /* if has result, move it to its place */ - p3 = restorestack(L, result); - setobjs2s(L, p3, --L->top); +/* +** Try to convert a 'for' limit to an integer, preserving the +** semantics of the loop. +** (The following explanation assumes a non-negative step; it is valid +** for negative steps mutatis mutandis.) +** If the limit can be converted to an integer, rounding down, that is +** it. +** Otherwise, check whether the limit can be converted to a number. If +** the number is too large, it is OK to set the limit as LUA_MAXINTEGER, +** which means no limit. If the number is too negative, the loop +** should not run, because any initial integer value is larger than the +** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects +** the extreme case when the initial value is LUA_MININTEGER, in which +** case the LUA_MININTEGER limit would still run the loop once. +*/ +static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, + int *stopnow) { + *stopnow = 0; /* usually, let loops run */ + if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */ + lua_Number n; /* try to convert to float */ + if (!tonumber(obj, &n)) /* cannot convert to float? */ + return 0; /* not a number */ + if (luai_numlt(0, n)) { /* if true, float is larger than max integer */ + *p = LUA_MAXINTEGER; + if (step < 0) *stopnow = 1; + } + else { /* float is smaller than min integer */ + *p = LUA_MININTEGER; + if (step >= 0) *stopnow = 1; + } } + return 1; } -void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { - int loop; +/* +** Finish the table access 'val = t[key]'. +** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to +** t[k] entry (which must be nil). +*/ +void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, + const TValue *slot) { + int loop; /* counter to avoid infinite loops */ + const TValue *tm; /* metamethod */ for (loop = 0; loop < MAXTAGLOOP; loop++) { - const TValue *tm; - if (ttistable(t)) { /* `t' is a table? */ - Table *h = hvalue(t); - const TValue *res = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(res) || /* result is not nil? */ - (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ - setobj2s(L, val, res); + if (slot == NULL) { /* 't' is not a table? */ + lua_assert(!ttistable(t)); + tm = luaT_gettmbyobj(L, t, TM_INDEX); + if (ttisnil(tm)) + luaG_typeerror(L, t, "index"); /* no metamethod */ + /* else will try the metamethod */ + } + else { /* 't' is a table */ + lua_assert(ttisnil(slot)); + tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ + if (tm == NULL) { /* no metamethod? */ + setnilvalue(val); /* result is nil */ return; } - /* else will try the tag method */ + /* else will try the metamethod */ } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) - luaG_typeerror(L, t, "index"); - if (ttisfunction(tm)) { - callTM(L, tm, t, key, val, 1); + if (ttisfunction(tm)) { /* is metamethod a function? */ + luaT_callTM(L, tm, t, key, val, 1); /* call it */ + return; + } + t = tm; /* else try to access 'tm[key]' */ + if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ + setobj2s(L, val, slot); /* done */ return; } - t = tm; /* else repeat with 'tm' */ + /* else repeat (tail call 'luaV_finishget') */ } - luaG_runerror(L, "loop in gettable"); + luaG_runerror(L, "'__index' chain too long; possible loop"); } -void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { - int loop; +/* +** Finish a table assignment 't[key] = val'. +** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points +** to the entry 't[key]', or to 'luaO_nilobject' if there is no such +** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' +** would have done the job.) +*/ +void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot) { + int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { - const TValue *tm; - if (ttistable(t)) { /* `t' is a table? */ - Table *h = hvalue(t); - TValue *oldval = cast(TValue *, luaH_get(h, key)); - /* if previous value is not nil, there must be a previous entry - in the table; moreover, a metamethod has no relevance */ - if (!ttisnil(oldval) || - /* previous value is nil; must check the metamethod */ - ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && - /* no metamethod; is there a previous entry in the table? */ - (oldval != luaO_nilobject || - /* no previous entry; must create one. (The next test is - always true; we only need the assignment.) */ - (oldval = luaH_newkey(L, h, key), 1)))) { + const TValue *tm; /* '__newindex' metamethod */ + if (slot != NULL) { /* is 't' a table? */ + Table *h = hvalue(t); /* save 't' table */ + lua_assert(ttisnil(slot)); /* old value must be nil */ + tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ + if (tm == NULL) { /* no metamethod? */ + if (slot == luaO_nilobject) /* no previous entry? */ + slot = luaH_newkey(L, h, key); /* create one */ /* no metamethod and (now) there is an entry with given key */ - setobj2t(L, oldval, val); /* assign new value to that entry */ + setobj2t(L, cast(TValue *, slot), val); /* set its new value */ invalidateTMcache(h); - luaC_barrierback(L, obj2gco(h), val); + luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ } - else /* not a table; check metamethod */ + else { /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); - /* there is a metamethod */ + } + /* try the metamethod */ if (ttisfunction(tm)) { - callTM(L, tm, t, key, val, 0); + luaT_callTM(L, tm, t, key, val, 0); return; } - t = tm; /* else repeat with 'tm' */ + t = tm; /* else repeat assignment over 'tm' */ + if (luaV_fastset(L, t, key, slot, luaH_get, val)) + return; /* done */ + /* else loop */ } - luaG_runerror(L, "loop in settable"); + luaG_runerror(L, "'__newindex' chain too long; possible loop"); } -static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, - StkId res, TMS event) { - const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ - if (ttisnil(tm)) - tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ - if (ttisnil(tm)) return 0; - callTM(L, tm, p1, p2, res, 1); - return 1; +/* +** Compare two strings 'ls' x 'rs', returning an integer smaller-equal- +** -larger than zero if 'ls' is smaller-equal-larger than 'rs'. +** The code is a little tricky because it allows '\0' in the strings +** and it uses 'strcoll' (to respect locales) for each segments +** of the strings. +*/ +static int l_strcmp (const TString *ls, const TString *rs) { + const char *l = getstr(ls); + size_t ll = tsslen(ls); + const char *r = getstr(rs); + size_t lr = tsslen(rs); + for (;;) { /* for each segment */ + int temp = strcoll(l, r); + if (temp != 0) /* not equal? */ + return temp; /* done */ + else { /* strings are equal up to a '\0' */ + size_t len = strlen(l); /* index of first '\0' in both strings */ + if (len == lr) /* 'rs' is finished? */ + return (len == ll) ? 0 : 1; /* check 'ls' */ + else if (len == ll) /* 'ls' is finished? */ + return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ + /* both strings longer than 'len'; go on comparing after the '\0' */ + len++; + l += len; ll -= len; r += len; lr -= len; + } + } } -static const TValue *get_equalTM (lua_State *L, Table *mt1, Table *mt2, - TMS event) { - const TValue *tm1 = fasttm(L, mt1, event); - const TValue *tm2; - if (tm1 == NULL) return NULL; /* no metamethod */ - if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ - tm2 = fasttm(L, mt2, event); - if (tm2 == NULL) return NULL; /* no metamethod */ - if (luaV_rawequalobj(tm1, tm2)) /* same metamethods? */ - return tm1; - return NULL; +/* +** Check whether integer 'i' is less than float 'f'. If 'i' has an +** exact representation as a float ('l_intfitsf'), compare numbers as +** floats. Otherwise, if 'f' is outside the range for integers, result +** is trivial. Otherwise, compare them as integers. (When 'i' has no +** float representation, either 'f' is "far away" from 'i' or 'f' has +** no precision left for a fractional part; either way, how 'f' is +** truncated is irrelevant.) When 'f' is NaN, comparisons must result +** in false. +*/ +static int LTintfloat (lua_Integer i, lua_Number f) { +#if defined(l_intfitsf) + if (!l_intfitsf(i)) { + if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ + return 1; /* f >= maxint + 1 > i */ + else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */ + return (i < cast(lua_Integer, f)); /* compare them as integers */ + else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */ + return 0; + } +#endif + return luai_numlt(cast_num(i), f); /* compare them as floats */ } -static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, - TMS event) { - if (!call_binTM(L, p1, p2, L->top, event)) - return -1; /* no metamethod */ - else - return !l_isfalse(L->top); +/* +** Check whether integer 'i' is less than or equal to float 'f'. +** See comments on previous function. +*/ +static int LEintfloat (lua_Integer i, lua_Number f) { +#if defined(l_intfitsf) + if (!l_intfitsf(i)) { + if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ + return 1; /* f >= maxint + 1 > i */ + else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */ + return (i <= cast(lua_Integer, f)); /* compare them as integers */ + else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */ + return 0; + } +#endif + return luai_numle(cast_num(i), f); /* compare them as floats */ } -static int l_strcmp (const TString *ls, const TString *rs) { - const char *l = getstr(ls); - size_t ll = ls->tsv.len; - const char *r = getstr(rs); - size_t lr = rs->tsv.len; - for (;;) { - int temp = strcoll(l, r); - if (temp != 0) return temp; - else { /* strings are equal up to a `\0' */ - size_t len = strlen(l); /* index of first `\0' in both strings */ - if (len == lr) /* r is finished? */ - return (len == ll) ? 0 : 1; - else if (len == ll) /* l is finished? */ - return -1; /* l is smaller than r (because r is not finished) */ - /* both strings longer than `len'; go on comparing (after the `\0') */ - len++; - l += len; ll -= len; r += len; lr -= len; - } +/* +** Return 'l < r', for numbers. +*/ +static int LTnum (const TValue *l, const TValue *r) { + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li < ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LTintfloat(li, fltvalue(r)); /* l < r ? */ + } + else { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numlt(lf, fltvalue(r)); /* both are float */ + else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ + return 0; /* NaN < i is always false */ + else /* without NaN, (l < r) <--> not(r <= l) */ + return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */ } } +/* +** Return 'l <= r', for numbers. +*/ +static int LEnum (const TValue *l, const TValue *r) { + if (ttisinteger(l)) { + lua_Integer li = ivalue(l); + if (ttisinteger(r)) + return li <= ivalue(r); /* both are integers */ + else /* 'l' is int and 'r' is float */ + return LEintfloat(li, fltvalue(r)); /* l <= r ? */ + } + else { + lua_Number lf = fltvalue(l); /* 'l' must be float */ + if (ttisfloat(r)) + return luai_numle(lf, fltvalue(r)); /* both are float */ + else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ + return 0; /* NaN <= i is always false */ + else /* without NaN, (l <= r) <--> not(r < l) */ + return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */ + } +} + + +/* +** Main operation less than; return 'l < r'. +*/ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; - if (ttisnumber(l) && ttisnumber(r)) - return luai_numlt(L, nvalue(l), nvalue(r)); - else if (ttisstring(l) && ttisstring(r)) - return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; - else if ((res = call_orderTM(L, l, r, TM_LT)) < 0) - luaG_ordererror(L, l, r); + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LTnum(l, r); + else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) < 0; + else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ + luaG_ordererror(L, l, r); /* error */ return res; } +/* +** Main operation less than or equal to; return 'l <= r'. If it needs +** a metamethod and there is no '__le', try '__lt', based on +** l <= r iff !(r < l) (assuming a total order). If the metamethod +** yields during this substitution, the continuation has to know +** about it (to negate the result of r= 0) /* first try `le' */ + if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ + return LEnum(l, r); + else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ + return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; + else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */ return res; - else if ((res = call_orderTM(L, r, l, TM_LT)) < 0) /* else try `lt' */ - luaG_ordererror(L, l, r); - return !res; + else { /* try 'lt': */ + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ + res = luaT_callorderTM(L, r, l, TM_LT); + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ + if (res < 0) + luaG_ordererror(L, l, r); + return !res; /* result is negated */ + } } /* -** equality of Lua values. L == NULL means raw equality (no metamethods) +** Main operation for equality of Lua values; return 't1 == t2'. +** L == NULL means raw equality (no metamethods) */ -int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2) { +int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; - lua_assert(ttisequal(t1, t2)); + if (ttype(t1) != ttype(t2)) { /* not the same variant? */ + if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) + return 0; /* only numbers can be equal with different variants */ + else { /* two numbers with different variants */ + lua_Integer i1, i2; /* compare them as integers */ + return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2); + } + } + /* values have same type and same variant */ switch (ttype(t1)) { case LUA_TNIL: return 1; - case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); + case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); + case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TLCF: return fvalue(t1) == fvalue(t2); - case LUA_TSHRSTR: return eqshrstr(rawtsvalue(t1), rawtsvalue(t2)); - case LUA_TLNGSTR: return luaS_eqlngstr(rawtsvalue(t1), rawtsvalue(t2)); + case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); + case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; else if (L == NULL) return 0; - tm = get_equalTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); + tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; else if (L == NULL) return 0; - tm = get_equalTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); + tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); + if (tm == NULL) + tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: - lua_assert(iscollectable(t1)); return gcvalue(t1) == gcvalue(t2); } - if (tm == NULL) return 0; /* no TM? */ - callTM(L, tm, t1, t2, L->top, 1); /* call TM */ + if (tm == NULL) /* no TM? */ + return 0; /* objects are different */ + luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ return !l_isfalse(L->top); } +/* macro used by 'luaV_concat' to ensure that element at 'o' is a string */ +#define tostring(L,o) \ + (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) + +#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) + +/* copy strings in stack from top - n up to top - 1 to buffer */ +static void copy2buff (StkId top, int n, char *buff) { + size_t tl = 0; /* size already copied */ + do { + size_t l = vslen(top - n); /* length of string being copied */ + memcpy(buff + tl, svalue(top - n), l * sizeof(char)); + tl += l; + } while (--n > 0); +} + + +/* +** Main operation for concatenation: concat 'total' values in the stack, +** from 'L->top - total' up to 'L->top - 1'. +*/ void luaV_concat (lua_State *L, int total) { lua_assert(total >= 2); do { StkId top = L->top; int n = 2; /* number of elements handled in this pass (at least 2) */ - if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { - if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) - luaG_concaterror(L, top-2, top-1); - } - else if (tsvalue(top-1)->len == 0) /* second operand is empty? */ - (void)tostring(L, top - 2); /* result is first operand */ - else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { + if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) + luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT); + else if (isemptystr(top - 1)) /* second operand is empty? */ + cast_void(tostring(L, top - 2)); /* result is first operand */ + else if (isemptystr(top - 2)) { /* first operand is an empty string? */ setobjs2s(L, top - 2, top - 1); /* result is second op. */ } else { /* at least two non-empty string values; get as many as possible */ - size_t tl = tsvalue(top-1)->len; - char *buffer; - int i; - /* collect total length */ - for (i = 1; i < total && tostring(L, top-i-1); i++) { - size_t l = tsvalue(top-i-1)->len; - if (l >= (MAX_SIZET/sizeof(char)) - tl) + size_t tl = vslen(top - 1); + TString *ts; + /* collect total length and number of strings */ + for (n = 1; n < total && tostring(L, top - n - 1); n++) { + size_t l = vslen(top - n - 1); + if (l >= (MAX_SIZE/sizeof(char)) - tl) luaG_runerror(L, "string length overflow"); tl += l; } - buffer = luaZ_openspace(L, &G(L)->buff, tl); - tl = 0; - n = i; - do { /* concat all strings */ - size_t l = tsvalue(top-i)->len; - memcpy(buffer+tl, svalue(top-i), l * sizeof(char)); - tl += l; - } while (--i > 0); - setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); + if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ + char buff[LUAI_MAXSHORTLEN]; + copy2buff(top, n, buff); /* copy strings to buffer */ + ts = luaS_newlstr(L, buff, tl); + } + else { /* long string; copy strings directly to final result */ + ts = luaS_createlngstrobj(L, tl); + copy2buff(top, n, getstr(ts)); + } + setsvalue2s(L, top - n, ts); /* create result */ } total -= n-1; /* got 'n' strings to create 1 new */ L->top -= n-1; /* popped 'n' strings and pushed one */ @@ -332,18 +511,25 @@ void luaV_concat (lua_State *L, int total) { } +/* +** Main operation 'ra' = #rb'. +*/ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { const TValue *tm; - switch (ttypenv(rb)) { + switch (ttype(rb)) { case LUA_TTABLE: { Table *h = hvalue(rb); tm = fasttm(L, h->metatable, TM_LEN); if (tm) break; /* metamethod? break switch to call it */ - setnvalue(ra, cast_num(luaH_getn(h))); /* else primitive len */ + setivalue(ra, luaH_getn(h)); /* else primitive len */ return; } - case LUA_TSTRING: { - setnvalue(ra, cast_num(tsvalue(rb)->len)); + case LUA_TSHRSTR: { + setivalue(ra, tsvalue(rb)->shrlen); + return; + } + case LUA_TLNGSTR: { + setivalue(ra, tsvalue(rb)->u.lnglen); return; } default: { /* try metamethod */ @@ -353,21 +539,66 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { break; } } - callTM(L, tm, rb, rb, ra, 1); + luaT_callTM(L, tm, rb, rb, ra, 1); +} + + +/* +** Integer division; return 'm // n', that is, floor(m/n). +** C division truncates its result (rounds towards zero). +** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, +** otherwise 'floor(q) == trunc(q) - 1'. +*/ +lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to divide by zero"); + return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ + } + else { + lua_Integer q = m / n; /* perform C division */ + if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ + q -= 1; /* correct result for different rounding */ + return q; + } +} + + +/* +** Integer modulus; return 'm % n'. (Assume that C '%' with +** negative operands follows C99 behavior. See previous comment +** about luaV_div.) +*/ +lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { + if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ + if (n == 0) + luaG_runerror(L, "attempt to perform 'n%%0'"); + return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ + } + else { + lua_Integer r = m % n; + if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */ + r += n; /* correct result for different rounding */ + return r; + } } -void luaV_arith (lua_State *L, StkId ra, const TValue *rb, - const TValue *rc, TMS op) { - TValue tempb, tempc; - const TValue *b, *c; - if ((b = luaV_tonumber(rb, &tempb)) != NULL && - (c = luaV_tonumber(rc, &tempc)) != NULL) { - lua_Number res = luaO_arith(op - TM_ADD + LUA_OPADD, nvalue(b), nvalue(c)); - setnvalue(ra, res); +/* number of bits in an integer */ +#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) + +/* +** Shift left operation. (Shift right just negates 'y'.) +*/ +lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { + if (y < 0) { /* shift right? */ + if (y <= -NBITS) return 0; + else return intop(>>, x, -y); + } + else { /* shift left */ + if (y >= NBITS) return 0; + else return intop(<<, x, y); } - else if (!call_binTM(L, rb, rc, ra, op)) - luaG_aritherror(L, rb, rc); } @@ -376,15 +607,15 @@ void luaV_arith (lua_State *L, StkId ra, const TValue *rb, ** whether there is a cached closure with the same upvalues needed by ** new closure to be created. */ -static Closure *getcached (Proto *p, UpVal **encup, StkId base) { - Closure *c = p->cache; +static LClosure *getcached (Proto *p, UpVal **encup, StkId base) { + LClosure *c = p->cache; if (c != NULL) { /* is there a cached closure? */ int nup = p->sizeupvalues; Upvaldesc *uv = p->upvalues; int i; for (i = 0; i < nup; i++) { /* check whether it has right upvalues */ TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; - if (c->l.upvals[i]->v != v) + if (c->upvals[i]->v != v) return NULL; /* wrong upvalue; cannot reuse closure */ } } @@ -394,26 +625,28 @@ static Closure *getcached (Proto *p, UpVal **encup, StkId base) { /* ** create a new Lua closure, push it in the stack, and initialize -** its upvalues. Note that the call to 'luaC_barrierproto' must come -** before the assignment to 'p->cache', as the function needs the -** original value of that field. +** its upvalues. Note that the closure is not cached if prototype is +** already black (which means that 'cache' was already cleared by the +** GC). */ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, StkId ra) { int nup = p->sizeupvalues; Upvaldesc *uv = p->upvalues; int i; - Closure *ncl = luaF_newLclosure(L, nup); - ncl->l.p = p; + LClosure *ncl = luaF_newLclosure(L, nup); + ncl->p = p; setclLvalue(L, ra, ncl); /* anchor new closure in stack */ for (i = 0; i < nup; i++) { /* fill in its upvalues */ if (uv[i].instack) /* upvalue refers to local variable? */ - ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx); + ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); else /* get upvalue from enclosing function */ - ncl->l.upvals[i] = encup[uv[i].idx]; + ncl->upvals[i] = encup[uv[i].idx]; + ncl->upvals[i]->refcount++; + /* new closure is white, so we do not need a barrier here */ } - luaC_barrierproto(L, p, ncl); - p->cache = ncl; /* save it on cache for reuse */ + if (!isblack(p)) /* cache will not break GC invariant? */ + p->cache = ncl; /* save it on cache for reuse */ } @@ -426,8 +659,10 @@ void luaV_finishOp (lua_State *L) { Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ OpCode op = GET_OPCODE(inst); switch (op) { /* finish its execution */ - case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: - case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: + case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: + case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: + case OP_MOD: case OP_POW: + case OP_UNM: case OP_BNOT: case OP_LEN: case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { setobjs2s(L, base + GETARG_A(inst), --L->top); break; @@ -435,18 +670,18 @@ void luaV_finishOp (lua_State *L) { case OP_LE: case OP_LT: case OP_EQ: { int res = !l_isfalse(L->top - 1); L->top--; - /* metamethod should not be called when operand is K */ - lua_assert(!ISK(GETARG_B(inst))); - if (op == OP_LE && /* "<=" using "<" instead? */ - ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE))) - res = !res; /* invert result */ + if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ + lua_assert(op == OP_LE); + ci->callstatus ^= CIST_LEQ; /* clear mark */ + res = !res; /* negate result */ + } lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); if (res != GETARG_A(inst)) /* condition failed? */ ci->u.l.savedpc++; /* skip jump instruction */ break; } case OP_CONCAT: { - StkId top = L->top - 1; /* top when 'call_binTM' was called */ + StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ int b = GETARG_B(inst); /* first element to concatenate */ int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ setobj2s(L, top - 2, top); /* put TM result in proper position */ @@ -477,31 +712,32 @@ void luaV_finishOp (lua_State *L) { + /* -** some macros for common tasks in `luaV_execute' +** {================================================================== +** Function 'luaV_execute': main interpreter loop +** =================================================================== */ -#if !defined luai_runtimecheck -#define luai_runtimecheck(L, c) /* void */ -#endif + +/* +** some macros for common tasks in 'luaV_execute' +*/ #define RA(i) (base+GETARG_A(i)) -/* to be used after possible stack reallocation */ #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) #define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) #define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) #define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) -#define KBx(i) \ - (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++))) /* execute a jump instruction */ #define dojump(ci,i,e) \ { int a = GETARG_A(i); \ - if (a > 0) luaF_close(L, ci->u.l.base + a - 1); \ + if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \ ci->u.l.savedpc += GETARG_sBx(i) + e; } /* for test instructions, execute the jump instruction that follows it */ @@ -511,96 +747,124 @@ void luaV_finishOp (lua_State *L) { #define Protect(x) { {x;}; base = ci->u.l.base; } #define checkGC(L,c) \ - Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \ - luaC_step(L); \ - L->top = ci->top;}) /* restore top */ \ - luai_threadyield(L); ) + { luaC_condGC(L, L->top = (c), /* limit of live values */ \ + Protect(L->top = ci->top)); /* restore top */ \ + luai_threadyield(L); } + + +/* fetch an instruction and prepare its execution */ +#define vmfetch() { \ + i = *(ci->u.l.savedpc++); \ + if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \ + Protect(luaG_traceexec(L)); \ + ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \ + lua_assert(base == ci->u.l.base); \ + lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \ +} +#define vmdispatch(o) switch(o) +#define vmcase(l) case l: +#define vmbreak break -#define arith_op(op,tm) { \ - TValue *rb = RKB(i); \ - TValue *rc = RKC(i); \ - if (ttisnumber(rb) && ttisnumber(rc)) { \ - lua_Number nb = nvalue(rb), nc = nvalue(rc); \ - setnvalue(ra, op(L, nb, nc)); \ - } \ - else { Protect(luaV_arith(L, ra, rb, rc, tm)); } } + +/* +** copy of 'luaV_gettable', but protecting the call to potential +** metamethod (which can reallocate the stack) +*/ +#define gettableProtected(L,t,k,v) { const TValue *slot; \ + if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ + else Protect(luaV_finishget(L,t,k,v,slot)); } + + +/* same for 'luaV_settable' */ +#define settableProtected(L,t,k,v) { const TValue *slot; \ + if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ + Protect(luaV_finishset(L,t,k,v,slot)); } -#define vmdispatch(o) switch(o) -#define vmcase(l,b) case l: {b} break; -#define vmcasenb(l,b) case l: {b} /* nb = no break */ void luaV_execute (lua_State *L) { CallInfo *ci = L->ci; LClosure *cl; TValue *k; StkId base; + ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ newframe: /* reentry point when frame changes (call/return) */ lua_assert(ci == L->ci); - cl = clLvalue(ci->func); - k = cl->p->k; - base = ci->u.l.base; + cl = clLvalue(ci->func); /* local reference to function's closure */ + k = cl->p->k; /* local reference to function's constant table */ + base = ci->u.l.base; /* local copy of function's base */ /* main loop of interpreter */ for (;;) { - Instruction i = *(ci->u.l.savedpc++); + Instruction i; StkId ra; - if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && - (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - Protect(traceexec(L)); - } - /* WARNING: several calls may realloc the stack and invalidate `ra' */ - ra = RA(i); - lua_assert(base == ci->u.l.base); - lua_assert(base <= L->top && L->top < L->stack + L->stacksize); + vmfetch(); vmdispatch (GET_OPCODE(i)) { - vmcase(OP_MOVE, + vmcase(OP_MOVE) { setobjs2s(L, ra, RB(i)); - ) - vmcase(OP_LOADK, + vmbreak; + } + vmcase(OP_LOADK) { TValue *rb = k + GETARG_Bx(i); setobj2s(L, ra, rb); - ) - vmcase(OP_LOADKX, + vmbreak; + } + vmcase(OP_LOADKX) { TValue *rb; lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); rb = k + GETARG_Ax(*ci->u.l.savedpc++); setobj2s(L, ra, rb); - ) - vmcase(OP_LOADBOOL, + vmbreak; + } + vmcase(OP_LOADBOOL) { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ - ) - vmcase(OP_LOADNIL, + vmbreak; + } + vmcase(OP_LOADNIL) { int b = GETARG_B(i); do { setnilvalue(ra++); } while (b--); - ) - vmcase(OP_GETUPVAL, + vmbreak; + } + vmcase(OP_GETUPVAL) { int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); - ) - vmcase(OP_GETTABUP, - int b = GETARG_B(i); - Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra)); - ) - vmcase(OP_GETTABLE, - Protect(luaV_gettable(L, RB(i), RKC(i), ra)); - ) - vmcase(OP_SETTABUP, - int a = GETARG_A(i); - Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i))); - ) - vmcase(OP_SETUPVAL, + vmbreak; + } + vmcase(OP_GETTABUP) { + TValue *upval = cl->upvals[GETARG_B(i)]->v; + TValue *rc = RKC(i); + gettableProtected(L, upval, rc, ra); + vmbreak; + } + vmcase(OP_GETTABLE) { + StkId rb = RB(i); + TValue *rc = RKC(i); + gettableProtected(L, rb, rc, ra); + vmbreak; + } + vmcase(OP_SETTABUP) { + TValue *upval = cl->upvals[GETARG_A(i)]->v; + TValue *rb = RKB(i); + TValue *rc = RKC(i); + settableProtected(L, upval, rb, rc); + vmbreak; + } + vmcase(OP_SETUPVAL) { UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); - luaC_barrier(L, uv, ra); - ) - vmcase(OP_SETTABLE, - Protect(luaV_settable(L, ra, RKB(i), RKC(i))); - ) - vmcase(OP_NEWTABLE, + luaC_upvalbarrier(L, uv); + vmbreak; + } + vmcase(OP_SETTABLE) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + settableProtected(L, ra, rb, rc); + vmbreak; + } + vmcase(OP_NEWTABLE) { int b = GETARG_B(i); int c = GETARG_C(i); Table *t = luaH_new(L); @@ -608,96 +872,252 @@ void luaV_execute (lua_State *L) { if (b != 0 || c != 0) luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); checkGC(L, ra + 1); - ) - vmcase(OP_SELF, + vmbreak; + } + vmcase(OP_SELF) { + const TValue *aux; StkId rb = RB(i); - setobjs2s(L, ra+1, rb); - Protect(luaV_gettable(L, rb, RKC(i), ra)); - ) - vmcase(OP_ADD, - arith_op(luai_numadd, TM_ADD); - ) - vmcase(OP_SUB, - arith_op(luai_numsub, TM_SUB); - ) - vmcase(OP_MUL, - arith_op(luai_nummul, TM_MUL); - ) - vmcase(OP_DIV, - arith_op(luai_numdiv, TM_DIV); - ) - vmcase(OP_MOD, - arith_op(luai_nummod, TM_MOD); - ) - vmcase(OP_POW, - arith_op(luai_numpow, TM_POW); - ) - vmcase(OP_UNM, + TValue *rc = RKC(i); + TString *key = tsvalue(rc); /* key must be a string */ + setobjs2s(L, ra + 1, rb); + if (luaV_fastget(L, rb, key, aux, luaH_getstr)) { + setobj2s(L, ra, aux); + } + else Protect(luaV_finishget(L, rb, rc, ra, aux)); + vmbreak; + } + vmcase(OP_ADD) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(+, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numadd(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } + vmbreak; + } + vmcase(OP_SUB) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(-, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numsub(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); } + vmbreak; + } + vmcase(OP_MUL) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, intop(*, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_nummul(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); } + vmbreak; + } + vmcase(OP_DIV) { /* float division (always with floats) */ + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numdiv(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } + vmbreak; + } + vmcase(OP_BAND) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(&, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); } + vmbreak; + } + vmcase(OP_BOR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(|, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); } + vmbreak; + } + vmcase(OP_BXOR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, intop(^, ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); } + vmbreak; + } + vmcase(OP_SHL) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, luaV_shiftl(ib, ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); } + vmbreak; + } + vmcase(OP_SHR) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Integer ib; lua_Integer ic; + if (tointeger(rb, &ib) && tointeger(rc, &ic)) { + setivalue(ra, luaV_shiftl(ib, -ic)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); } + vmbreak; + } + vmcase(OP_MOD) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, luaV_mod(L, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + lua_Number m; + luai_nummod(L, nb, nc, m); + setfltvalue(ra, m); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } + vmbreak; + } + vmcase(OP_IDIV) { /* floor division */ + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (ttisinteger(rb) && ttisinteger(rc)) { + lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); + setivalue(ra, luaV_div(L, ib, ic)); + } + else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numidiv(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } + vmbreak; + } + vmcase(OP_POW) { + TValue *rb = RKB(i); + TValue *rc = RKC(i); + lua_Number nb; lua_Number nc; + if (tonumber(rb, &nb) && tonumber(rc, &nc)) { + setfltvalue(ra, luai_numpow(L, nb, nc)); + } + else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } + vmbreak; + } + vmcase(OP_UNM) { TValue *rb = RB(i); - if (ttisnumber(rb)) { - lua_Number nb = nvalue(rb); - setnvalue(ra, luai_numunm(L, nb)); + lua_Number nb; + if (ttisinteger(rb)) { + lua_Integer ib = ivalue(rb); + setivalue(ra, intop(-, 0, ib)); + } + else if (tonumber(rb, &nb)) { + setfltvalue(ra, luai_numunm(L, nb)); } else { - Protect(luaV_arith(L, ra, rb, rb, TM_UNM)); + Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); } - ) - vmcase(OP_NOT, + vmbreak; + } + vmcase(OP_BNOT) { + TValue *rb = RB(i); + lua_Integer ib; + if (tointeger(rb, &ib)) { + setivalue(ra, intop(^, ~l_castS2U(0), ib)); + } + else { + Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); + } + vmbreak; + } + vmcase(OP_NOT) { TValue *rb = RB(i); int res = l_isfalse(rb); /* next assignment may change this value */ setbvalue(ra, res); - ) - vmcase(OP_LEN, + vmbreak; + } + vmcase(OP_LEN) { Protect(luaV_objlen(L, ra, RB(i))); - ) - vmcase(OP_CONCAT, + vmbreak; + } + vmcase(OP_CONCAT) { int b = GETARG_B(i); int c = GETARG_C(i); StkId rb; L->top = base + c + 1; /* mark the end of concat operands */ Protect(luaV_concat(L, c - b + 1)); - ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */ - rb = b + base; + ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */ + rb = base + b; setobjs2s(L, ra, rb); checkGC(L, (ra >= rb ? ra + 1 : rb)); L->top = ci->top; /* restore top */ - ) - vmcase(OP_JMP, + vmbreak; + } + vmcase(OP_JMP) { dojump(ci, i, 0); - ) - vmcase(OP_EQ, + vmbreak; + } + vmcase(OP_EQ) { TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( - if (cast_int(equalobj(L, rb, rc)) != GETARG_A(i)) + if (luaV_equalobj(L, rb, rc) != GETARG_A(i)) ci->u.l.savedpc++; else donextjump(ci); ) - ) - vmcase(OP_LT, + vmbreak; + } + vmcase(OP_LT) { Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) ci->u.l.savedpc++; else donextjump(ci); ) - ) - vmcase(OP_LE, + vmbreak; + } + vmcase(OP_LE) { Protect( if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) ci->u.l.savedpc++; else donextjump(ci); ) - ) - vmcase(OP_TEST, + vmbreak; + } + vmcase(OP_TEST) { if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra)) ci->u.l.savedpc++; else donextjump(ci); - ) - vmcase(OP_TESTSET, + vmbreak; + } + vmcase(OP_TESTSET) { TValue *rb = RB(i); if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) ci->u.l.savedpc++; @@ -705,27 +1125,30 @@ void luaV_execute (lua_State *L) { setobjs2s(L, ra, rb); donextjump(ci); } - ) - vmcase(OP_CALL, + vmbreak; + } + vmcase(OP_CALL) { int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ if (luaD_precall(L, ra, nresults)) { /* C function? */ - if (nresults >= 0) L->top = ci->top; /* adjust results */ - base = ci->u.l.base; + if (nresults >= 0) + L->top = ci->top; /* adjust results */ + Protect((void)0); /* update 'base' */ } else { /* Lua function */ ci = L->ci; - ci->callstatus |= CIST_REENTRY; goto newframe; /* restart luaV_execute over new Lua function */ } - ) - vmcase(OP_TAILCALL, + vmbreak; + } + vmcase(OP_TAILCALL) { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */ - base = ci->u.l.base; + if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ + Protect((void)0); /* update 'base' */ + } else { /* tail call: put called frame (n) in place of caller one (o) */ CallInfo *nci = L->ci; /* called frame */ @@ -748,13 +1171,13 @@ void luaV_execute (lua_State *L) { lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); goto newframe; /* restart luaV_execute over new Lua function */ } - ) - vmcasenb(OP_RETURN, + vmbreak; + } + vmcase(OP_RETURN) { int b = GETARG_B(i); - if (b != 0) L->top = ra+b-1; if (cl->p->sizep > 0) luaF_close(L, base); - b = luaD_poscall(L, ra); - if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */ + b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); + if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */ return; /* external invocation: return */ else { /* invocation via reentry: continue execution */ ci = L->ci; @@ -763,105 +1186,137 @@ void luaV_execute (lua_State *L) { lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); goto newframe; /* restart luaV_execute over new Lua function */ } - ) - vmcase(OP_FORLOOP, - lua_Number step = nvalue(ra+2); - lua_Number idx = luai_numadd(L, nvalue(ra), step); /* increment index */ - lua_Number limit = nvalue(ra+1); - if (luai_numlt(L, 0, step) ? luai_numle(L, idx, limit) - : luai_numle(L, limit, idx)) { - ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ - setnvalue(ra, idx); /* update internal index... */ - setnvalue(ra+3, idx); /* ...and external index */ - } - ) - vmcase(OP_FORPREP, - const TValue *init = ra; - const TValue *plimit = ra+1; - const TValue *pstep = ra+2; - if (!tonumber(init, ra)) - luaG_runerror(L, LUA_QL("for") " initial value must be a number"); - else if (!tonumber(plimit, ra+1)) - luaG_runerror(L, LUA_QL("for") " limit must be a number"); - else if (!tonumber(pstep, ra+2)) - luaG_runerror(L, LUA_QL("for") " step must be a number"); - setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); + } + vmcase(OP_FORLOOP) { + if (ttisinteger(ra)) { /* integer loop? */ + lua_Integer step = ivalue(ra + 2); + lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */ + lua_Integer limit = ivalue(ra + 1); + if ((0 < step) ? (idx <= limit) : (limit <= idx)) { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + chgivalue(ra, idx); /* update internal index... */ + setivalue(ra + 3, idx); /* ...and external index */ + } + } + else { /* floating loop */ + lua_Number step = fltvalue(ra + 2); + lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ + lua_Number limit = fltvalue(ra + 1); + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { + ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ + chgfltvalue(ra, idx); /* update internal index... */ + setfltvalue(ra + 3, idx); /* ...and external index */ + } + } + vmbreak; + } + vmcase(OP_FORPREP) { + TValue *init = ra; + TValue *plimit = ra + 1; + TValue *pstep = ra + 2; + lua_Integer ilimit; + int stopnow; + if (ttisinteger(init) && ttisinteger(pstep) && + forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { + /* all values are integer */ + lua_Integer initv = (stopnow ? 0 : ivalue(init)); + setivalue(plimit, ilimit); + setivalue(init, intop(-, initv, ivalue(pstep))); + } + else { /* try making all values floats */ + lua_Number ninit; lua_Number nlimit; lua_Number nstep; + if (!tonumber(plimit, &nlimit)) + luaG_runerror(L, "'for' limit must be a number"); + setfltvalue(plimit, nlimit); + if (!tonumber(pstep, &nstep)) + luaG_runerror(L, "'for' step must be a number"); + setfltvalue(pstep, nstep); + if (!tonumber(init, &ninit)) + luaG_runerror(L, "'for' initial value must be a number"); + setfltvalue(init, luai_numsub(L, ninit, nstep)); + } ci->u.l.savedpc += GETARG_sBx(i); - ) - vmcasenb(OP_TFORCALL, + vmbreak; + } + vmcase(OP_TFORCALL) { StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); setobjs2s(L, cb, ra); L->top = cb + 3; /* func. + 2 args (state and index) */ - Protect(luaD_call(L, cb, GETARG_C(i), 1)); + Protect(luaD_call(L, cb, GETARG_C(i))); L->top = ci->top; i = *(ci->u.l.savedpc++); /* go to next instruction */ ra = RA(i); lua_assert(GET_OPCODE(i) == OP_TFORLOOP); goto l_tforloop; - ) - vmcase(OP_TFORLOOP, + } + vmcase(OP_TFORLOOP) { l_tforloop: if (!ttisnil(ra + 1)) { /* continue loop? */ setobjs2s(L, ra, ra + 1); /* save control variable */ ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ } - ) - vmcase(OP_SETLIST, + vmbreak; + } + vmcase(OP_SETLIST) { int n = GETARG_B(i); int c = GETARG_C(i); - int last; + unsigned int last; Table *h; if (n == 0) n = cast_int(L->top - ra) - 1; if (c == 0) { lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); c = GETARG_Ax(*ci->u.l.savedpc++); } - luai_runtimecheck(L, ttistable(ra)); h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ - luaH_resizearray(L, h, last); /* pre-allocate it at once */ + luaH_resizearray(L, h, last); /* preallocate it at once */ for (; n > 0; n--) { TValue *val = ra+n; luaH_setint(L, h, last--, val); - luaC_barrierback(L, obj2gco(h), val); + luaC_barrierback(L, h, val); } L->top = ci->top; /* correct top (in case of previous open call) */ - ) - vmcase(OP_CLOSURE, + vmbreak; + } + vmcase(OP_CLOSURE) { Proto *p = cl->p->p[GETARG_Bx(i)]; - Closure *ncl = getcached(p, cl->upvals, base); /* cached closure */ + LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ if (ncl == NULL) /* no match? */ pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ else setclLvalue(L, ra, ncl); /* push cashed closure */ checkGC(L, ra + 1); - ) - vmcase(OP_VARARG, - int b = GETARG_B(i) - 1; + vmbreak; + } + vmcase(OP_VARARG) { + int b = GETARG_B(i) - 1; /* required results */ int j; int n = cast_int(base - ci->func) - cl->p->numparams - 1; + if (n < 0) /* less arguments than parameters? */ + n = 0; /* no vararg arguments */ if (b < 0) { /* B == 0? */ b = n; /* get all var. arguments */ Protect(luaD_checkstack(L, n)); ra = RA(i); /* previous call may change the stack */ L->top = ra + n; } - for (j = 0; j < b; j++) { - if (j < n) { - setobjs2s(L, ra + j, base - n + j); - } - else { - setnilvalue(ra + j); - } - } - ) - vmcase(OP_EXTRAARG, + for (j = 0; j < b && j < n; j++) + setobjs2s(L, ra + j, base - n + j); + for (; j < b; j++) /* complete required results with nil */ + setnilvalue(ra + j); + vmbreak; + } + vmcase(OP_EXTRAARG) { lua_assert(0); - ) + vmbreak; + } } } } +/* }================================================================== */ + diff --git a/depends/lua/src/lzio.c b/depends/lua/src/lzio.c index 20efea983..c9e1f491f 100644 --- a/depends/lua/src/lzio.c +++ b/depends/lua/src/lzio.c @@ -1,15 +1,17 @@ /* -** $Id: lzio.c,v 1.35.1.1 2013/04/12 18:48:47 roberto Exp $ +** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ - -#include - #define lzio_c #define LUA_CORE +#include "lprefix.h" + + +#include + #include "lua.h" #include "llimits.h" @@ -64,13 +66,3 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) { return 0; } -/* ------------------------------------------------------------------------ */ -char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) { - if (n > buff->buffsize) { - if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; - luaZ_resizebuffer(L, buff, n); - } - return buff->buffer; -} - - From 4dd411e86227216ff0b2e534a625bb1b47a3b9ca Mon Sep 17 00:00:00 2001 From: Vitaly Pronkin Date: Tue, 26 Jul 2016 23:29:26 -0400 Subject: [PATCH 041/413] Update Lua config and patch checkdp --- depends/lua/CMakeLists.txt | 1 + depends/lua/include/luaconf.h | 35 +++++++++++++++++------------------ depends/lua/src/lstrlib.c | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/depends/lua/CMakeLists.txt b/depends/lua/CMakeLists.txt index 782bb5e96..bd244a126 100644 --- a/depends/lua/CMakeLists.txt +++ b/depends/lua/CMakeLists.txt @@ -80,6 +80,7 @@ src/ltable.c src/ltablib.c src/ltm.c src/lundump.c +src/lutf8lib.c src/lvm.c src/lzio.c ) diff --git a/depends/lua/include/luaconf.h b/depends/lua/include/luaconf.h index fd447ccb9..6578a6d07 100644 --- a/depends/lua/include/luaconf.h +++ b/depends/lua/include/luaconf.h @@ -11,6 +11,9 @@ #include #include +#define LUA_USE_LONGJMP //TODO: this is bad +#define LUA_COMPAT_APIINTCASTS +#define LUA_COMPAT_IPAIRS /* ** =================================================================== @@ -167,38 +170,30 @@ ** hierarchy or if you want to install your libraries in ** non-conventional directories. */ -#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #if defined(_WIN32) /* { */ /* ** In Windows, any exclamation mark ('!') in the path is replaced by the ** path of the directory of the executable file of the current process. */ -#define LUA_LDIR "!\\lua\\" +#define LUA_LDIR "!\\hack\\lua\\" #define LUA_CDIR "!\\" -#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" #define LUA_PATH_DEFAULT \ - LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ - LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ - ".\\?.lua;" ".\\?\\init.lua" + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" ".\\?.lua" #define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.dll;" \ - LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ - LUA_CDIR"loadall.dll;" ".\\?.dll" + LUA_CDIR"?.dll;" ".\\?.dll" #else /* }{ */ -#define LUA_ROOT "/usr/local/" -#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" -#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" +#define LUA_LDIR "./hack/lua/" +#define LUA_CDIR "./hack/" #define LUA_PATH_DEFAULT \ - LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ - LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ - "./?.lua;" "./?/init.lua" + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" "./?.lua" #define LUA_CPATH_DEFAULT \ - LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" + LUA_CDIR"?.so;" "./?.so" #endif /* } */ +#define LUA_PATH "DFHACK_LUA_PATH" +#define LUA_CPATH "DFHACK_LUA_CPATH" /* @@ LUA_DIRSEP is the directory separator (for submodules). @@ -231,11 +226,15 @@ */ #if defined(LUA_BUILD_AS_DLL) /* { */ +#if defined(_MSC_VER) #if defined(LUA_CORE) || defined(LUA_LIB) /* { */ #define LUA_API __declspec(dllexport) #else /* }{ */ #define LUA_API __declspec(dllimport) #endif /* } */ +#else +#define LUA_API __attribute__ ((visibility("default"))) +#endif #else /* }{ */ @@ -606,7 +605,7 @@ /* -@@ lua_number2strx converts a float to an hexadecimal numeric string. +@@ lua_number2strx converts a float to an hexadecimal numeric string. ** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. ** Otherwise, you can leave 'lua_number2strx' undefined and Lua will ** provide its own implementation. diff --git a/depends/lua/src/lstrlib.c b/depends/lua/src/lstrlib.c index 12264f881..a4a356a3f 100644 --- a/depends/lua/src/lstrlib.c +++ b/depends/lua/src/lstrlib.c @@ -933,7 +933,7 @@ static void addquoted (luaL_Buffer *b, const char *s, size_t len) { static void checkdp (char *buff, int nb) { if (memchr(buff, '.', nb) == NULL) { /* no dot? */ char point = lua_getlocaledecpoint(); /* try locale point */ - char *ppoint = memchr(buff, point, nb); + char *ppoint = (char*)memchr(buff, point, nb); if (ppoint) *ppoint = '.'; /* change it to a dot */ } } @@ -1259,7 +1259,7 @@ static KOption getoption (Header *h, const char **fmt, int *size) { ** 'psize' is filled with option's size, 'notoalign' with its ** alignment requirements. ** Local variable 'size' gets the size to be aligned. (Kpadal option -** always gets its full alignment, other options are limited by +** always gets its full alignment, other options are limited by ** the maximum alignment ('maxalign'). Kchar option needs no alignment ** despite its size. */ From 3833ff2e0964bfe34e999122250546076393e100 Mon Sep 17 00:00:00 2001 From: Vitaly Pronkin Date: Tue, 19 Jul 2016 01:37:29 +1200 Subject: [PATCH 042/413] proper 64bit address formatting --- library/LuaWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 08af93e78..0c5848408 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -993,7 +993,7 @@ static int meta_ptr_tostring(lua_State *state) lua_getfield(state, UPVAL_METATABLE, "__metatable"); const char *cname = lua_tostring(state, -1); - lua_pushstring(state, stl_sprintf("<%s: 0x%08x>", cname, (uintptr_t)ptr).c_str()); + lua_pushstring(state, stl_sprintf("<%s: 0x%llx>", cname, (uintptr_t)ptr).c_str()); return 1; } From fe18f176f7a4dabd0a1581b712516b12f284adbc Mon Sep 17 00:00:00 2001 From: Vitaly Pronkin Date: Tue, 26 Jul 2016 23:47:53 -0400 Subject: [PATCH 043/413] More 64-bit fixes Cherry-picked from 7eb3ba6 - Lua update already done in e2c6350, 4dd411e - Excluded library/modules/Buildings.cpp --- CMakeLists.txt | 4 ++-- library/Core.cpp | 8 ++++---- library/LuaTools.cpp | 13 +++++++++---- library/LuaTypes.cpp | 6 +++--- library/RemoteTools.cpp | 2 +- library/include/DataIdentity.h | 4 ++-- library/include/LuaTools.h | 12 +++++------- library/lua/dfhack.lua | 2 +- library/lua/memscan.lua | 4 +++- library/modules/World.cpp | 2 +- library/xml | 2 +- plugins/eventful.cpp | 10 +++++----- plugins/isoworldremote.cpp | 4 ++-- plugins/remotefortressreader.cpp | 2 +- plugins/rendermax/renderer_light.cpp | 4 ++-- 15 files changed, 42 insertions(+), 37 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec339b037..291fab324 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,8 +117,8 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac endif() # set up versioning. -set(DF_VERSION "0.43.03") -SET(DFHACK_RELEASE "r1") +set(DF_VERSION "0.43.05") +SET(DFHACK_RELEASE "alpha0") SET(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/library/Core.cpp b/library/Core.cpp index fb1dd80bb..975290e52 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2107,7 +2107,7 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve if (!df::global::world) return; - std::string rawFolder = "data/save/" + (df::global::world->cur_savegame.save_dir) + "/raw/"; + std::string rawFolder = "data/save/" + (df::global::world->save_dir) + "/raw/"; auto i = table.find(event); if ( i != table.end() ) { @@ -2167,9 +2167,9 @@ void Core::onStateChange(color_ostream &out, state_change_event event) case SC_WORLD_UNLOADED: case SC_MAP_LOADED: case SC_MAP_UNLOADED: - if (world && world->cur_savegame.save_dir.size()) + if (world && world->save_dir.size()) { - std::string save_dir = "data/save/" + world->cur_savegame.save_dir; + std::string save_dir = "data/save/" + world->save_dir; std::string evtlogpath = save_dir + "/events-dfhack.log"; std::ofstream evtlog; evtlog.open(evtlogpath, std::ios_base::app); // append @@ -2187,7 +2187,7 @@ void Core::onStateChange(color_ostream &out, state_change_event event) evtlog << timebuf; evtlog << "DFHack " << Version::git_description() << " on " << ostype << "; "; evtlog << "cwd md5: " << md5w.getHashFromString(getHackPath()).substr(0, 10) << "; "; - evtlog << "save: " << world->cur_savegame.save_dir << "; "; + evtlog << "save: " << world->save_dir << "; "; evtlog << sc_event_name(event) << "; "; if (gametype) evtlog << "game type " << ENUM_KEY_STR(game_type, *gametype) << " (" << *gametype << ")"; diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index 008cb00c2..b44f309c3 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -319,7 +319,7 @@ static int yield_helper(lua_State *S) } namespace { - int dfhack_lineedit_cont(lua_State *L, int status, int) + int dfhack_lineedit_cont(lua_State *L, int status, lua_KContext) { if (Lua::IsSuccess(status)) return lua_gettop(L) - 2; @@ -636,7 +636,7 @@ static bool do_finish_pcall(lua_State *L, bool success, int base = 1, int space } namespace { - int safecall_cont(lua_State *L, int status, int) + int safecall_cont(lua_State *L, int status, lua_KContext) { bool success = do_finish_pcall(L, Lua::IsSuccess(status)); @@ -1138,7 +1138,7 @@ static bool do_invoke_cleanup(lua_State *L, int nargs, int errorfun, bool succes return success; } -int dfhack_cleanup_cont(lua_State *L, int status, int) +int dfhack_cleanup_cont(lua_State *L, int status, lua_KContext) { bool success = Lua::IsSuccess(status); @@ -1246,6 +1246,11 @@ static int dfhack_open_plugin(lua_State *L) return 0; } +static int gettop_wrapper(lua_State *L, int, lua_KContext) +{ + return lua_gettop(L); +} + static int dfhack_curry_wrap(lua_State *L) { int nargs = lua_gettop(L); @@ -1261,7 +1266,7 @@ static int dfhack_curry_wrap(lua_State *L) for (int i = 1; i <= ncurry; i++) lua_copy(L, lua_upvalueindex(i+1), i); - lua_callk(L, scount-1, LUA_MULTRET, 0, lua_gettop); + lua_callk(L, scount-1, LUA_MULTRET, 0, gettop_wrapper); return lua_gettop(L); } diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index fa9445a81..e8d07dc2f 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -305,7 +305,7 @@ void container_identity::lua_item_write(lua_State *state, int fname_idx, void *p id->lua_write(state, fname_idx, pitem, val_index); } -bool container_identity::lua_insert(lua_State *state, int fname_idx, void *ptr, int idx, int val_index) +bool container_identity::lua_insert2(lua_State *state, int fname_idx, void *ptr, int idx, int val_index) { auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID); @@ -351,7 +351,7 @@ void ptr_container_identity::lua_item_write(lua_State *state, int fname_idx, voi df::pointer_identity::lua_write(state, fname_idx, pitem, id, val_index); } -bool ptr_container_identity::lua_insert(lua_State *state, int fname_idx, void *ptr, int idx, int val_index) +bool ptr_container_identity::lua_insert2(lua_State *state, int fname_idx, void *ptr, int idx, int val_index) { auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID); @@ -887,7 +887,7 @@ static int method_container_insert(lua_State *state) int len = id->lua_item_count(state, ptr, container_identity::COUNT_LEN); int idx = check_container_index(state, len, UPVAL_METHOD_NAME, 2, "call", true); - if (!id->lua_insert(state, UPVAL_METHOD_NAME, ptr, idx, 3)) + if (!id->lua_insert2(state, UPVAL_METHOD_NAME, ptr, idx, 3)) field_error(state, UPVAL_METHOD_NAME, "not supported", "call"); return 0; } diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp index 77374ea0c..909ad9133 100644 --- a/library/RemoteTools.cpp +++ b/library/RemoteTools.cpp @@ -386,7 +386,7 @@ static command_result GetWorldInfo(color_ostream &stream, if (df::global::gametype) gt = *df::global::gametype; - out->set_save_dir(world->cur_savegame.save_dir); + out->set_save_dir(world->save_dir); if (world->world_data->name.has_name) describeName(out->mutable_world_name(), &world->world_data->name); diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index c94129f9b..10c905df3 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -132,7 +132,7 @@ namespace DFHack virtual bool erase(void *ptr, int index) { return false; } virtual bool insert(void *ptr, int index, void *pitem) { return false; } - virtual bool lua_insert(lua_State *state, int fname_idx, void *ptr, int idx, int val_index); + virtual bool lua_insert2(lua_State *state, int fname_idx, void *ptr, int idx, int val_index); protected: virtual int item_count(void *ptr, CountMode cnt) = 0; @@ -153,7 +153,7 @@ namespace DFHack virtual void lua_item_read(lua_State *state, int fname_idx, void *ptr, int idx); virtual void lua_item_write(lua_State *state, int fname_idx, void *ptr, int idx, int val_index); - virtual bool lua_insert(lua_State *state, int fname_idx, void *ptr, int idx, int val_index); + virtual bool lua_insert2(lua_State *state, int fname_idx, void *ptr, int idx, int val_index); }; class DFHACK_EXPORT bit_container_identity : public container_identity { diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index a36459d68..ae35cb52b 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -182,11 +182,9 @@ namespace DFHack {namespace Lua { } // Internal helper - template - int TailPCallK_Thunk(lua_State *state) { - int tmp; - int rv = lua_getctx(state, &tmp); - return cb(state, rv, tmp); + template + int TailPCallK_Thunk(lua_State *state, int rv, lua_KContext ctx) { + return cb(state, rv, ctx); } /** @@ -194,9 +192,9 @@ namespace DFHack {namespace Lua { * specifically, the callback is called with the same kind of arguments * in both yield and non-yield case. */ - template + template int TailPCallK(lua_State *state, int narg, int nret, int errfun, int ctx) { - int rv = lua_pcallk(state, narg, nret, errfun, ctx, &TailPCallK_Thunk); + int rv = lua_pcallk(state, narg, nret, errfun, ctx, cb); return cb(state, rv, ctx); } diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 900607c08..f535d25ad 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -606,7 +606,7 @@ end function dfhack.getSavePath() if dfhack.isWorldLoaded() then - return dfhack.getDFPath() .. '/data/save/' .. df.global.world.cur_savegame.save_dir + return dfhack.getDFPath() .. '/data/save/' .. df.global.world.save_dir end end diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua index afee78aee..87e2ad58c 100644 --- a/library/lua/memscan.lua +++ b/library/lua/memscan.lua @@ -155,6 +155,8 @@ function MemoryArea.new(astart, aend) uint16_t = CheckedArray.new('uint16_t',astart,aend), int32_t = CheckedArray.new('int32_t',astart,aend), uint32_t = CheckedArray.new('uint32_t',astart,aend), + int64_t = CheckedArray.new('int64_t',astart,aend), + uint64_t = CheckedArray.new('uint64_t',astart,aend), float = CheckedArray.new('float',astart,aend) } setmetatable(obj, MemoryArea) @@ -321,7 +323,7 @@ end -- Validation function is_valid_vector(ref,size) - local ints = df.reinterpret_cast('uint32_t', ref) + local ints = df.reinterpret_cast('uint64_t', ref) return ints[0] <= ints[1] and ints[1] <= ints[2] and (size == nil or (ints[1] - ints[0]) % size == 0) end diff --git a/library/modules/World.cpp b/library/modules/World.cpp index 3be400515..fcf516f4e 100644 --- a/library/modules/World.cpp +++ b/library/modules/World.cpp @@ -151,7 +151,7 @@ void World::SetCurrentWeather(uint8_t weather) string World::ReadWorldFolder() { - return world->cur_savegame.save_dir; + return world->save_dir; } bool World::isFortressMode(df::game_type t) diff --git a/library/xml b/library/xml index 7d312334c..369dfdd86 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 7d312334c320022cd6275cddcdb8a64d4ed8d722 +Subproject commit 369dfdd862da961c74d35174cb55fed3d96a29c0 diff --git a/plugins/eventful.cpp b/plugins/eventful.cpp index 45b94510c..14f1ec26e 100644 --- a/plugins/eventful.cpp +++ b/plugins/eventful.cpp @@ -158,12 +158,12 @@ void ev_mng_jobCompleted(color_ostream& out, void* job) } void ev_mng_unitDeath(color_ostream& out, void* ptr) { - int32_t myId=int32_t(ptr); + int32_t myId=*(int32_t*)&ptr; onUnitDeath(out,myId); } void ev_mng_itemCreate(color_ostream& out, void* ptr) { - int32_t myId=int32_t(ptr); + int32_t myId=*(int32_t*)&ptr; onItemCreated(out,myId); } void ev_mng_construction(color_ostream& out, void* ptr) @@ -178,12 +178,12 @@ void ev_mng_syndrome(color_ostream& out, void* ptr) } void ev_mng_invasion(color_ostream& out, void* ptr) { - int32_t myId=int32_t(ptr); + int32_t myId=*(int32_t*)&ptr; onInvasion(out,myId); } static void ev_mng_building(color_ostream& out, void* ptr) { - int32_t myId=int32_t(ptr); + int32_t myId=*(int32_t*)&ptr; onBuildingCreatedDestroyed(out,myId); } static void ev_mng_inventory(color_ostream& out, void* ptr) @@ -204,7 +204,7 @@ static void ev_mng_inventory(color_ostream& out, void* ptr) onInventoryChange(out,unitId,itemId,item_old,item_new); } static void ev_mng_report(color_ostream& out, void* ptr) { - onReport(out,(int32_t)ptr); + onReport(out,*(int32_t*)&ptr); } static void ev_mng_unitAttack(color_ostream& out, void* ptr) { EventManager::UnitAttackData* data = (EventManager::UnitAttackData*)ptr; diff --git a/plugins/isoworldremote.cpp b/plugins/isoworldremote.cpp index 017fb45f6..bd3433b27 100644 --- a/plugins/isoworldremote.cpp +++ b/plugins/isoworldremote.cpp @@ -198,7 +198,7 @@ static command_result GetEmbarkInfo(color_ostream &stream, const MapRequest *in, return CR_OK; } if (in->has_save_folder()) { //If no save folder is given, it means we don't care. - if (!(in->save_folder() == world->cur_savegame.save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them. + if (!(in->save_folder() == world->save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them. out->set_available(false); return CR_OK; } @@ -345,7 +345,7 @@ static command_result GetRawNames(color_ostream &stream, const MapRequest *in, R return CR_OK; } if (in->has_save_folder()) { //If no save folder is given, it means we don't care. - if (!(in->save_folder() == world->cur_savegame.save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them. + if (!(in->save_folder() == world->save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them. out->set_available(false); return CR_OK; } diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 7a853db82..e210b7d50 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1576,7 +1576,7 @@ static command_result GetMapInfo(color_ostream &stream, const EmptyMessage *in, out->set_block_pos_z(pos_z); out->set_world_name(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, false))); out->set_world_name_english(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, true))); - out->set_save_name(df::global::world->cur_savegame.save_dir); + out->set_save_name(df::global::world->save_dir); return CR_OK; } diff --git a/plugins/rendermax/renderer_light.cpp b/plugins/rendermax/renderer_light.cpp index 5e6f2e2de..716f3d0b6 100644 --- a/plugins/rendermax/renderer_light.cpp +++ b/plugins/rendermax/renderer_light.cpp @@ -1172,9 +1172,9 @@ void lightingEngineViewscreen::defaultSettings() void lightingEngineViewscreen::loadSettings() { std::string rawFolder; - if(df::global::world->cur_savegame.save_dir!="") + if(df::global::world->save_dir!="") { - rawFolder= "data/save/" + (df::global::world->cur_savegame.save_dir) + "/raw/"; + rawFolder= "data/save/" + (df::global::world->save_dir) + "/raw/"; } else { From 99dbf20c08251e6117349c30ae1a6022d96b6dd8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 27 Jul 2016 19:34:24 -0400 Subject: [PATCH 044/413] Reorganize win32 build scripts --- build/{ => win32}/build-debug.bat | 0 build/{ => win32}/build-release.bat | 0 build/{ => win32}/generate-MSVC-all-breakfast.bat | 0 build/{ => win32}/generate-MSVC-all.bat | 0 build/{ => win32}/generate-MSVC-gui.bat | 0 build/{ => win32}/generate-MSVC-minimal.bat | 0 build/{ => win32}/generate-MSVC-release.bat | 0 build/{ => win32}/install-debug.bat | 0 build/{ => win32}/install-release.bat | 0 build/{ => win32}/package-debug.bat | 0 build/{ => win32}/package-release.bat | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename build/{ => win32}/build-debug.bat (100%) rename build/{ => win32}/build-release.bat (100%) rename build/{ => win32}/generate-MSVC-all-breakfast.bat (100%) rename build/{ => win32}/generate-MSVC-all.bat (100%) rename build/{ => win32}/generate-MSVC-gui.bat (100%) rename build/{ => win32}/generate-MSVC-minimal.bat (100%) rename build/{ => win32}/generate-MSVC-release.bat (100%) rename build/{ => win32}/install-debug.bat (100%) rename build/{ => win32}/install-release.bat (100%) rename build/{ => win32}/package-debug.bat (100%) rename build/{ => win32}/package-release.bat (100%) diff --git a/build/build-debug.bat b/build/win32/build-debug.bat similarity index 100% rename from build/build-debug.bat rename to build/win32/build-debug.bat diff --git a/build/build-release.bat b/build/win32/build-release.bat similarity index 100% rename from build/build-release.bat rename to build/win32/build-release.bat diff --git a/build/generate-MSVC-all-breakfast.bat b/build/win32/generate-MSVC-all-breakfast.bat similarity index 100% rename from build/generate-MSVC-all-breakfast.bat rename to build/win32/generate-MSVC-all-breakfast.bat diff --git a/build/generate-MSVC-all.bat b/build/win32/generate-MSVC-all.bat similarity index 100% rename from build/generate-MSVC-all.bat rename to build/win32/generate-MSVC-all.bat diff --git a/build/generate-MSVC-gui.bat b/build/win32/generate-MSVC-gui.bat similarity index 100% rename from build/generate-MSVC-gui.bat rename to build/win32/generate-MSVC-gui.bat diff --git a/build/generate-MSVC-minimal.bat b/build/win32/generate-MSVC-minimal.bat similarity index 100% rename from build/generate-MSVC-minimal.bat rename to build/win32/generate-MSVC-minimal.bat diff --git a/build/generate-MSVC-release.bat b/build/win32/generate-MSVC-release.bat similarity index 100% rename from build/generate-MSVC-release.bat rename to build/win32/generate-MSVC-release.bat diff --git a/build/install-debug.bat b/build/win32/install-debug.bat similarity index 100% rename from build/install-debug.bat rename to build/win32/install-debug.bat diff --git a/build/install-release.bat b/build/win32/install-release.bat similarity index 100% rename from build/install-release.bat rename to build/win32/install-release.bat diff --git a/build/package-debug.bat b/build/win32/package-debug.bat similarity index 100% rename from build/package-debug.bat rename to build/win32/package-debug.bat diff --git a/build/package-release.bat b/build/win32/package-release.bat similarity index 100% rename from build/package-release.bat rename to build/win32/package-release.bat From 709111ea338fbf6d8da0b56b244bd0749e8c7048 Mon Sep 17 00:00:00 2001 From: Vitaly Pronkin Date: Wed, 27 Jul 2016 19:35:51 -0400 Subject: [PATCH 045/413] Add win64 build scripts --- build/win64/build-debug.bat | 4 ++++ build/win64/build-release.bat | 5 +++++ build/win64/generate-MSVC-all-breakfast.bat | 9 +++++++++ build/win64/generate-MSVC-all.bat | 6 ++++++ build/win64/generate-MSVC-gui.bat | 7 +++++++ build/win64/generate-MSVC-minimal.bat | 6 ++++++ build/win64/generate-MSVC-release.bat | 6 ++++++ build/win64/install-debug.bat | 4 ++++ build/win64/install-release.bat | 4 ++++ build/win64/package-debug.bat | 6 ++++++ build/win64/package-release.bat | 5 +++++ 11 files changed, 62 insertions(+) create mode 100644 build/win64/build-debug.bat create mode 100644 build/win64/build-release.bat create mode 100644 build/win64/generate-MSVC-all-breakfast.bat create mode 100755 build/win64/generate-MSVC-all.bat create mode 100755 build/win64/generate-MSVC-gui.bat create mode 100755 build/win64/generate-MSVC-minimal.bat create mode 100755 build/win64/generate-MSVC-release.bat create mode 100644 build/win64/install-debug.bat create mode 100644 build/win64/install-release.bat create mode 100644 build/win64/package-debug.bat create mode 100644 build/win64/package-release.bat diff --git a/build/win64/build-debug.bat b/build/win64/build-debug.bat new file mode 100644 index 000000000..f53df9063 --- /dev/null +++ b/build/win64/build-debug.bat @@ -0,0 +1,4 @@ +call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 +cd VC2015 +msbuild /m /p:Platform=x64 /p:Configuration=RelWithDebInfo ALL_BUILD.vcxproj +cd .. \ No newline at end of file diff --git a/build/win64/build-release.bat b/build/win64/build-release.bat new file mode 100644 index 000000000..551e27b69 --- /dev/null +++ b/build/win64/build-release.bat @@ -0,0 +1,5 @@ +call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 +cd VC2015 +msbuild /m /p:Platform=x64 /p:Configuration=Release ALL_BUILD.vcxproj +cd .. +pause \ No newline at end of file diff --git a/build/win64/generate-MSVC-all-breakfast.bat b/build/win64/generate-MSVC-all-breakfast.bat new file mode 100644 index 000000000..edf540f48 --- /dev/null +++ b/build/win64/generate-MSVC-all-breakfast.bat @@ -0,0 +1,9 @@ +@echo off +IF EXIST DF_PATH.txt SET /P _DF_PATH= Date: Wed, 27 Jul 2016 19:46:49 -0400 Subject: [PATCH 046/413] win64 fixes (partial) cherry-picked from 2f734ae2317060edb83021f17cffc966c435ad7b --- CMakeLists.txt | 5 +++-- depends/lua/src/lobject.c | 4 ++-- depends/tthread/fast_mutex.h | 2 +- library/DataStaticsFields.cpp | 5 +++++ library/Hooks-windows.cpp | 20 ++++++++++++++++++++ library/VTableInterpose.cpp | 6 +++++- library/include/DataIdentity.h | 5 +++++ library/include/VersionInfo.h | 2 +- plugins/CMakeLists.txt | 2 +- 9 files changed, 43 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 291fab324..de8c48846 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,8 +48,8 @@ if(UNIX) endif() if(WIN32) - if((NOT MSVC) OR (NOT MSVC_VERSION STREQUAL 1600)) - message(SEND_ERROR "MSVC 2010 is required") + if((NOT MSVC) OR (NOT MSVC_VERSION STREQUAL 1900)) + message(SEND_ERROR "MSVC 2015 is required") endif() endif() @@ -177,6 +177,7 @@ ELSEIF(MSVC) # for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /vmm /MP") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od") + ADD_DEFINITIONS(-D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS) ENDIF() # use shared libraries for protobuf diff --git a/depends/lua/src/lobject.c b/depends/lua/src/lobject.c index a44b3850f..0c6e7a9e7 100644 --- a/depends/lua/src/lobject.c +++ b/depends/lua/src/lobject.c @@ -280,7 +280,7 @@ static const char *l_str2d (const char *s, lua_Number *result) { endptr = l_str2dloc(s, result, mode); /* try to convert */ if (endptr == NULL) { /* failed? may be a different locale */ char buff[L_MAXLENNUM + 1]; - char *pdot = strchr(s, '.'); + char *pdot = (char*)strchr(s, '.'); if (strlen(s) > L_MAXLENNUM || pdot == NULL) return NULL; /* string too long or no dot; fail */ strcpy(buff, s); /* copy string to buffer */ @@ -394,7 +394,7 @@ static void pushstr (lua_State *L, const char *str, size_t l) { /* -** this function handles only '%d', '%c', '%f', '%p', and '%s' +** this function handles only '%d', '%c', '%f', '%p', and '%s' conventional formats, plus Lua-specific '%I' and '%U' */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { diff --git a/depends/tthread/fast_mutex.h b/depends/tthread/fast_mutex.h index 6627408e4..a381b2c75 100644 --- a/depends/tthread/fast_mutex.h +++ b/depends/tthread/fast_mutex.h @@ -39,7 +39,7 @@ freely, subject to the following restrictions: // Check if we can support the assembly language level implementation (otherwise // revert to the system API) #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \ - (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || \ + (defined(_MSC_VER) && (defined(_M_IX86) /*|| defined(_M_X64)*/)) || \ (defined(__GNUC__) && (defined(__ppc__))) #define _FAST_MUTEX_ASM_ #else diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index 96f91dd66..9115784d7 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -30,8 +30,13 @@ namespace df { NUMBER_IDENTITY_TRAITS(uint32_t); NUMBER_IDENTITY_TRAITS(int64_t); NUMBER_IDENTITY_TRAITS(uint64_t); +#ifdef _WIN32 + NUMBER_IDENTITY_TRAITS(long); + NUMBER_IDENTITY_TRAITS(unsigned long); +#else NUMBER_IDENTITY_TRAITS(intptr_t); NUMBER_IDENTITY_TRAITS(uintptr_t); +#endif NUMBER_IDENTITY_TRAITS(float); NUMBER_IDENTITY_TRAITS(double); diff --git a/library/Hooks-windows.cpp b/library/Hooks-windows.cpp index 7ea1385a7..3d925bc27 100644 --- a/library/Hooks-windows.cpp +++ b/library/Hooks-windows.cpp @@ -726,6 +726,22 @@ DFhackCExport uint32_t SDL_ThreadID(void) return _SDL_ThreadID(); } +static char* (*_SDL_getenv)(const char *name) = 0; +DFhackCExport char* SDL_getenv(const char *name) +{ + if(!inited) + FirstCall(); + return _SDL_getenv(name); +} + +static size_t (*_SDL_strlcat)(char *dst, const char *src, size_t maxlen) = 0; +DFhackCExport size_t SDL_strlcat(char *dst, const char *src, size_t maxlen) +{ + if(!inited) + FirstCall(); + return _SDL_strlcat(dst, src, maxlen); +} + // FIXME: this has to be thread-safe. bool FirstCall() { @@ -813,6 +829,10 @@ bool FirstCall() _SDL_SemWait = (int (*)(void *))GetProcAddress(realSDLlib,"SDL_SemWait"); _SDL_ThreadID = (uint32_t (*)(void))GetProcAddress(realSDLlib,"SDL_ThreadID"); + // new in DF 0.43.05 + _SDL_getenv = (char* (*)(const char*))GetProcAddress(realSDLlib,"SDL_getenv"); + _SDL_strlcat = (size_t (*)(char*, const char*, size_t))GetProcAddress(realSDLlib,"SDL_strlcat"); + _SDL_EnableUNICODE(1); fprintf(stderr,"Initized HOOKS!\n"); diff --git a/library/VTableInterpose.cpp b/library/VTableInterpose.cpp index d81c6d730..63edb2205 100644 --- a/library/VTableInterpose.cpp +++ b/library/VTableInterpose.cpp @@ -82,7 +82,7 @@ using namespace DFHack; // multiple, but not virtual inheritance. struct MSVC_MPTR { void *method; - intptr_t this_shift; + uint32_t this_shift; // was intptr_t pre-0.43.05 }; // Debug builds sometimes use additional thunks that @@ -97,7 +97,11 @@ static uint32_t *follow_jmp(void *ptr) switch (*p) { case 0xE9: // jmp near rel32 +#ifdef DFHACK64 + p += 5 + *(int32_t*)(p+1) + 1; +#else p += 5 + *(int32_t*)(p+1); +#endif break; case 0xEB: // jmp short rel8 p += 2 + *(int8_t*)(p+1); diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index 10c905df3..32bbf0d5d 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -487,8 +487,13 @@ namespace df NUMBER_IDENTITY_TRAITS(uint32_t); NUMBER_IDENTITY_TRAITS(int64_t); NUMBER_IDENTITY_TRAITS(uint64_t); +#ifdef _WIN32 + NUMBER_IDENTITY_TRAITS(long); + NUMBER_IDENTITY_TRAITS(unsigned long); +#else NUMBER_IDENTITY_TRAITS(intptr_t); NUMBER_IDENTITY_TRAITS(uintptr_t); +#endif NUMBER_IDENTITY_TRAITS(float); NUMBER_IDENTITY_TRAITS(double); diff --git a/library/include/VersionInfo.h b/library/include/VersionInfo.h index 58ecb2c28..b3d6c8346 100644 --- a/library/include/VersionInfo.h +++ b/library/include/VersionInfo.h @@ -53,7 +53,7 @@ namespace DFHack std::map Addresses; std::map VTables; uintptr_t base; - int rebase_delta; + uintptr_t rebase_delta; std::string version; OSType OS; public: diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index c24b940b9..46c4b8054 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -91,7 +91,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(deramp deramp.cpp) DFHACK_PLUGIN(dig dig.cpp) DFHACK_PLUGIN(digFlood digFlood.cpp) - add_subdirectory(diggingInvaders) + # add_subdirectory(diggingInvaders) DFHACK_PLUGIN(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(embark-tools embark-tools.cpp) DFHACK_PLUGIN(eventful eventful.cpp LINK_LIBRARIES lua) From 50144b60eab967687e6b382bd84e64b6cf61ca3b Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 27 Jul 2016 19:54:19 -0400 Subject: [PATCH 047/413] A few %08x to %p changes --- library/Process-darwin.cpp | 2 +- library/VTableInterpose.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Process-darwin.cpp b/library/Process-darwin.cpp index 95c347368..d6988d5d6 100644 --- a/library/Process-darwin.cpp +++ b/library/Process-darwin.cpp @@ -207,7 +207,7 @@ void Process::getMemRanges( vector & ranges ) if (log_ranges) { fprintf(stderr, - "%08x-%08x %8uK %c%c%c/%c%c%c %11s %6s %10s uwir=%hu sub=%u dlname: %s\n", + "%p-%p %8uK %c%c%c/%c%c%c %11s %6s %10s uwir=%hu sub=%u dlname: %s\n", address, (address + vmsize), (vmsize >> 10), (info.protection & VM_PROT_READ) ? 'r' : '-', (info.protection & VM_PROT_WRITE) ? 'w' : '-', diff --git a/library/VTableInterpose.cpp b/library/VTableInterpose.cpp index 63edb2205..96cbfff9c 100644 --- a/library/VTableInterpose.cpp +++ b/library/VTableInterpose.cpp @@ -308,7 +308,7 @@ VMethodInterposeLinkBase::VMethodInterposeLinkBase(virtual_identity *host, int v * - interpose_method comes from method_pointer_to_addr_ */ - fprintf(stderr, "Bad VMethodInterposeLinkBase arguments: %d %08x (%s)\n", + fprintf(stderr, "Bad VMethodInterposeLinkBase arguments: %d %p (%s)\n", vmethod_idx, uintptr_t(interpose_method), name_str); fflush(stderr); abort(); From ddd56d7825f121deac70cd89676a1bf6d445067e Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 27 Jul 2016 20:10:03 -0400 Subject: [PATCH 048/413] Fix (for win64) and avoid duplicating base address --- library/Process-darwin.cpp | 3 ++- library/Process-linux.cpp | 3 ++- library/Process-windows.cpp | 3 ++- library/VersionInfoFactory.cpp | 8 ++------ library/include/Memory.h | 22 ++++++++++++++++++++++ 5 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 library/include/Memory.h diff --git a/library/Process-darwin.cpp b/library/Process-darwin.cpp index d6988d5d6..69defbf92 100644 --- a/library/Process-darwin.cpp +++ b/library/Process-darwin.cpp @@ -41,6 +41,7 @@ using namespace std; #include #include "MemAccess.h" +#include "Memory.h" #include "VersionInfoFactory.h" #include "VersionInfo.h" #include "Error.h" @@ -241,7 +242,7 @@ void Process::getMemRanges( vector & ranges ) uintptr_t Process::getBase() { - return 0x1000; + return DEFAULT_BASE_ADDR; // Memory.h } int Process::adjustOffset(int offset, bool /*to_file*/) diff --git a/library/Process-linux.cpp b/library/Process-linux.cpp index 14c70a802..7a72171ca 100644 --- a/library/Process-linux.cpp +++ b/library/Process-linux.cpp @@ -39,6 +39,7 @@ using namespace std; #include #include "MemAccess.h" +#include "Memory.h" #include "VersionInfoFactory.h" #include "VersionInfo.h" #include "Error.h" @@ -167,7 +168,7 @@ void Process::getMemRanges( vector & ranges ) uintptr_t Process::getBase() { - return 0x8048000; + return DEFAULT_BASE_ADDR; // Memory.h } int Process::adjustOffset(int offset, bool /*to_file*/) diff --git a/library/Process-windows.cpp b/library/Process-windows.cpp index 5474d7cfb..b9e58462b 100644 --- a/library/Process-windows.cpp +++ b/library/Process-windows.cpp @@ -43,6 +43,7 @@ using namespace std; #include "VersionInfoFactory.h" #include "Error.h" #include "MemAccess.h" +#include "Memory.h" using namespace DFHack; namespace DFHack { @@ -306,7 +307,7 @@ uintptr_t Process::getBase() { if(d) return (uintptr_t) d->base; - return 0x400000; + return DEFAULT_BASE_ADDR; // Memory.h } int Process::adjustOffset(int offset, bool to_file) diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index 02dac568c..672f5a9c8 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -34,6 +34,7 @@ using namespace std; #include "VersionInfoFactory.h" #include "VersionInfo.h" #include "Error.h" +#include "Memory.h" using namespace DFHack; #include @@ -98,25 +99,20 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem) if(os == "windows") { mem->setOS(OS_WINDOWS); - // set default image base. this is fixed for base relocation later - mem->setBase(0x400000); } else if(os == "linux") { mem->setOS(OS_LINUX); - // this is wrong... I'm not going to do base image relocation on linux though. - mem->setBase(0x8048000); } else if(os == "darwin") { mem->setOS(OS_APPLE); - // this is wrong... I'm not going to do base image relocation on linux though. - mem->setBase(0x1000); } else { return; // ignore it if it's invalid } + mem->setBase(DEFAULT_BASE_ADDR); // Memory.h // process additional entries //cout << "Entry " << cstr_version << " " << cstr_os << endl; diff --git a/library/include/Memory.h b/library/include/Memory.h new file mode 100644 index 000000000..1016f2966 --- /dev/null +++ b/library/include/Memory.h @@ -0,0 +1,22 @@ +// Default base address +#if defined(_WIN32) + #ifdef DFHACK64 + #define DEFAULT_BASE_ADDR 0x140000000 + #else + #define DEFAULT_BASE_ADDR 0x400000 + #endif +#elif defined(_DARWIN) + #ifdef DFHACK64 + #define DEFAULT_BASE_ADDR 0x1000 + #else + #define DEFAULT_BASE_ADDR 0x1000 + #endif +#elif defined(_LINUX) + #ifdef DFHACK64 + #define DEFAULT_BASE_ADDR 0x8048000 + #else + #define DEFAULT_BASE_ADDR 0x8048000 + #endif +#else + #error Unknown OS +#endif From 223c83071e9b72d59590a869043de25cec3db6b5 Mon Sep 17 00:00:00 2001 From: Vitaly Pronkin Date: Wed, 27 Jul 2016 20:21:57 -0400 Subject: [PATCH 049/413] win64 fixes: doReadClassName, ParseVersion cherry-picked from 2f734ae2317060edb83021f17cffc966c435ad7b --- library/Process-windows.cpp | 9 ++++++++- library/VersionInfoFactory.cpp | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/library/Process-windows.cpp b/library/Process-windows.cpp index b9e58462b..cb2e16bd2 100644 --- a/library/Process-windows.cpp +++ b/library/Process-windows.cpp @@ -345,9 +345,16 @@ int Process::adjustOffset(int offset, bool to_file) string Process::doReadClassName (void * vptr) { - char * rtti = readPtr((char *)vptr - 0x4); + char * rtti = readPtr((char *)vptr - sizeof(void*)); +#ifdef DFHACK64 + char * typeinfo = d->base + readDWord(rtti + 0xC); + string raw = readCString(typeinfo + 0x10+4); // skips the .?AV +#else char * typeinfo = readPtr(rtti + 0xC); string raw = readCString(typeinfo + 0xC); // skips the .?AV +#endif + if (!raw.length()) + return "dummy"; raw.resize(raw.length() - 2);// trim @@ from end return raw; } diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index 672f5a9c8..707c2809f 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -136,7 +136,11 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem) } if ((is_vtable && no_vtables) || (!is_vtable && no_globals)) continue; +#ifdef DFHACK64 + uintptr_t addr = strtoull(cstr_value, 0, 0); +#else uintptr_t addr = strtol(cstr_value, 0, 0); +#endif if (is_vtable) mem->setVTable(cstr_key, addr); else From 828fee532a381ddde181edd7ef4380308b8126b7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 27 Jul 2016 21:08:24 -0400 Subject: [PATCH 050/413] Switch to downloading zlib.lib and SDLreal.dll on Windows --- CMakeLists.txt | 48 ++++++++++++++++++++++++++++-- depends/zlib/lib/win32/.gitignore | 1 + depends/zlib/lib/win64/.gitignore | 1 + depends/zlib/lib/zlib.lib | Bin 108064 -> 0 bytes library/CMakeLists.txt | 2 +- package/windows/SDLreal.dll | Bin 321536 -> 0 bytes package/windows/win32/.gitignore | 1 + package/windows/win64/.gitignore | 1 + 8 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 depends/zlib/lib/win32/.gitignore create mode 100644 depends/zlib/lib/win64/.gitignore delete mode 100644 depends/zlib/lib/zlib.lib delete mode 100644 package/windows/SDLreal.dll create mode 100644 package/windows/win32/.gitignore create mode 100644 package/windows/win64/.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index de8c48846..1055ee623 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,12 +195,56 @@ endif() #### expose depends #### +if(WIN32) + # Download zlib on Windows + set(ZLIB_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/depends/zlib/lib/win${DFHACK_BUILD_ARCH}) + if(NOT EXISTS ${ZLIB_DOWNLOAD_DIR}/zlib.lib) + if(${DFHACK_BUILD_ARCH} STREQUAL "64") + message("Downloading win64-zlib.lib") + file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win64-zlib.lib" + ${ZLIB_DOWNLOAD_DIR}/zlib.lib + EXPECTED_MD5 "a3b2fc6b68efafa89b0882e354fc8418") + else() + message("Downloading win32-zlib.lib") + file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-zlib.lib" + ${ZLIB_DOWNLOAD_DIR}/zlib.lib + EXPECTED_MD5 "f4ebaa21d9de28566e88b1edfcdff901") + endif() + endif() + # Move zlib to the build folder so possible 32 and 64-bit builds + # in the same source tree don't conflict + file(COPY ${CMAKE_SOURCE_DIR}/depends/zlib + DESTINATION ${CMAKE_BINARY_DIR}/depends/) + file(COPY ${ZLIB_DOWNLOAD_DIR}/zlib.lib + DESTINATION ${CMAKE_BINARY_DIR}/depends/zlib/lib/) + + + # Do the same for SDLreal.dll + # (DFHack doesn't require this at build time, so no need to move it to the build folder) + set(SDLREAL_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/package/windows/win${DFHACK_BUILD_ARCH}) + if(NOT EXISTS ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll) + if(${DFHACK_BUILD_ARCH} STREQUAL "64") + message("Downloading win64-SDL.dll") + file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win64-SDL.dll" + ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll + EXPECTED_MD5 "1ae242c4b94cb03756a1288122a66faf") + else() + message("Downloading win32-SDL.dll") + file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-SDL.dll" + ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll + EXPECTED_MD5 "5a09604daca6b2b5ce049d79af935d6a") + endif() + endif() +endif() + # find and make available libz -if(NOT UNIX) - SET(ZLIB_ROOT depends/zlib/) +if(NOT UNIX) # Windows + # zlib is in here so 32-bit and 64-bit builds in the same source tree are possible + SET(ZLIB_ROOT ${CMAKE_BINARY_DIR}/depends/zlib/) else() set(ZLIB_ROOT /usr/lib/i386-linux-gnu) endif() + find_package(ZLIB REQUIRED) include_directories(depends/protobuf) include_directories(depends/lua/include) diff --git a/depends/zlib/lib/win32/.gitignore b/depends/zlib/lib/win32/.gitignore new file mode 100644 index 000000000..683bf139f --- /dev/null +++ b/depends/zlib/lib/win32/.gitignore @@ -0,0 +1 @@ +*.lib diff --git a/depends/zlib/lib/win64/.gitignore b/depends/zlib/lib/win64/.gitignore new file mode 100644 index 000000000..683bf139f --- /dev/null +++ b/depends/zlib/lib/win64/.gitignore @@ -0,0 +1 @@ +*.lib diff --git a/depends/zlib/lib/zlib.lib b/depends/zlib/lib/zlib.lib deleted file mode 100644 index 51f579dd775795ecc302b52bd47792f8d5e70401..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108064 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 INkiWLKYjs1tpET3 diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index d3e3480ab..b0142a14a 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -376,7 +376,7 @@ IF(UNIX) ELSE() if(NOT BUILD_EGGY) # On windows, copy the renamed SDL so DF can still run. - install(PROGRAMS ${dfhack_SOURCE_DIR}/package/windows/SDLreal.dll + install(PROGRAMS ${dfhack_SOURCE_DIR}/package/windows/win${DFHACK_BUILD_ARCH}/SDLreal.dll DESTINATION ${DFHACK_LIBRARY_DESTINATION}) endif() ENDIF() diff --git a/package/windows/SDLreal.dll b/package/windows/SDLreal.dll deleted file mode 100644 index 3ce97a59deb86e64d75443ff5bbf55a697a501ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 321536 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⁡Y_0|PGD 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�<9il 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 BhV%dc diff --git a/package/windows/win32/.gitignore b/package/windows/win32/.gitignore new file mode 100644 index 000000000..6a7461313 --- /dev/null +++ b/package/windows/win32/.gitignore @@ -0,0 +1 @@ +*.dll diff --git a/package/windows/win64/.gitignore b/package/windows/win64/.gitignore new file mode 100644 index 000000000..6a7461313 --- /dev/null +++ b/package/windows/win64/.gitignore @@ -0,0 +1 @@ +*.dll From 42c620bb9c61fdacac80730d3ac2b262b5e992f6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 27 Jul 2016 21:43:38 -0400 Subject: [PATCH 051/413] Download non-broken libstdc++ on OS X --- CMakeLists.txt | 27 ++++++++++++++++++++++++++- library/CMakeLists.txt | 6 +----- package/darwin/libstdc++.6.dylib.bz2 | Bin 360865 -> 0 bytes package/darwin/osx32/.gitignore | 1 + package/darwin/osx64/.gitignore | 1 + 5 files changed, 29 insertions(+), 6 deletions(-) delete mode 100644 package/darwin/libstdc++.6.dylib.bz2 create mode 100644 package/darwin/osx32/.gitignore create mode 100644 package/darwin/osx64/.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index 1055ee623..a854a74aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,7 +193,7 @@ elseif(WIN32) add_definitions(-DWIN32) endif() -#### expose depends #### +#### download depends #### if(WIN32) # Download zlib on Windows @@ -237,6 +237,31 @@ if(WIN32) endif() endif() +if(APPLE) + # libstdc++ (GCC 4.8.5 for OS X 10.6) + # fixes crash-on-unwind bug in DF's libstdc++ + set(LIBSTDCXX_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/package/darwin/osx${DFHACK_BUILD_ARCH}) + # check for existence of uncompressed library + if(NOT EXISTS ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib) + if(${DFHACK_BUILD_ARCH} STREQUAL "64") + message("Downloading osx64-libstdcxx.6.dylib.gz") + file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/osx64-libstdcxx.6.dylib.gz" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz + EXPECTED_MD5 "cf26ed588be8e83c8e3a49919793b416") + execute_process(COMMAND gunzip ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz) + else() + message("Downloading osx32-libstdcxx.6.dylib.gz") + file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/osx32-libstdcxx.6.dylib.gz" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz + EXPECTED_MD5 "40f3d83871b114f0279240626311621b") + execute_process(COMMAND gunzip ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz) + endif() + endif() +endif() + +#### expose depends #### + + # find and make available libz if(NOT UNIX) # Windows # zlib is in here so 32-bit and 64-bit builds in the same source tree are possible diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index b0142a14a..0958a6efc 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -360,12 +360,8 @@ IF(UNIX) DESTINATION .) install(PROGRAMS ${dfhack_SOURCE_DIR}/package/darwin/dfhack-run DESTINATION .) - OPTION(INSTALL_NEW_LIBSTDCXX "Install a version of libstdc++ from GCC 4.5.4 to fix various crashes" ON) - IF(INSTALL_NEW_LIBSTDCXX) - execute_process(COMMAND bunzip2 --keep --force ${dfhack_SOURCE_DIR}/package/darwin/libstdc++.6.dylib.bz2) - install(PROGRAMS ${dfhack_SOURCE_DIR}/package/darwin/libstdc++.6.dylib + install(PROGRAMS ${dfhack_SOURCE_DIR}/package/darwin/osx${DFHACK_BUILD_ARCH}/libstdc++.6.dylib DESTINATION ./hack/) - ENDIF(INSTALL_NEW_LIBSTDCXX) else() # On linux, copy our version of the df launch script which sets LD_PRELOAD install(PROGRAMS ${dfhack_SOURCE_DIR}/package/linux/dfhack diff --git a/package/darwin/libstdc++.6.dylib.bz2 b/package/darwin/libstdc++.6.dylib.bz2 deleted file mode 100644 index a25b10b26ae833090ea40f1aa61b89fa1d78682d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 360865 zcmafaRZtx~7wy5_p}145KyjCYySo&3DeiV~_ZDq&cZ$2aySv*txXb+ zPbO7e6r5!jb*ns`un9Q0D#`V>(IA8`|rb+|HWJ= zPmYf3LKi1Y#I|X893%|+o6u0@R!@ZGe|e1giD&ct6#iR=hQF&j0AzLmDFUkxASv)kFm?NB6GE(s&QfsWRJ}bC^HaK-3X7tYjd-ASM&Ua?-r!};IX{Q z!?h5m`r)Q)#h0^4z}6dl(a^vA1Hq#z!K*;o|4;jRdDoTjw{2m$bqC=({GRWIKfWiz z0p>3K006+93PTUzJc0LzxWlc@V+*o}aTRwD9D6YcDi@%_36Md0^vvq?0a+`pa$5LY z_|TVdLF@z)XAdLvBJZ`pga~zD%b`3OR)!||h&v)aLChBoGxXa4$a%~xyD@3xa7Y7Hu?*Jr#Mx=3Up|`fD z1@N!}(0n-kS77`@=9Fe17aTl2Hy4&`^v7Pe2%zo&7!&{iK5G*dTajjt-*;tw!T<0> z0XgwOu$q7Vc-E(O;BD-16>N+^F~yw&psHH$MS;kk#{8rcFhBspiXTqUeVFD&bHu_U z|EAD-n0AfN!#WY3WqL0b1uTeccL@Lxf~uW_4~_M1000)6SZ}1avd1YYG{q4$@rzb1C5YhBc4PLemZ(dGMe|JW; zvdt0@JyuhmLUSAaqq`GdC-@3O-${Gr>CC>w>AdODiQJRN9*uKIu(+YYLhjWK1K``X z1HS}SyKX$|xx#g+b@ipzR{)d+u=JT^f%?;nYRp~h-QwjaB(T2q;$mClx+SoM;1B7z z^KE-B^gr|IB3bcm?OSeV=;24vwa3exNwl!FU4bqI08pd35YH$B_+V%i$*6?aJTH8h?L|Ex*;>KS%AS9UVNJ zb=%%x0S8z8EtZ$FEuZFyuGizv3iyrvW}$Cw*VdgaZUQE!XP&03R@M61g6DVw!UpGL zbW=jjC0qVWt|I_An2u+Z9RO@qhW!@+)B*l#!DbHtU{xatJx|PqrIlqV24hbl*_ci> zVQh!ZX+&4|Xjzl?^TK<&%|AFi{CH#7>$0zk;E!JXMl-SD>$H%OajGxc_Rp0kO^2R` zsSb+!b6W@ee)+W9ttN&G3R~y9o_3sfEw*^G$0 zZF|dVh}xq-$jF5dG5{Bl``b_UBEL zL-(_nkOD}K>t*M9Jy@>|*QQ)P%i+RvV}tX&x)a{sx3fLMe>(T|0Fuesx!<3g&~nz$^jhVYapr!?$^j zoc$jG3nApFp%E*_>opxh!&?wCYD;1Q8Y-;x>0(>~f!GNhpPj@=dc+`#NV;0qAYh^l zdmnTV=Bjc1X)on!L|qUf4QVW~u=LXXdeYP>2{!sTJf^RY(?u_$P%U9v0rPL<@+y#Z z6EEy>*E)iraMg*w%Jpf`%zrEZjJIx=&3f_#e7$^>J)3LbwwzvGkof_{%b6$P&^P!4fObKiZtNfi2Usi|sY|rwags>r7VDzS=od@Gc z?$^J!mR|nEJtK(0dibp;WEht4_GA-6M-iIqm{78{xbUmxYyfL(z*3N&^&-)iUP@8j zrWGPK0Gx`DRoHY#5fT~PeZ<77e3!fbqmtv#pH0ioR|Jok;XBq?7)|b{e}MpWP5a#k z<44||A12cOE~UcyR&Z8$ioi6T`!kP-sOkQX?L7c6MF&OX9#VZ`Yl8^@{f|2Uv@xv|wE2t)yD8@kj5zTB_Wi#Gwg(U*1`D7CK?7h% zW&jG%Ho-P|1^-KeHda(Drp>g8Dh|pkkdn$wx1N^`c7PoXHZ@^4Va;Gyznc|e#nB+j zrb48k0Dy34L86JUHlef0=6$HZd6{{-e4A6Y@|+Y(p(MKC;+*hbD;etZBMWBgoC&HY zbV+k=%j(r1$dD@zFgWdM-=+qRHEI5^^>1yXSY zK?SfxXzWCsTta~Vjl;>Bo@oqgJut73X>Dzxyl^*zM#QO@NK2Hfp^8X>2>?P{Th9Ps zM+NV z;`YRl;IwA3j!SA|CNUL)pkXBDrqhkwN;-7>)`okug%B2(FBoM$uB9`RQyNN@^9obC z@vwyi)fVn()E6{-82mL-5h`@a>Tpw5@GeY2-sz|zlO$_u$tY8-Y7#McNSI1)DpWPX zwMwAKJ4#pxCDutQY--1Eis#a%jy$uYx%^ab54tW%>T#ohnq_&)6DADST4hpGy4o_~ z{H|h(2abQi-n_#4xz$VG9TBDm?y$)GC?ftLUG%{(2Lm?5;7=3bcK{hF$*a`Z(?OK5 z(Q>f=)WUg^)HFs#UlGR(X;O`YRoh^FC<;A+n?bq&Pab(6omeqlY`!8mfW91&AC>3x#EjfNCP0%h(;Xj}~-iEA1z|3qUnPhVOt^ z5u&ER$Ixkymu(79!V1YL6KOb<7w-ce?mc4#&8nJiwW#;FeQh?@zY_v=gmp6pM6#5$R%S%Fd)Ko9;#75FhzNuAj-vyJ0VF#SjH3xbp8pw z2dGDhgrZM@!3Dg-5b*!xA4*lD185QSB{3gh^mu^VlMHQo=tBWu)E(&~n4Y*$GL^SK zkFDZ~0{pL=JAsI9@gk3ti4i{cML(pUSL)tH3(IQ^9wG(;cND2)gxP~{NKQqTW&W0< z*#rykaV7DK@HN=ZTKp568DdxAL|~YBpFQipYZC&k+>6aNq3++sX|!o5zec8lymVFD zxCjZ`a`TbxkPj(z4mzS5CLyJ-5^9Ny#`F}25*We=n(Kr^xBI_81w;FZM9;$jo?OO& zG}V`gceYhG36I%tuA0eig*V9pK?A(WUgA*#)a~fAbAdDdy`M;L)=$SL!}c#SA5m9k zyV)APA?+AY?=pcJ*%(FFWFDNiZq58gBvgyhJ$b)Oj;cffs_E=Z+Dxp_sJ#In=lIg4 zEcD3$y*%j#ktvO{#hE3g2rXK+2dTdf`dLC89aDowlVr9RD zDTmYc^Ahj6$1>+tPJadp(N*uG8w*^iR`jLCYCzt3iMB#AF+LrY*ss9}S<=3|Ge;WP3= z@x+H%4v@?pv@;2FE+7A&g#AEAL{Y@2k!vw%B={&=8>|CxNgAAwcm)YmZq#Q>1hLA3 z7O}fpaniAPM!5=ho%y9cc}n4IBu32yT`F8Coi+DU{oIl-pve@`+?v7xRw2RCjusAn zu4y4gx{zPGx*^lp=bVS{SFy^<$_bmSZiu>l;}yGeE5i{QHSICniOYRD(ww@b(v2cg zm7w`+%6riJG0NJVTwvW?$uW6L#U;7teaLG**L_!GixB>0x~#i)OzH=Jy$1UnVbGp^ z;23cE#v>|Q4oZvF!TqTTd5J1W4Jcsa`rQL6%l15OJTCdKuN~2{icJlvwt*vlR0w2D zmv6dmPFAG5nb2m&Od1SM5*rh1Vcaw2HIUgkJiA-NIfFA14SHaW0RLEr77At%jT}Gp zSSB=6^;Bg5Q)t9cF4CAV+V`{f_l4Fhb9APPidzHv{B#vY=+*S#Fn?EK<&HSr2XNCM z!EZm?_ke((9^IQvP-JYmGr(ZSN8XidJ+Guze zyMkwleRR4-=?W31*Mbx39TH{Bz$f90XH~FL()<%yTG6TR$Iw6)>^eiAqhP?pJ>4A8oh4$lxw@V$AK77zG)b`_<5~o@o?s5P`3vIOn2Ew6_q8CK>X4 zEP+*g(IRo~hKQtR-EpE?RK(_~;ssa`X)JPZWY5QBDpoY5u+H8bG^@tGZTg4?&|`)i z13-+apGQ^p7HSTd8Ktny#)!(e?&eB9dQ#3RYCecI88^e?b#rzP3BK-fJG9yi;1a6* zP`wfRc-$7yd;U@RF?k?b%QLdq2k&K5lQSKOpD;ErSAE(Vv{0wn<4#*rt%(K$I-aE?7dxuCcN3gbb3Cv+sd%J<((HvqOKaF#5iR`ldTgXRiSsQncJOO_Urug#O7_({6ij`4Y4tr=xaf|V z{UGcAHODjmQo0rLw*;(%;~-6?(A@Jf_6_$wBOQXi#KhVe^#z{c!Xd=B)3k7$F!WoD z`a6z!_F<*N7eQdN?W_I@#9(mzd~47_09_wmp{{#aDCy^$Zs2;&hN0*`5zz4sFHRq%-Z+QM1(wVMms&FM{9d4|R6b5Yn`U zAR*?@7mE(nd*6+#v`K}{Dq@V@yOynw&T^;5Cq~!io9ikIe(+oRNBhH{)|I_N)Kw3^ z*~$z2((^5FlwwruETV9?6fIdlo&IjDX^=ysL-4QGY2vDy+0aL-NwQ7H^Y;Zz-C50W z+=MI1_`U7F$qoMOX-#tC!K(2SjdpA8hKxDgcZ2_y-*^_{+y+Sj#``Un^Fx#Qk~iMB zu|KKWZ7p)*-9t1M{$9!M{~9aAp!z0Rr_yPgEw(RLEA-Wg{EAv%eNR1jdGPMC8h5gE zlObm{aUlPwM(=+dQJ0WA!M4V?s)K=iC#TubG z_G#gDGP>w9<4Xpa1k=JVU%kk7SMd~1>UN)Su>|{M$B%bmR4aKqO{LYv?@0FBnCBkZ z#}nN#uWsx5kF*FjU$d@jini|}?AS6OI*&+pN$t+1x8Hmt{$V7Z)LBkv89?mLt!7Uf zebT+-+ukZF*PeYzB#(>RJ-2ixdoa>{#ry^HRN=@9)pYRWnlm51nxZh~F+$Mqu8=Q;@!NY5$DbAt`@q{#j#bn>QJOihjX;Lg)IgCd`jvpzL2( zQ6N$qP$+>QTiyq0SqPcrx*G^7ca7lf;O~?l&n2-Yk?Zhr>))O^#P6i@HXQ#AlcD@= zGT)_tzQky`^Wu1`=Mw#fl!DZI&CS$bxTK0!vUK^|;l#pGuR4K3`ux$%2B5afD2xC) z{)N%;31y{MBW9#2o#@gTx3BtyQGtaAE1<>5P65suA4YrUrzeLo+|~`#cYskitPvz# z0E_^z`+zlO6-Nl^*Hj;$$qVj-3M2S+0*l!n%9>j{3K++#gF(d!356%+6466Tw-S~; zbSMG{DG1Ssdtrh*kxukI>9m#9n~(!S`FXQtf(}f{#z#et9jRf~p4JegwdLpiMX=5T zx~dVo+gLG02;RiY^vRP}&*bR?nfTM)IiBcLBo4gh{8Iw;A9TJ7FWY&{@fcZz6=b?u zE^R(6&Nl8T!(i0IJR5t?QG==6oB*3Xw}07R`orE)S^BfobNHe`)23$aQ2_;awGLVW zySGB(Yy7n+|Lk%ew$?9PXT9N;TW;wb5a}ou2G0Ys>Km3H1MU)tu9P79dxf?>Di{A9J;wcVtCYX+;dFqa zB;kdGPWvk1QlxuDxIgXzp&C7X^sU?@gJlG;)WiFAjo3Ny`hfjE$4yNhdu`8nzmH`6 zfd&AIgb>(8yhBqM1IS!~k(lq+D*&$kC1ikIZ?Obm`SE^e*)9*Tji_$oUfaSZA+(2U zCqW;Ir;-_BOVRRa*pvbVdY{utUyqO-c0#wJLqG~@7)*dICX5yg%$xY{;Dr_R{v?9V zO(867(tm!m&`-v{HxLl0&34#=E)V!IezDetB@%0Wi}6qjgQg22bf#<~gUWD0{6w&ii4B>z5GEL^H=; zzEs#CXe!Q7<53E18S%;N<$AV=3vbA8(a$ptl~RgYP%gO?eK{AdmZU~0mEQ=`&m2Ny zjP{zV+8aA%K*sf4{5FvSJT0VYvhO2#l&=t&jZ*&~T=M)L%Ad`5;}m$w;1C87RNh^p z6b{`O>IipwpLDjRCAse(N z8Pq;sv>4y{Y!AOj`CL2LQ$!Z+Dv18r+H%r@YXh8TE8LGm5gWQx*8`$>6n?L78S$aT zgwkt(R$PNVo6u(S8-Zd2>61R%eWEZ0KF%{-(z48(1Qm!a$m>v1@c0Ge^5N|mjg~nB z?S*gZwJWrg;1ZV)a>vFNcPsJUO715|`N2%qjY)@gInL~DXa=M#^QVI~X((844hC9m zsb#I4Fh**M#rmXpi@2Y&-n!eVLewkHx#WK@BqfCNM<@09rj^iSF1Z(C4n%vih>92T zA?c1TKV|l$pcfvZ6Zj>;8)KTTNnj(2kT`a16B8RP6x>1LWtXfBJ;3o#8b3jyu}{(W zZ}e>Jd&2sP=s0z;rW-(xSg7#~s0@E78RH^WX1%I7lbj0ptU0FA91F*zpG2z1v`etW zP8M;Kn&V5_HOT($n?v!m8tIU26@ot`Xu9all2HEdQ*f^2^_P1G`e|5uvj>kE0<`!k z=wG7=#5f4jb!=g@%q7IZPMkSyx09MskMAY%&#-6HwO%Q`?ou@w{Ng_Tq96VJL@dx~C$VnwTBC75nn zAmT-(Vi)zkPMpcL@A*aUWRr_sqYHht5(oNCIAixDf-rR@!nB{zd@DdoJ@&UZ(nE|q z9mxNQw%ZWnbIZF&Ks=X=IrFF))CS-NdMbNwpL%gtT$}1kqNmVNZ zX~-+msd5v4J3uRd6%uzt{T*Hq>_TAYZ}ie@ZKx(~Xh7P(!>dyZ)#pQmi5m+tA?Pjt za4e+y!4Z4{{S*V(2?SZeAPWWwtn))C_k~*C(s&MhLek%8z&ZAB3?FGfj=Cpu8kCpb z$w0d*Fzm)1Ul4@F>3x!jMX4#_;J=3Stw!SGKmC15Maa;OidiC#-mQFs0JHF?gD}w5 zzwj2{PP>8*qs}9nVlt4!MI)f!%eG+>oT$A(lxa|vo^XNoCP2z7>|Xkwk0C(>1xJAb z$u%U=SazaD;AXB#v4|7pJIo*Dn#ZPO??5L1Ko+0cBaC>mbN@^6y)45GWeqrjS^(SX zVZGDHtKA^4@Pp9#L-dW8Hx3O!~#-i5Jy_ zBNIZAOgN1ScOu&cO3nKj?ZPJN=_lUD3xcLhr!WDEl8ayo>R{ad&G8I7&ZNAHr2T%G zhiWnW^kQVq(})t8Fcb8_M)JAjC9iOHRAD9n${+MMdvB;+J##+bv-|dQ_s3So?!dDh zYwi#iLMe@zR=&7uXdqbPNlVnnCA;do+0a)>7RhEUKaN+sw=U7Q-G2-T8|JiI%kYjz z&FMbY4A)VwmHD4mie<4Aj-RWFUjuR9a;(5zIP>J^pV!8l*h#qudGx?w@nS^u<-qzj zxV(tq?l{4d2O9DlqH8eB-J<8;p9g#F()am^7aId7Xs}R2vOMl+qoh=1cM^0Ldq_BO zeF=I{bidA-ISwwll>h>d}{nlM3Uw#t64Bck3~|R z>H||&aLL%9X^Qa|{j=_V_ZHeaVP+7t)Ew8?c*%G4`p04uU<=_ES8B6n9a8Thx7(zg z`;T6B?*wX`y_R))*Ea~(4U?7)-E@fd-uO8mGLNQGF*4#tI26_}xG$7Phcanr^{3tx zLp6L3e@wI7fBJ$=RzA0tVdnZ{W#0YqV{O-V6iWFTc(u8__Bc0i1uM%GpliVh7&95m zm>eKhgqXlCwl3!9Pm}!DMQUE#gD*IbF7&rakrB`>o@YV1RC6gH4vYBmKTV$mJeEN^ zasDY}mG80st>>{pX`y@}#K(cdk-bZ4QB$|1hUWhn6VcZknfJ@Sdbex!96k!IRz3>TLA>cPqR!?r{Ee;*Uq zcMG+;fgkEOTc_`|Rl2NeEjf+c#nU6$69>6Vj& zJJ%wdcjTWjCj&xiHpU2dz#EY54tcP;04xMqAcOcrorvF_G${w3bta*77#+}CuiRAIaOGq4?EwZ!c6_Wj=pm36=1G)*5*!jQReE!DL9+)>98hT!W!<58WwK>!qB3lJaBFgXkB)j1gWZPyA0MmFYTS7-UKylXR5pz?YGe zv!68L7Sd3R{zfCq9&2h@2*bD_o=j0pO-9E++Rry0eRv*La>%43hWAy7eC}Cy`^XWH zyY&vOEt6HCy`4$Z50%%jI0!5%mL>y9Th_2`3RFMz-|CeMR4Q$dCg+I(!sHoiD6VRg zPr7%T!%9BE$jD6|el`6@U%-}Oo)n8Pj~T4g!yQn))t$)-e}*xp8fuo(|F(TIXwS$1 zp%xv7iC=^G!G0O}`elp+MNn5Jwj_DqQyEA^3TrWQ{%pp=$@v*r#73skKj@x@P(+z8 z;&~gWOz<~6c?CU>6sBTrf+agQ2zwqjcg*637oCJWCk8451~cK7r2M`TQNkqM5|@<` z9KxShfnE}9risM60`M1;TF2Brr3M{Q#2cEWgZT1sTrd$gYpkYEKRXj)&aLPdpYrY< zYM>7iQm539C*C1iJA-f1lBxSX-si?qo`=u&UQ)e#C+EiQg@|94cS9#neoGb;q3_=u3+c&QYrs!X>_w=Dc zB?=)Db4OLAD_6eqTRjUHyiPZ8k6SQ33-OrXLgo6%xCGi*d;jewBJrBFu5uGQ_E>9h0 zyT)#GuD|4`0-R5wq0i$(6bq`b$K;64&CI~q~n=E_x|#zu2+^x=9xHvlZzi$qjJZ0@B6 z17Jc0EpkuW)hQ`!wZl@A6^Ft@qHm=)(ylFz4AGWSQno^leok(fF&7kb52^nfgU9l< z4obaZztQ{P**$42)@P7Y@87#l+JD)ygprbv`3hL4@K*WJ4}evupp?iJ-&`j!y>j>{Kr};} zGG$j5i_~&!hM}yvQ>qmLOH0^s!MB|Y`hDX23L~x#DV^cF>4a$ zCMuEDNG6nh3|5vZ4zoc^m=}Y#*n*c@ESheXcwBFc+R7l==kJ>GKaG+Pp^J=YIp*JR zp-as$?9XZ<8Z!8pDB+7ursE=vi73<0q|+SZg#C!wo3g>qJ|Eabl%X61wsSo(r~{@{ zLB$iZ>gmVADBeHU`D?L*89UMMB(1hgP1i{B;tVK)Z#+fIT1SktzTxuW=8^;I+}+~b z3c8beB8B49?25yjMF`uCOX?4a-~J$QT?4$IyJ~OMsRTblgYp;$IK)0A7zq+58sUXa zibp|%NGXPAcdf*YhlI!RNV*8|=QF63Rb==o?(Ux4XspCy@!zIg4AGBgo!nw~^OwH! z@Pqh$tM)0~D>*GaTriSWScf<}$LUi#_Fk>iknU!rw# zvfAxJgY(t5lxY~>kP$Xlk#vvk1LF`QTO?V8Q)ED7xB1@v^1^2Zw z*Q_s*p^x$x1-h`=)InHmg|#a@dVx+h&lkO~bJAPZQm?RIQglfksPqx_vBft=Z|wCN zu`Kk8%3(|=f~Lt)E2#`stwTjIb^K|&(aZ+V9X^FG>VxZj{5}>?JL?80%n?^1)2e2- zu{%L+2YA=OuL&z;pQ#A~6wsGFbm-%^KAOA}JwlxA&VPDbw&D2W=mw&>^AGdF;ZaTf z#4*NAYpqQI1HgfnVYZR|#j7+r5hvHtD}!>z`~rAZ6Ff~k$!LmbdL~U3nS829P=0D7H3W{C)FFf$?+wR z)K^gq`QXZX{v!aFEC4sP0AzkCgGddQ0a+tb+9ts)P$CCh^uKX4?cXkEVDCzdrHSb! zh}-rVt@-}=NCurq|9Si*IyxzYhmE9Mm$+BO9mG=%>$uvczVq(x?Kg!%RnHSoM68!l zV3Pf^uJu(Xv4Y|U#Vv*&8lz+)rZF_tNF;J>tSQw910g1qcIE3h!3zWR{Erm-B9y1831hz?U0bw{KyrblABvxi7;#ch|min0V%(vwKL-+cREisg3mcKr#Kn8elaw{HM&iY zN+|D;X#UmoKH^WpN#+^q7@{M67Ay?4kBS75@!*Wdhb1%B(1D=+E)FuH0~PeoSZpqv z6LsE7It()crc3(K;NguzbhLhnD^7wwLZVA8s#6(FV=DL}Oc?qh85DR44qh9tkGn?Vbx{h}*;dSlnY1T!%=HvqT?xC6*MiBD44MQ~J;Y?+nF7?QGcPVe8Qfj8!e-;xOw*kKoPoz;8dtx1KaRM$b8W1=u?TVy0r7mVKXAl-hq;Vc&3?uuGUVG(ZuP{r49Hi z!qQcq9RrzMgDRnN^5B7*zk|=6cm|3p>{tymL~gp`Q@*&LM!kvRMs95DFj6TJ)x7wr z{p1|2K~dRP1vH1L)kzz?0S0%9KQ~`?BLuDxrlbi50RX=nL&a= zvq^?(#>;-SNV4eae!ey6{Zv!iEB*3;s<=0j0>%)Yn=icLPW zu0V|+o4lIrB``@-x{ioY;JtJQMeK;7k^)BamN#P8c_!xc_0Shoi6daoB6U}ydB-d(FA6{#$+!gmN6{o-5l zIj`}R`?ZX|(7zsj7}Y?CF44Nw&9FBj5S5?1X!bXLtOV?Sq1dgZ0FB(F5yA19kDhW4&PW zro0XlYDxx`L=X%lX`2d*)5LXtJ&hElQ*FWV;MjLjH%VWB)-0-056D>>)IbB98zhRX zhYL87&87?&-w$!VTl(Nh$%(gEBJ@B@&ZX3vaQSO23jNKRmk+MpkTOwX@Eals(V0hZ z>4L6)D*I>vUWG?R1Xtp`Fz2J(2m^j@DPIhzZj`k2&T@U_N)RNHQ+F$%u2-;)E;=9+ z&~0|Z9GYD}?)oEaxRZCk-e2FD{{;YtuWNFmLw;;@5SFhF$8(XhDYpj4)b4kVQfh@7 z94H0otw-7?EKw5Hcw{sV`Z%Zw+x)x?l`ROz;j!HQJ^S2S`Uu}pW4wY3syzad9Pw&* zPA=1|;1>lBhds5M$TT%FDfp2t5I?!g=6SUA|2d-iUiTPn*-e*Fejktn^SKQtq8?D) zDm0TF0kKh))4m5Y$tHj2)@h?Li^|4H@T<_eD=~}dA%KiwlWq%qdlHv#&zqX~DaJz5K5yFwOp~@L=Fc$Es01wwbNcJF% z!z@OyL(aXBzN1dY;_LlHdF5C_(nb4%fcE0%tGl4sq0~lbYt`B|NKIw%I(|ff@2gl661a*CQ7vLX6MhrL(Ei__Z??F`@wZovs zV_^eW-L^Hx_P^5$K#YVxni`hBeRW_mP$;tHySCr&#{D`oj7~S=wBN|l1}>Y{`JkXQ zo5K_`%FFjRqSE~=KCXP($uBSFjjkXzrf8bVM;rnOQIsxjSp z^%tQwevx23xv^*&3FdKt^1y5G@`m$YWX73T@tfUi%S@B>v~1w_3Sf}(vXNuI*-}Aa z`W~H6K0=73M*)40J;_f>4;qwYkkLn^Vze1sSe&d}z6{_=Fop?V`1U;&{<23EmU(Ru zLDd}b?>;pQ(%;aOmbgZE6E=3^{t|WFGV8^%8x4xU`5hE^Ju{en=nwTxLo#f9W!ax_ z7GVHJ(gq#R8J2e6^N#jsUTx-RhSX`e+lQlP-=N~+T-l0fYHWgjR%8zr!?ezSfE^?d`b}q1~Oy*`$27ZZIy@gG) z_V6E6z?GwUWM8x~Cg|SY-vO1%npM&Z$nA*RH$d6{q<{7W!;W>esCc5I^g zI8$WmI_+Knz<@oIGeSsD0R4L|S8%6+ta`FG&vXnY&>n!oCCB#buu@B0LI5$(a73~; zvY%OaWcy$Mh|z}kDaF54kfef#8X!)F=#S#redpswE#EE*_w7w#TB3LdfOGlT4}7UplGZHMnTRT)d=g5B<6U+8>aS-b5~LXc!V zo&7JA3AdEUIKP>M8MI7DSQNb2`&VS4H`@7Duyn(-=hjBLD~G#qV2u-{sLoS)x~r9S zjg_Y$SN$G$ApQ#cfJb>sGt#O3MrpS%*Qk<{%~$<;KOK6{Sv?V(`TAQj?MeinIR4H` z@9+?%BuWC=AlgscVk`^4+xID^I!j2ejqo0OZK-K1_V?4rL&74ox!i*Uu^@f;?kmBY z)ok&PpikR!pRUX=Aq1TVfoZ$F`HvUA#LvB_#LVr1VNDXQsU!&&HAVqsdy|*yT>|Ds zf=?ovco)h?6%N`ct{he7`#P=K8}c~MT~gZ5R@U|(j?z6F* zV`OsIl*5>+CS=ytwQ2FVo1;0Ou8B@;D|P|xxY+X5u-`V^Q8{XNf6h6>UmF@suNLM~_|EF$ zEZQi=MVJ&bcZ&eRvu@ z%|;J4BQnTdybYJQJ>e#M%fGwC_=NlVc$7Ez+3bo)gKs#wz|cpUBIrsYUp#>>Z#ZV)5v zVAN8W0Plj<#j`Wj@oMi!lk=-P$KfdB7O$StQmTY#?Ut_i9(!i865O?dkM?KL)oXQf z<2r6oumZQ^VfLTP6?@i=CMnDCiO8&k$`w_yMw-F$i`75{U%9~j&6`hihVc5MsasVh z?|$}uQkE}%%=T^VBDj@XO{bgsy88F0$lSjYW0|5q*}~sbJ#<|>wEn8EO4l@U(?-=O z?)KRm%rmQE9$N*BoPOTo{|Wh~Nh`V5LjS&|tR4a{wWV1p)Kk^ zVmA{F|6z9VH&i*eSa6pfkn?(nc_K7qZ197*IY}19cz@H5AL7@{VRjZjU%dHi@X(Dj zZ!qybCs**VV_f;D>9hye2`;pX4c zVYf`*ALr;>H5p1 zoAs!d@vdOgMP(n6vC!m1=zKT^IhXJ;i>%fs*j-=XEBJ3eey|u7T(9p;U$&QcUIBAa z-|BUfyl*K1{dfi-sz4ETONTX3v6d>>DPSWK#?Usff#^5R;khV<`fRE^O+?CziOuha*N3(+}3HwEIh?mC~`cW zb#sc_YnG-K(<6f0x3Ku7DuC`tzq`1`zB!&Ou35{dD#va(i16yGOV@TbNSl3RixQ*H z*f|^kBT@+PfXSp6>3JAl3s|3dQ$X#$eX?VFc$-c~kA0y9P!M8vZ+@ZBpM%9$!=`ua zTCKBYsZUeEX3T zZAdE8leb0AbS0f2v`dryc1PDnU%*#R!Yk^E@bbj)nNw${R8#SqEPLx5K|zYEi<{>^ z3g5BlW>kL_gR%YA0jYvz-tw$XN1uf^G8r2FPYMZEzeLmq#R|bup7CM^pRWPkNueK< zvxK$OuRI9+q<6OeEBH6gX~?^6`AFfBvwgX72Ky+Ni3{zj$xaL-7ipak1~QW%?F*(h zDW6_-6?CWfOw-IU?jb@0wwn$xVK#L82n2xDXGVW?H`Qa|4O`Llp0A^o05Q~x`_-}A zi*`J_FyEwf#W^sS*tOHqiu=*vI}WcejNyBZ7`CnM5=g~-KoP~r_^V5b=^xut2@N3)Kn8kdk$WUqDSb;^OG*eix@v>S$)`cp% zVIeeX4BXD6rc{Yat{84~P~!FL6kn7Y)qfpRbMB-8^xOd80U*wpT6zdGezsH!K&- zH%;Hypff~ApZHihoSC^0jFdk-(vKRq;vynghieB~WF#pM$1QT{1D9)W!fBYhNH`!- zYZFbFHy(zi$26d8nkDqPnwy5)C!tkf6VyyC*mH44mzbF?N0!96-|PNV#$6V)6J zjyttPbNJXF(2m!dxR>XHFn;ceJu|F+_SzKQ*{ACZt41H3FLDpKvD&W82R#0$Sm`Fs zyaxU)v^g9R%B<>gk6V{|vz2u3n+kvO+ul38(sS3)rL45Pf$SG4@l{}Zm}_yA;~xlV zt{TADTj=+V-a2S)-E_}7O&N~7nKjrOPs2bAN>SLLa|0=nmWs8IR;Q;UpS{dzlD!aJ zQpOc-DKX~K6XcZ@xs!fIa1ntrHx77Tp(Hm-79NE%z|P--gDCRjHxo~5CpA5ln#|=Y z6wde4y+S_%mtKWmgjiVLAZ96|Eu83kN6`yR`aj)DeCn>ID@{_~k-KE6SABwc2~_RR z&c3F5w-_6bjHwO5pNhnvV9q4++A1skj*JgplB3-7xCZytN=VV$vs2|Ehu#}~SYpju z$ci)w@&@;m+TG=lhJH#n>^vDo^xk6(*hyI;VC>6)aO-L5CnJNNC6MvXZ9OfK{iJhB{A zoj{7agd)G6m;`< z(Bxuq$48&`mMKTfNvPYl!l)>CVO$D>w&PrA*syl+^>RT>M5&QSR5=eenI>r8pegU) z$Upc)xUO3Xo<2JC>eGy&F=g04MoxF9(D>v9h_O_jSL+Idnm$Gkfi}WhO)%_RK#PT6A>ZBD%F%hWsuAl}#;8z5j?Fs!GU5jgLj(d9Wmz|Jxt`1tPuFEJ-)$el!tl+u(A zpPgT*U~Hb0Y-D7iRNU=9XPSL^faS@bK&e_rGUBpXr&?t*YlP(HbqR(npkgQqppB8+ zMe=mPG&D3K&6i?{aUx!pmHNZ242KvA3VjTD;t)-5LV)u#R5L#kn??S{aVk}^NfJaY z!MgA4rfYtDXo%N#Vl#+Tq-JGjs>eKjZS?IrnGL?=N?Y*nNN}~EDXdO%hAmCjg@w1{ zKWLl`I!7fjI9BG#$C!)@XZyhq6)pc5_3E_rzPMjrQcv&q;Q!yvq0WAeNPn}LZQsM8&-i$` z+o=A|^E< zP*_ET5eI_Eavb9BIL<;;Pz8qr0*r-0LuA7W1rZ!&6pSJ;h(;oJB*2$+^r7P&`b#AD zT^4XAGE-vgGY&vJZ?}%7&Atxqef;3T3J6I`5yP9Qcc98%;KMeb{q|c z0(?cAzoxrxYIO-g;KI$Yx*BK_okI-?18GW0m{mly6=eKO7=qm!7=|0SGKN&qhLEF% ziheI6M;adeHysp8X(q@hsw#pkKv;tjM2afKni3c^O&Q9WbSTr1rWDajMnhr+i3}+& zCFKPOp9UTtD*ebSd=d2!5CQWj4#6o58GK{9dgG0Z{i_{@ki~O3B-p(p1L2k}#h$uH zCIFHT|E2t7t>gL~E4_X)grK$JNYrrD=rr5nuZUj+Uw(0YL~Nxu)$H!>?77V9st_Ug zx_I&FaZqih{!_gp!<+rv+l99B@WDruguHWX-*E_R(p~cdonxO^%13A;oQeUwNxf#! z$tPzK&`4C@RE>G9pHQ^13#O#d3d%DxF*vR(3xcqU*bxC4$qZ4%IPu>qn)OZ?&$Fb7<-cx%E7l{oo1!Uu_w#9yB=zx3TfGP+Aqf&CqS4xe8K&w9M)SnbTXuU$I<|#1RDySheWFC)O`RDtIH)=F_v@Io%_s+Y2K#a) zZtN$TM_)%M=LcS+Nh~qZO?tpmo)24@K~z)+3{cHxNG!N8Mk@#6A_B;QgX`u;eL$c| z9<+f1gO5)<(}Ri4rcVUAP$_lusu}3xhA?hyN+WSy2m-kjj2!_L2Bhwj1E+ZA0mTm| zLSS2$bujm>q4v)TTqhJb3~(wwZdAZl)Ws>S;8Ke(GE*b z$SQ2(+i{h-#^K4A638+aXA@J)u3{)gWRhq|p({;n`ZtQLUqQQ#jFeH<+Rlyjt%Ut} z0J|{+akWEFO|n}QQ#lg`1GXSoj=3?>DhBlN8O&Jl;{sJG!Lp|Fyu{;V%FJ;HN(%@; zKn#P7%m778kg#Db@qMi-1F)TXB`qYqg91H-^a0Luu0se^uS~e>l$d5J%Nv(W_;A;R zK=hL&Eq&;3!Fqa&vT@4jABtNELQzFlMNmf!u{j~C*2P*8Ue!wWNKE~SW!NF7xun`n zoO)JsX3?VI#T3>sDiAFc+Yl6x%9Peoti$G}8kJp)b%P{WKv`Zg0W=-I_(6H31fn4M z7>_A8+xiWHA+m06mNu|9#aV9JM7&R3+3WeQJ6Sk+3?r#yonyYC$GLvfz;|*KbCg*{JYZ|b@Hd%>IDn{ok39W|8Vw`GX$ZW7|rz*)cSyc+GsjWD; zu#PIbV8XVhS;TN*gDD%i85vm>#e~9@P0DU^u+#nwK$3IutgIn4f{+kJ7C{gq#evYk z0_By0m@=wX)v{1XAl3+lMFS_LZi+&Q2#%z}kPT}MLr@FYXu;6kV7Y+Zj3<0#n*ykp zz)&O=8{ncy3djmF1eU^D5o|4xTMJ@aBCJKJ1+rR}q=-MmVi1ff8|V^LhWp+SnnN2h z*JQ+)_A*M%xn|mvXBIPYB$P-TH6#_?p$;0T#1!qaX~t~#*^cdC2*5l39~jn@-H?>@ zZwcD;{PRgCkK5ys*RY@!9qbC!>w8J0f`Y)q&D+7LPR2-bW~XZ62atw^v?W3; z=V>+5XO-pHY=nq}7{ENgDu)b^(sDqZY%ua^uFYc@cKc&zTCn^CHg_$Oq?MC~26+A~ zliac%Jn}fsOqan<|9;J#sb>$zi3#!P-SYRvhicQf)EAmaLe}`qq5_1~sqJi-&%4#x zyV@`@0=`|KC+$ly3`lKif`mo~3@eQC7#@SCrr8A~@7fDK=?mbnl-2ZHdrT^f5g?sO zNT0EwSF2f)d1w?6ivvhhhgHX^H33L9%$0(O#e&+{O7CeRfa#=Qfi%<#-pUe=T58Zn zNhUCa2}pv8a>*qb8$@a&R?Wjp}J*dbL!QD5DGpYE5XShDnU2q=gtnVabvdQRI$h4#`ajDK4<7v!YWf zFbIhZ5@p6=aR=8`)@9_GVd?t2xY7Y*S?1)to0;hD_TikD6JmlFki`%^VcKrC8Z`aA}gZ z-peJM*cDeSRYoT$s6+w{qCPd--%L+*nNW-MzvPG4OOc4aOQ4B0t zq=88Vf~*i6&aX3Pzv*{1Jl@KFj%=;FqHXkS>SEcz_j|jQOF_i~Mx=oV4pTh_zVWr% z?5$Gw^|j4w57^`;;)+B>)oDd!QC32-M~exJQy3{TD6z{+YV5f~%yzWnc9mPRR})Rj z*+olGjXE~me;>1fgA_qI&E|U#rrvt4mbRGiHk+K>oB+9BWfjF0EOP$N+ein$;{Q(H z4{eay=QX!@u)&}W+*G1M2`33+QkJn)5LHzSd_LsSvBzTPvt)gwxLB-$0;p)Bz0DO2 zenWxA`wn}P*Y$dxA>Q`7Jp}Ji(ZzZ?wy;PLW7K1={y^mW*Q?8L7{YqeI>m@wdaqMf zynb#vF&-;NC34(A{K}~hpY&(<`wgD;&Tg@)2mnR^fCdqSz+wQ?+GaPjXeS-74jN!1zdut8EsXlU;sp+_6+p*A%2=%@m zQ^PRBvpAcd?Tx(AxcD9dh$sUD1(OsXqis1xgelqMelK3VE}j>~X_ieUYRZF@)yNQF zLkJ@xF%}T_*U4enlV%ksdkP|+@k*vG+R|WmCJ#Wz0=&UP6!~b7RYlV}h%m?)Fyj;$ z18EVsn`k<4Y^*`yFrvmhT$k(L$w0;bIKzLbM-jcSp_w!re-Fn{Xfnfc3_e*mW?v(Q zmVOigK*-1fpnQY`FoA$UVD(3_FriTPJ$Ev}UjkuzuNNV3XXVt-%3#QF2n>jZ(}$z+ zkoUfRoy?IBoMTdv(`e#huMOM_wzwxJwbW|v*sBI-NY0<0Sc#`Sem|m_pqfAtMBPe+ zgHyu2*ai~i^e!$hBl%rg?DlRUyETO-Dn_&`o0^hX1XyMTV*qK4h-^#@Qv@kBU_b@~ ztt2lH>&=1XyS`g0JSb zvCtUg1Ng@TBHm`7OtK&X!$aU82pk*{0w4@>F_{h|Py#na;LG@VIr__^r}iIN$Kyw7 zV)cJrAB%aHx^6i9KQ{*Z;P7}Nakl$^TWfOW?{?X)Ui%ZW-c|MQUQHfzyyfZC?>Dy| zH}_M(cJJl7SgmFk$<^fJ_?vHik5cQC@k01?k574}7swYMd<3gQbh`6Ro(lz)hJky8 zje&u)zCgv!J<(6Xxh@79Gft{V1 znX=H@C~VX-^Nn;76cdpUQcrW#GxJk+iJ6ILiW&*KJ(^*fa&~@#f_{3@F&RN+f1sS5 zptaejr|2kIXeX@JYc-P0`$IbeJwauK;mJ);P|m>5N6=1DS?u!-lGHRav$kpJ`U^A- z1l#<*1Vr@2^yLi23pCX9{RA7_?A*k}wEWeU9?dxcJv}i!K}9JCJ3%`=K^JDTOwT|| z&(2O+;OA%Oo#g0YtkaYe^7eW8$SHd?%?tGG^!)7H%*-6b?DYKP{g!>^$vovbKM`h~ zpM0B|nwgZJvd_)U&B)F@$j?Jrr>yg{(=$`j^0QO6X`4LU z=$1T_?hJRo7X*Gg1}DGq>?}<;IHL7R_r{>E2PC2;kRvjt4~uJ*iU1NS2xfqq@ljvw z{r~&?99Q;#k9VKu|K8=DV9xJ&z0EfRYn<_QJqR^H>i>UkA8Ax)-*~;!>^iL9{$kYg zdwvg2>O+LZ=KSxgJIff|_)Glf8TC$q|egujuf&Is@xpE?^iW{+xnZLjd6C0{j_y_-cN_;*%-&;_Ey*b zBpaw`tkf?{?Y=lw*G46(yO)S}u9HJF#8>ys{=MXxa%GqL!M4K3URPdcmn`}*O0Hf1 zNx9D3Sl;V=cmGenz^S>3z1ew7>{_@hL@U!*p01L}6@DL|7H^>|El`kel)md$1&`SJ z*K2`;cy7I2DIPp{CzbcdAMK)&X>(0=p?d($3cle);X(F|oRnpCUbn>3+Mk%Beg37t zDX6vxYg_c3CH8g#If4Z>@y>hW5pJx6exj_DTPG3ci}+Qj`}-UsrCHkTFiRKS=2J;h zvM7%EuDM4}TNeJ2!%8+>Zf}#%-!(%T^?M9WP`=t& z@vz?aoI8H=tDBs=+hk7T^K>PMLTTnL#82V8q5#%GwJ&|=@PN$|Cg8k&~cB#=ir7F96z=gUWNmL2jFZENb_Mw zcj62&?g3*FVvg8&u)|ATKiz-efBfA8|H=P@|6~7y`A71n<=Nhz?~FBaFKoAqlteqt z>9tUpMMse4G9&};E^C=3HkfhLn92eM01<(K%q1c~Q-cK?Kt+LQ)Ivjyp6V`g1LQ!% zQbrpxr%(>0t(l9fI#Cw(cb0>Rau4nYK!)RGaQp0+!!ZYK?SGqCxYN#sDLuhLQ4@B_ zMp*f;XTxD~b9nf@p9SV|ey)waT|F;vm*U-iLPfe85Iyiigy<_*LgQO4CRL&T;|yjb zs0Bh)fWC_+(g21dwF6|tiUmL`Af#z!L1x;p%%lLUG|eK>D~T3X1&AmpDJGJzbxObn z*`y3f3dvZjFc=ktb!ALjO&A>n)HJCkl={ft=R zv0d3jAwUue5fKjVv)JBaK+^i_5(W7NIS+sPJ6BPTCC0r_p$0}q2!}p7+@I=iwB7(P zAfypEO3zTjs}Bn~Cg`#8(E*SUm@~Nbj8=u1*cj2{Z^d^Jqy3{v%xo38-Jl|XFA5n7 z_g;g=>WBNxKk%5qibHXdowqYV>0!Ux?rd#gw=T>d^9iF4 z3TjkF0;v@d5Jee~QVId6FheBCfcQu{h_nFsY;MSOo0ziYz$H4Zh`cTNAPKmbqJ;Rz+rT~F} zBQlVoASfbcTClA!y50-m9xi5fkzA&){_W}@2Zn)_fffcL^b?3ZDQLuf&9gw277Cb^Rf`c-HEO7;A}G0K5k@MRXu%?ywj!}&f(o%j zRhZb3V4^`43efIQqU_g4fj72IGN33ZV51Ipv(eYYVXus*ccy*M*l5SO*X=O!Ix4@~ zzp1~StW7BCR-SVY9r@oYe)!fUi?w@SeWT7zy@mE)XL&uH`j^S=-MsIl=bfZEuuwtx zXZ%{x0}?E%u^ja|Dq8flJ#Bq0oo%p<%5?N^+-V;Nw#Ifiv)RsUmsoR==6JnpCCU;3 ztqwb(q4Lgj28^08(@}ybtV)GvUSMLWwW5N9iES#&TP0$ujh2aK z>AFqO5bOEG3Nk9=W5DT_9ugR?V~Zfz=w|7f2Co$a6%rx>q6OmfUJw3C^M&p{6%xS! z3>leh5M%M1`wKHJcY-NUx(>8I0-X9+C%lId%5}T^Sg=&gMF|&Xa3JV{95f5#%=6{y ztF^;V8%FCdlgof=z6RZH|M0hLlZ2@O3>i(mFrv{ly*fp+Vi<{hvB^XAGM?xUGf{dB zT*R|UgsfyChkv+qpGEvV_;ew;%PkiysKjlfK=2hgH4qChO$I>B%)mDrPnZIMD)pJ}7!5NEaGnD_q?R5?AkKdh}Xf5AJduiiOuv=3wT+kYNL@hZDx`Fq2ntfa7Nr zRWRydTijMTTesKvt6q{AP_3QkDS7H|K7lm!Q-6S?-eE^~4^8F#ZhYGz%w&gcJBf&> z8Dv-p!iXTjg95SyDbE!8O)A(OM~tCeVs#H$q^*sT!1T|`2rL?}HQ>Fb8h>A{`8vNi z$_$kQ&P?n^YSL3OwWmpR2`vC&tqy`5yfvYhCTR2*c{#DY?-mWVFA--(7Yd^QuAqMr z1&WRDOm(v$+#jwnvGRO%7ZaI4Js)D7DUjWsiQhi5K7;fqJXAW_rTSk!-CwrdSwb;T z;`q8phk#r|c>r}ix*Z!!+tPD0mq}YUYDS3~(nuAjDfRjEABY&nKoiD=!42^~Z8rAZvC8D2(C5%@%yPXaCF*YF?ZY+* zbtk>I=1Yh{2t`-FbbU{oyS!$^S}_ty3{V$NDOLlX$!|;RFEsfLZvmgv?et^1sDU6N z;tkl*wY=6ecj%80FhphDm=z}O?V8N*Xz#h0I+oYn^Zd%j-M@+2%4O$j%kuwu_<1Ih zQ6BcNsZ@FvObl5;XO6U?kwuU4d}(*io+S66z{c>9ztsDP5HpYQ76@l>hkK5&PZ5z3 zj$<_lRm=ETRO#xq!cI$Gp&Z9@qDVUAwBUe%;regV_n)`sX1uszP9M1s+K(_ z3{NxB?Q77{RK-`A`}-+1HnljfjkQP>G=lnv6+j>Wul0VdilA^@F##f(f(cR?03;n> zOLOEoy)7?y=DFU+{l2F!rf>Ks8>hd8aI~snGePt4M$ldS6BIM?t5O1O4WPgsS_<{I zjhl5*^7wBLGZHsM20kwVS;q{B6A4;n5dfnCtyC0t1QG9{i}80i;Cqkj5pZh`69fR0 zaG}D}p=70v^2OsBdN-6P+-fD$x%`RWZW0Yrh-ii&EkW=-A_5}9FhWx&!G~5H7#aUE zo<4bQ4Y8a@g~K;5&DdNZ^FD)p?fPHK|9-b2kr?hdD7BZbG+ynukUYJ8_XbtP! zX(S3roGw!1^REK+Y*EH-JV~RWy$6>Y;8-xQVh5I?q0Qqeq+Zuo=`otq82C8apv(I*WLjVI0!^%(+=_6?Y=I+-(Zm&HXlYgywbL#%;nNsoC;%EJ0cpI76vG9r<={(t(&=Llc9g&fQ*eBYb%xX$AQU4Vb@MvYxe3}DkhpYD+4{G2~kSqEESJnsH?QmSZ&vV{~b+38?)J%qCF+qYP z5!d?r-rKqKn3%7Tb-iXuQv*X^UlGv8HXpIIvngg<w+QlJ%&-J4odw!UsG0^+^jH>faJZLzy=}^ zK!cdiFrX1ma~K_*7KMEgzqjI=rS*- zR;6mC*FL#q&fH@fzydVx#R@3v7ui?rL* zWB|_r!16^swB?C$4&TjEDZYq!PA3aPk%zbcYCY_~-80|eG~{l7KK4oJBv!$_eG@ zPD)y`DEU?|YeZVdpY6XylFE*$9lfX z_s3qLr#Ttf$F!cR0h$wgK;a7zJ0Gjx`!8wee=^rsSAxK+1CeuN!C z{nPra-2q4}5Bec1&7Z+cV!~x89?_@^KYqfYJ_^wFui2#F)t;~OHhw||gg(ovO&0hMD`s(m7!(JfzPThr6k|3PWL#X=FT<@tq>c_RN$;HdHDVk!N`fLz^_n=Ys&u zwfa=3blRsyEa*V2g27GFEDDhr3n%$}6#v_@$ZfkpV#0slE;3Pvb%kX5RtA!Ma(Y-% z+La)r5kdV+jvBrs{?1dh&Aa{FlanXHI}SUbaKJyDmrLSQsmjjQS|)jX4)^W3Yi0M| zGsTx0QW1n4#*Iz!!0&%S`^AThA^*G19})oPdGAxmt&0yU@4Usah8Akzq&|WY&5l5& zC(BrCCu8T{c3cZ6n_lt|T(IIGDonrjWCTU;db)wVgA}h+IN`49RyCUJZmHwQMvn3# z9x z^>>@fv8%*qIhdPb?P_uJ^!FtJQd*^5YcAJ0E3B=P0Xso5z`?F$^UaZ7pvC6{fKsJL zqHw4i`*b$s$Em6FU@#TDT*YFV?E~vL3RK~dNuP{Kg2U2$)dO4=)-bTIvU+f;44Z~< zmh(bHfZ5DurFnNzhObU(mOpJ?xHsSYOnFSD#^Rx1zavh|l(59lTT}tpp}=o42^W`> zh)g~&4{q4&l!2Jx;I6Auoh|cYMT5&~E{tqyAp?_svs#W6d-hmnuU|8DAh=&}O-w8! za=k1bsv~t{MTOSK$mFrOeoYh3rc8LeO)9dP?W<;4N}z*K5^4?$xB5uf8q$V5|8Xv# zho`O5s+z;>$1qx>#&aRm)rwV2LsJk_3Ly4P8%P>@Rc-x8kD@9J$WRD3@HT%89uKL= zPRyt%X`?w5bi}7IC`enL-2g+AtV*n10b(?7xo2s3j=cqZfYzSP#SJ#~=bpX7`CX}b za~5KBVkN@gR~s7%%iVFmBVoJbnWf~t38%NR6-8`QOq`a0TJC>UBEknn!sBlS#BG)^ zqH=kBLuC%$BL0*G_gng0xKf;Pkhke@wbysggUn>)C$#I#SN^r)oZf%0=Xv8uFkL^v zt-6;RKzCt^0lON7!hi<%hzXF1It09B$^czk;qA=K|)(gGLC&pxA3F39f=b381dz@F7 zl+q=GQGCijTV?t=ymQ3o#u5rI1lZoqXUbbFjhcp+HtuinEj7Qp(}>Idx>B;PaFDm? zJ2sK~p#KV)yqux(&U$!w_}9$bDZZn&P6$Aa=AXo1QxwXL`jG?+X5#L zmhjP^t<@h%tGgb8zPW)~zzinfKA4?9r$2s8WB*Xg#a!4c*NhAhm^lIjF{t0(Ff?=N z)>xQ;L0iO!wt_ewABUmE!s_YfImf^iczrnHKK5&p+OpO;A1lc3El-)Ld4Zr;6P;h121C#T8rJut}~2%VC_ zA&^4?D@aIV6i|uWZrdM;pD(ooOo3V6N#b;$o=*=H{*yTU75N>nK=VVE9AALZCX-fz zBF>gm-teFx{VfyaK^ha8!{GmNKp7o4p~TZuw2j$%`=cCghLjgHbY1Oi)MeD)AJ~i4 z@MtxmiXq3-TrfQbWBQ~zoM&&dFz%;mfr3vi++-o`--#@Y-0m@XThjv*qZa}Z#(w3H z$A0SC9Gak+fq|n*wu!XHG604-D1}7Gk+TYtcgeSN(D|$B;q%+|&EYQ+&8Vndyw+~G zR)!Lk5m1;Q8&+JIB|*YPfFthy>4qdPu8?`ZyXo=|DH$Il`k?`EJQO9U^HxEC!B7E! zuoO)&^YI!aQ9M*e|NU^`Y3c!-VL)=mEe-|Sk23<)6b!9|6^;w2C92jbD3q_UmOCg> zaSDg|e4p$5&adqKpQmlU<51ij+}!We!`@{vrDOV)2LmsnWbCop)uK-SvEa$uP*5mz zumhoj3zi^`V^3FBRxAt@!Vn;Uzz%Fo5k4?N?KqPA+(81u;Spdl(`#Q)Gl|F*-KKYG zIX|#xQbU&{u2X#!I+}!!c9O6Hm>q{jy(C}X=vUfpZSFsw;#=PeUY_?G;9Ao0*2W9S zA~GuGeWl_hZ%q%6?z{aRKO^xV)%X4HqvUcuZtiNdn`2kR1>SOdU^z`X%15XMQjDti@!})90Z+z#6 zx#m5s91penKBnhEs6rJ)HM;73cLJXqi_2Ksz_edq8xT8q;W0zc`Td{r?!TkW`F{WC zyq?!^X+QZLp6RHnkye!^%NR%kQ<}3}(j1zWE&A>f#(@1?4~Eukp+F^&M~R(JklH#<7r$ z#i}?nFkmqp0B}Ho3xaD~svsmFL09R@ZMBn)gcCh}iJ{d=L}Baq^<{JREd^p&VX8|l zpiu~bm^V%epSS;<`Fypec0>FpZeMKI#ceFS^#Kus?%jUyk9MIQKM$(HXe3~T_lNZ) zXw@IBP0W(SIX z6!j4l$;Z}cJS09B8<@oR9H&=qy}GTj#JY^@dlviUuhKP8VNKwDr%Ma&bWV<_7K{Ke z{jfl&1}vO+GuXGd5FrLbR*F1_HugS8E%|cOnjFA-3P^`gb-6aE8I49f+6yG*dXS=( zVGE*flC_oBAl-Xr1p*Pl(rCW);>c0_(>5t_(eZTaz%YX8RW8;cGnKrn8EX`Q3;;_6 z!vJ9!An$#2?d{t$hR@zmBe`1Flb#g_fWH32z>`3cBCteMMT@6r%eG`xATp6iLalAE z!pmbs@Y-B-gvr;vvk!p!gKQW;Cz$nXABcU6+K&Z7pd5_>bAs%N7C)B?Ds2ebXqruG zMVlg?Um(qB7A#VJZTM6V7aSNx{zd#uCl4S*8Bm^=r>Bs~q}WY*YuT#`vQ(8gxclB8 z+g`X$q*9{M83laDm*u%%XLtvfiJapIWjK3){V4IgWR=>%^n4GSVb4^zR47SQKWjt& zbGRD^+$$K6#6~t|3ZalcAqcYdeX-O-*x{aUZ=|=}b}opIMaY%Q$qzF-SiE`1oe6=< z9PeEwB@9;^dnwR$pP^%{f!09&XmzmsP~gsw3OrPKEVvVZB#|HIgD}UAKCND13OI=lrXs?eEi+g7LMdqfQeOzP|Z+J>0(j)N1QBLZ45{gdeV-J9*Uh+7j5h%rUf zDz?QuJVm-!^sb7Zcks7xON{aiODP%i#z2hAwT(LrZrwx#0LEZGi1H)pdeG7ky0k=(i{uSHX4Nb09W<-2InX zucF0=fZX!D&Bv6z)`OpY)mclRCvgKr#==2L<~)ZDT_tgtjl4XZ!=C9o&j;u5x_jJ* zrNe!Cn@HH3Q+aKPDo8lu7Kn8Krrg@qxX{3P$WNFB0Du_?Pt`GCr!a;z{2ib0qW{OK zvtaKYGe|Vx-8o7*o+h77eGy?72oBZ*QJG$SESINI86 zE40@Vpc`nsLC)-3p~*;MA&RJVXyzi{i-nwVamjfqFvmsk{A9}l8K7{sJANbMX!o1! zeVkOrFoMp8O0Y`BlXRa1hiTYJ=`>M_FgGjKT{eMx9_CMncC=2bnkZNzGa5-!r|0Xg z@mK&47!+1RJmm(~XjBjh!E5-+*5^qdUU{XM;m@ZSDt~&Y#Lii^J z12>d%@VW-HP8J6d3r_RIY--nxUyEwLc){!IrB}pvRx;E;R5BZ=LOc8%6a!5GfMT)? zUM0`T+`Gdv$H>S~rz`VdkXr_u2Mu&A1yIVN`s1!-;syhJ6T-p519VeqMM7$Ax}9vd z>uKXSQy&pv;jvdKI#a4)W;Go;fTYMU9F-g;)>x6gA+&h{szKi(RFjTT62MNs6}Ff! zY;>v|b>tPa*w0Cw^_*O?z@WhlI^d#2o;xZAWsyZ2$S0iZxvuL_(gRKv0!7abCS--t zW{OS>3zmjPLN;UD%7<5*>mUv>`b=d-T|@jZ?{69iHZ+*ZZDvNvVjy4{kS7>GWpx2r z#>sRVMu_${v2Psdn&GCJg8)!uJiF)pr|5pOy~^5hSJvUjBcH8^d3H3d)Y^{yj1V_8 zR?}<6Yf@^ z{e5JthQeJ!6dSe|ww9ciXC%qmzf(SMnnM%zR|Dg{V{!?=GjV|f5g0kZgM$xpwx-L1 zNTbKMYgMFmbxi2y;P#yT<(LN@ZifZja#u>AN=LZo@D4rLRwV`l%=~NfI-<`Kc}WZe z5e7cdQ1pMrzQ+E24=;P~@SOiG;&VEXUM>ej?Yst#^A3ju)Ci6^HK$9@!@a@;u~fkO zCKA7Rp+#g9gB#VpHPk1EX$Vidm{=U|(&M?0kt`j!kUCf%b0>A-(>7GvmPAER`3Kx# z$Hv_w;nl;s`04GF=#L(r4m-E-a1PoB(RuU^8KfjKvnD#i%%=4n1+{{*-q&SSgOs*| zfZ`KoanW}!5bJF|<^(AKGHcVbbvI#4zk=LIUrBBwb>MMf#(g}4x${1vt&qTp^awzs zFryNPeYuWwO!uev4_z2gsl0beie3)EKrH5)`e_y(sNs@0D(*Sz+qyVPd|Jyvu*H>E zP=zy~3ot}M;~-ozLlDJCNm4*l)u2gP2rL#X6xk{$ZERSk?L{jMB*q$K#u$)`0bm=j zmC`^f3~`Y%zA7!WHcS!WG1jF`TE;5%eu@c$3gqET>P)t-(0?8n% zNr@{V0cOYqiV{kQvLXebf)xd185KzoQcSG~Rs<9z6ogp-Bnqg(48S0UeR3cMP*z8} ziD#0AK3&5ng=5FeNaNJrhdE@^p=vO~-QR=#1vR=*EipDdr|BDHP15%CBnF5hgOBwXm#G z2~rwgRrWdkzJ|2e++b?&;v-ij_!sRxhYsJjr7)}AZqIUgZGs{{}} zAt53`+>>G~=jsbR*v})i-SRxn+~?nDewXFCG@yuz2U=99OXw;Of&DJK=683a-=Y|a zyxK`dXhKb1D%OH^!&iaTqe?Yf2?huOMBq%Jn5?GF&Cf5!)KAiULrMl%)YCj_1rE-O9vs4EuiHr ztF6&OAGGnGJXp7L$Zo37%Q*Y}g|2^BOZ@8ZDEfJon@IHsIKeZIx@9FB^a21VBN@1^ zL=YnnH_Bn!FZ2IQsG9eA9pC%!BO9Q>TOj2;ak8!v`_b>t=Q-M8DZEtA+|!!3)SDr- zrkc7n;|~#tV>Kd?MwaNY*NeXj5J9&>HN z;x3R5`bFzv%#^(}16Z1d5c4$kIxQu2#smKn6$o%4L>goOq&=mxmyf7nIG-{Qpg^S3 z)MYIu3m$3_Xf*^+?|2-}Q$!|a2L(Dq$yh=lVxibc+)p_$WJE<+ilQfFKQHS~P0{A~ zd%i4N8t3iLnafQtY``E594TqW;J6aZEA@A4$R3P@ z1A&YguxbDK8Sc;Y84xVv1xb+s01E5S4>??xs&zS{!{J*UH^=Tg)(4OI0~;+u!fxc* ztYGxCdTxUbACTp_tovMt#WezmoP6&eS7yO{O<0FR0JM{yi$*Faj5u26_naR!hW}F$ zXvj?dk{*QBJ)wpNtfZg}4>#vr3Lcq-P8}Pcu=KC>8Hl(#^DjuU3joYeHq0Gi_%=WO z!;}=9xls2G>;vEv-yQ`$rP-a&;BwaI;(h3utmC~9iu>pAa{!M^ZJU_4|&Q}*UDO@V;5%E(w8?h*oS z4u>O|=_PIcS^U}=izdR#@qVY}WG*BSkw(N#SgnXjCi|DRUI)g}w#gj)d;H19I3UxR zFo2(eORBWOX_LlNs38Tsp`c@&de&0SrPLdaM>h+bOF@Wl2%GpaV~JKeUvF1GKB$0| zL&4L8oN95b@%0&SvTv!rp}OYvsk+QmDtyX$? zXOGcmcb)LO{@RDjv*FluA;Z#wCy<>y?v1IW#NCq<7>+QgE+niCFe?e#PmX8BWzr~l zNxyc@A?;arHs`K{_>?&_`Y35S-;GWXIs_t+=E^w2^87rTp{Iw#%8C;c{wQOzbUs@r zL&@I`nCXH&5T;PtX#_>3%Q8MybFbN|tfA_!-(}x=_S7tW-b_IiGYi_8W6o${dW)HgEJ_?{Bs0#jv%-dM{ zq~YP8$^IuEd#T$_7iNh|_}_*QY)=@sIs*ZeS#mxw3w(-RC%5E#^ma z5&MhZZ@%=ljpX=hFas6efimi>He`xpXE>={q1}2mG;+( z#*hw&%hH_Bx%!>YYtDSELhJ22yLg$@+JrqnceyP6GUeNklIzp`7`@iqXUSB!EohEr{Z-P(!YdcvGv$iWa_9p7Kt{}uD*r!-*)r=yNh7-jamT+~jF zVwa7EN|8VTv=M>1BZ|%zPV1zkc~}<_PZNrRq9+PPZpp;(edo-*V;}-dg^cCzKcCoR6u)U)Y>P%&plcL7OBl-E98e&`;(EprcA&?`d?Sd- zXn@DFORPnWcdk~EV<*^bdB1Cm+jaZ%tD^ z1D_uqi-Wt@|61E*b3xdF!@=J~8;@B|v9o&Hg3j6Rp_!ppq;2)l zX(eC;HlWIb0ES_Zx?qsPgOH1^JfpI}nq6m2or%bNJ5LBLSFH17(COa`(ga-OpDW=r zJ%TFeGoEID9Km-tkyEN2QwE__^tepsOc6F6bB|&C_#H=>_ZDzqG6A`a7!hPx$q0y3 z6-cs01(88fL|6)-ED=;hLJCMRkr)EN6j-1rq(&@IP*_C;ivSc*7D16nuvr!{K>=hz z7$_`JWLY2zK}8i9K~@k%RaJt5F%(h>0b~VKK?R7QfP%4#u#yrLR6vqQDEk_Ai(4AW zZF4g*QYXU|0O`0SZACzmM3*fA^XICFac1Q5hl9JF^#3Oi7v6h6rgJ#Kd(!xL-Ao4? z@z2#OGX>4-qip@bt?T)efMXjBMldjLAYftG1ZR;Tj}S#m;tA@|2IN8cBufi%5-pLc zSr}9mVIH30WRE_`hVsh@QiYI*q@ zltw5pN8=kJAJ#xn0>lV0Fyb?Sadu7wf2lrvJ(uI6(-0p^e{5N=EOvHk)z|kP!pbJ0 z0M~%{2y>9Bt!AC13tdZ=`nxD@o?d*e94_>wrjTFlr`W5>IrGd9;qOc{{j!@uzuLPR z53oQGXkXrce`Me3ZMN91c}cA_op(4}@B7DXL8y?}l-Ln!Z>^Eolt_#yA0qauS#+5Z zvk`mNF0pr2wRY`Ii>lgNhw2_b-#>om?{m&|o%5XMdCvX5@AvCI#1gjPd%Srl#2~Zh zALW-%Nt9mZ-@$pNxxu49#s0);^;jPki5ic6Tehisi7KOA}9Ms=p2^i+5HZ8cHN@%?>?&^S5JVA-vi>*#lk19m56? zJ=$d6GF-0x{qoFp2lzHYw@Bd*!&FPiZFc(nGlwyYO&f`x?o=)Xs$a7+)w_*Ku zM;Xelicj2Zzdw%=G7%YLB(czpG0?l9g2uO8PU`7t!(Xf~NcQZy;Lu!ccg}%Bv?jwn znr6RD{RZ*&p+K>0F_aWfCR-X_$M@SqSCbci7#Pz(f9crwxe9swazj`8aG}gO(OOXs zJD&h*@WHrYS-WHv7pb(ogszYL5C$-T{@W9O?lHSW-T|54Mru6IP7bm@X?TL?K#I{o zz+yxFRtx{hYn&}T+?*zj2S!etEgaqRk_X&+7^Ov?nfBcfi2-uTLSZIiM$*Pa%PDNO zX~!q13=h$S%Btb`9e;qlJUuszNzjg@WVz2@{ixK|Bwf$&8ZYu;iH*Mr(2whW=+l&a zt?T)^2oFHGqExuYP2CqGe3JQlJQ=N3z^sihj!|ijUQPmY9t>_<#`NQ8f)*@x!;V*v_OJh5{>l$&rW?WMTvZMZl zyGb@r-v2c5=+b79AqXqbblIV&xIIiI+8V)SUb#f#iJZOvU3C8UJOQCud47BQ7nE*eOi~FZsVY)Pq|2_ zJvKuBcZ()T5|c0E+`$sq=?;lw>$aF+qzyp38)O}A6n9e0u!gT#^I&Sl2ao2E@ut^+M2--|!FABZQ2_5kvRZ9vc4W5lY< zP`7(;zXuuUP;z}(vadq?*4r$61b&B0gj%#`%60U#KZmX9cZJge3He)iQ?9C(u-AB+ zvVL*XPP(tqh{;NoJb3io2|dLV&8nB%0UCHRZjMGYm%-w@K^F_ z9FQwetcU(Ou0{R!lP;x{n}r$)e)m$f{F8Db!zJ8pEz}Z$?nRB3M9E;t!#_J{no`L6 ze|$r;+eok3O9kQeueN$T2m?axb?3DS!9?*`SoU_gS@t311Tp%qOZyPWwNW-FD2d3SLvP>G2Jbm#T*cjXBX8Une-{8Xcte-{1Yl{B;N5 zQ+fULhdWn>Sql|$*a7C8mJ7GQu>=6Zfo7Zw*!#b7*sCv9mj<|Uib@?U>d{SBUkH4K zfG)pts+a(0fmqpyeV(kftctprUy2&zK?mu6u@w}V4t-sUO~yd=1m+l*|HKD3XbZ>s zrkF@o_aPFxm$K}lGDuSmd0*#0eCycS+SXs= z5Gpy@$VAb2xXY^0Z#!3-{@LG(PCaHq1t&_YA*TI_ zJ5i@56_`5PfF%wz$+=0X;g(k`Nt+{LEkMH3+oM6woDQKI{Tw8w7r)ouu0LNvho@=I zaAjsd!f+%NVTcr$#v`dQ864yA%Y_E2LI(qjGf9c)k-;FkWNQ)}B;~*)BaDo1 z5fg#NlPF|c4iiKS5(z-PVb22LiKFGD3bA?;IL5~u?P_e~y57?D;IqPn!|i3?oCw#t zlGCh>jP>fYubU;l%GX&e*e>%>ER$WHBV`EYW8f~j$w?u(5E`(Cv?9PGjWc;DabP@G zUW9$}r1erODl{&NU0SP7t}+2CHRRy*uG7Z5ZfZYgz2%ZJ>}oN@7Ar-s1kEaIqqCiT zXBw?@B>r)COZI0d1Sq^MtU0IPUdH~6fg4pbUR_!iL(i~Wnddd4L=~#r5wc|EtVN*a;nH*cOToK6UL_8(;a5}cxQq0_x+It zMSon#>)r~}#O&DT-5^>N2SY8YYXC1U$0L0qN=?DMB+!?qmA1`{!JmYI4``yu9z|TLvCi6k`d?x(_VM+ zgBacI>ORetu@s5PY_<))y8(?W*{ne!rj-9b>gsL6E#g&Exiy>zecQ&k$)#@TK4Vp> z^;r|N35Ge2>sHHSV(szC9I(8nt$zdpTQA=JhgtR7`n7T8#lJK;M>O5in^INi$>308 zjL7Dlb?hYx{`@;>TtHd{x+n*Pl8bjYzc<=o7Ja=wP|9Ai7%Ljk# z9!V^Qhe&&8Y<~C<*Azv9zD1bnfA8x5(85v~6U*%*b>bvk36Q2o^1|4~tX?qQ7k+9s zn!+SvD@}#DVkPLrI?KOp6*Qm+=({nPdi|Cb?YA3lTiClV3$7CX++=0ltDriDoF>i+ z!gaa7r(=!ZUSCB%p^wxTHO8Di0u(bMcb-8bUKR^tIbP`2QQdJ?8no`a8Z?((bFdz*X!5IW*c`v7dvEG zO#J9cATcgxV|aAs7@uK(WfwoVN&R$ zYx<2_K=>5;WDu?<)|diMW`-uwgK-F+(o}FNu0qUSDisA!hFzXHjHGr+&OpWj>8x$# z5hx@*H5#hO%uLgt>e7$Aj9%@DfY>2iy_LOGs}$6@yatZR&_m)_z+fC8Ma-JRmJUH0 zp*Cd5v(vW?NxHJuyD@LGU-FwFc=xYS$LuE%XPtR68#q2|CMJL)dpsx= z1A%Y>LDra9W*8iS2IFFrFXLZ&2+9#zXDSPwPw~UbLU8j~Gcz+&S?mipp^%TyPyhSq z@b>I|1R(G8#6Djo+xhaGL8bqsCl~4z95{uhVk@sE*=id+I|5(-5 z+dY|t1wN0_k_ud;!6Sb1!%!Nr4_*Eq@e8Si>V>V9tisZ4C!$O(2~-X`FTwK$=B33z zb-cFpGdFFoG3Wpb1nd&8NAE%rh47S?rhxI{cs4$g14w+mS&4CQ9Q(D zVC*-n?r!Yw_qdbObQEac!qb9)Kyb}SD-bamXbh79>0Q22Vhx27OMxXpAjEnr1ddr6 zf+m&{GmLA9<**bUh2#+hJWp~G7c_-SlqVI5)=Qy>Ku4fRh$|ONL66Kp_E7|ksd}2I zypj!kMruBr_r=)srJxpJ(%pL0EYwM>GP;AD;v91(tYm)SyI1%=Lv;6VIuEopH4c)I z@j@e~%la{C)N}}21v)w~CjL)F;}R_B`!Gp^2#ZaQgiDNR77T=nkVOH_T+DhmZGPXh zYe3o?x41qfH)kLmShT`23p5%4T2cL zV1Uw8o>UCta;BHdKrpEYTey9xLMp;ybqK))l~RZU=^?Da7%(oGLQ%kgAl8=(6cU7t zu7K9-SzBYk82U?85-$0N&hvO6B08Yb<4gIweUgVy$6}BRtXv3eHNukgM3D${ZzA9J z2=thw`V*aSgYCtui*B}n-}wiZo~;%}*$XW5N?a%lG0{Nn;i>6^$XXPPU>uhUU^HPU z^~!oB^nk5P;h~7&&iKdZaynM1ujSW93^_dU!H#D((<8*-N1k)V7x0zYD zd_XUf>xlZ}v=V*f^~5~cwgK8fP1a?V;w_uF^Z3rQzvI^l=EnWH=h2!Sw=Jg%@iK8E^^x>D{0V+#b%*N7DAz zNlK3ChfIK1IEL&aB7A(+m+=oRCLV|UJ$u*lPi8pswafMs9{e3|faHVxgV=o74OGR# zoSW=YdIuiry4dBe%RUH?w`JF}3y#^QqJ7R+E~LkGldBpt{)Ep&pbIzu^~d??&+on~ zuY7~4L0gQo@SV|Iv@pBo%@?!%REjjv3*C1?JgvC7frZ9F{IMy9nK)rJ%0MKz5OQzr z7uw&ebSL9gGiZuNvYuE|DczJ8Rn&AY@Ogdn2IltKI0(~8siE}De;NsNx)|VCbWmek zU>C;vaOg)Xu5tkM>G(KJlighji;sATQ!YG>zP_D%-$GFQt$_`##M6!`Erws_YPUW5 zYlRnetM*;)>ipR3dGUL!=mMYN`LJWcu;kh|IvQ`Wc~0|8SqU0yE#8vR>Xr6U&Kk=t zK7GFgq$)&iq?LX0TG31!*a{g0oHBX*&z*J!0--}@ zTne<)m5JCg%5``Q+m^Ss^TS6aiN)a;XzikB+COhvjzw#S{SH7M@v!Tt#U4V?^B8tn zcvFZH9D~QuAqf)VdSgg|GF$hi=)mw~frk*i&|l9J4FY4B0vLu@e|~e^G}~Rn`ars> zXD7IR+>b9eHnSNfN$HR*T0rq(Muy7_W;aInZ= zs%61dJM>1!uVZa~o3?j7cdkh8bZly8x{*Unpfys=3hb-Hs5v|pseP@l%g*HGqq!Yz zJL^LK{-rhiu^M4tcGxI&xs>CF)sFE)u;71dhw$z6e(H6Mh({=lA=kuZRG1gagJxdZl(JBq2TPwcS60 zLua`&5+#bv=Quml{@yy>(7rSAD^P3Uhunv51)j(M9;s_ghU!1kZ0b?JPy5>+!hf~; zVa)R7ko`5y1u^>4Vz9JN(r2Xqxx#EeN;X?$+u9p;C~2 zG$_N^2oM1`g~|spGD_((?sN3R%sricizgOci;5P#AIJD%kekYj!$^MY$tX20FTT-c za}=4b&tzak7ggrMjNM6N6s{4pAY#~R6z1Nk`>y1!MawZ70#yEV(M9gvl(#_`AM#y` ze%vSRnQQfm#KR{a3j zCeyD5F2+`C{#^(NGYvWd?gQQorvKGdQMN@CGzvA`OyEw!q1Qd61SE$KPX0?^ zXzY-X@;&~la8;Uy!=RUeRl8#1Jsm+s)N_Qt3&3F)RiSmZ*r8|fR{g^Kw}?s^n_*|3 zTL=10(tK{N{baQmYaUB{KD!p(JkL~KYUaW3hrQqL{b+Nznu0HUAwk<>=wmbw4@Uo; zN|P!7daU*|U8}{B$y&u^gq>BDN*{_(FSbf|oVFV}3)QyWb^qk7?fx$GWa3H4i@9!8 zSRGaq#-g2QQqkf0I02l9KDbuRxe)p5%fT5}6Y;oGn_`vN$oo@kx0`JrrtSdCro80N zg6x2j{Trqn{dvzwF(=w(AH~*o|w*hp~O^ zA0|dM$2B72b&vF={L@Yqr8BQvn#m5QPV#%^;Z!>x4?F(6M6yj$9@>W_XGOtND)0Hd zcZW35b;DkH9*L3NzP842C#H@+nnRUWbNkc^ZIb&-0C|SB>hnBe`WV-j9}3VUbL_TWh2F9)zqP6L%b z_)j$22DQKrn>!ae*3QxS`Mqx+Qd6bNNI>IZc`mx5Ett%gjibHM%o*Wk$+@xWGn*m9 z#^cUGCHz$ZKQx+U{6uQY<4Gwj%Ze9Q!cW*f>+oN%SY&5#HaiogeA4`kp)mjjzVA#= zC@I3Ag$E7xA=rtGTqjWbt4jp|V?ZUW5F9J0p_U~v0j=CdX zSiTFk%#GhaUb16l$os)Q+25|6l9IFL{y%7Dxb_G3+(lgrY*qSkYy{nBAKLc8}%Kxliw*TUY~8a9RH${}l}U{<7V@Y#nA z{WF`$jXM8OhUacWPXcSNIoBp)PYaMpu&Q{16nhO{wD6my7u|^1Ix887JQ9`HY>mLo z%cx4+c7Kapp2&S5FqPja%|K%rsGK3{+km(QxowfK$%Ekpq+)Q}bhamaaF$_V8S@2T zg(^G=5Sv!rE|D!YJ62L7ax*SOo7koQPG8$P zI*NJcQhJ$hqzu4g``tZ#_viM`^adtyZyfy`VMBsz91Bosy`~1MI|JE+*Z=s|gBKBY z1OIw`Z??Ff31FqQmbqHto`cV z6~e~+wo!VCKEBlWI#_NraZp4zpw@{G*JZD$m-JHg?cUn3VFt~IvU@>oLd?N&A^Ikx zFb}{!2VR-9Pe)5PG(9-?4!*wXPrd$ZL#5oA4uioUF-9Tw=1@e6#}Ae#il}xg)heQa zRlOX+Ws>*yY(o{d;oEqmU5I~$;QVWm?ia@muOw)jsh`S#1#5lu%L9NWK11GEUZ^kw zg5VK7iZ@cxkRvd$zCzx;J;?M%Im})G!vm$Vy5bb>$4-^0H@f?6L+hqRL@2LHYLMde zdW~OK`*0(X{DiTqP4lFUQhg;Ro~d-TBTV$WU>TFpm*Nz%kqFSrCX(Oc`j-HMRb#`i zq1uH%JTtnmmLJ3 z;>n?6%%mD=5N{efR`(nMqB9lFk8-lB9Bb)-m+dR_&k$oqe<%iC?-IJJ;3d?!7I>2T zwlodUPy0kx5TvuZ4{{6sZP>tRDJH6W7?!`7>O9E-XzTa*miXVb@VzN=!h ztF!qtfg?55kY{AhsMGnCNyjq}8LR4HtD65rCRO$HOyB?fr)BS5DC!4SuWgc6-5)=r z2$XnF5qupqN>5Frur0&lR?wG$3Tl%nsJyJWZkN3T&3Rfzs8jvUR`al3%ygqe*}BsL znH#GlP=+SR7T4YN#0$r}!JELfynHfh`VN$-)G3P?d%`H#1X7r3;CF6FqA~X5Qw%Oj zVXY3tgDUx)j9vM(Glg$0F!+Z>l-|*cyX};1&Y=%AmQin?zu?t0=*4Bd$Y%uEaxe#W z`eKUmry?jvsj}}!`GfTdNnHD3Rx=| zT8T-;+vjk|w+mDLW3WQ@ie zdL+R?46J6t`5GAGR*aQj13Og`z*xC9_N_Spo^+XIZ$}Wzz4T^dpb%@^=cPl-N{wEi zx^Md18o$rH3*)a_RS19ZNA>H_H=$baw-SO0S;CO%!eKsS*SMns_?d=X$hRQ zL*Urx5My+KfVof|vjQ)_>$18q5zYy(pfB)n)dS&@bI7TNDFx-n_a;K*-(^Dx@xm+g z)l5hOOJV(ZpGC4r?B-g7ieq^Aa%=n?9aliMJw>rXwNhLt0kLoBv0~;|xu)){?{Coo zQj9*!b1_4Vn7hUo6rN9gT2UDpdVSquA~zFjyB5dDTQ4tO&ge|%-7#r77Uys#t4lJO8S9nO$wcDh*uY#JrnBH&PbUvU<(}E`>+ck<) z)NG=fFVLZE-~_)z(q3 zaam{~zkh$bn)x$KsF(hx2PY}NdBtOdKfPcpspuMSmGYW^cT1g3)TJ(FBO2F{NgA|F zS9kJ7Dp4DxmOhK{F!b@Uv5dEfqZP(>yqT&i_jSMkC)?;);~vNZd1@4;TR*zK0;|p? z<3}^zn8qgG&Svy(trJ{bRcrvEM1ARRD;tDXH@HhP^9=N?np6|L3-hI*yZ!wZP+X%m4At~*L$udaz_(0<3D9pWkBa6b?3?nwqtu9t=5N$Ii!T!`m#tt~5zh(O72Y1xHlH zo2d@pq%x;88=m?e2W*P*oOw54FoOoApxfccA;AYHWPsyAz}cnpDU{e#Jpu~jCGTDv zzl5sC$d6kcOjcrJ*Q81h^pTAA9tIG?o6pE zfhWfCP$_G6fCRrkl&6bZNjj+Umic6mHN*~;Ri(C^C|2->PkG=yf#Lw7PjReJhkMYZ+brHgQ8}ISg8^zynE>UiJ^oRvmP=4wp+)o*%}{YKZ_j4BiCYv9!0on%Z7K0Jzq9qI82E8QOUqskX+n%3d% zm*U>;1-{JNNL94-2*V3G^~PdjEV{#8@ zL_tVrq3!`Fi4IqvqDk{TJ=Hn7ps&B08~CZlCu{M|65)>5%I&_}J$e2BKS{bRBnItN zS>Kr`E2r5%lu9IimS`D2`cOYt@2k9L8{psR>+f_CIzQj<WdFbC75==+fi#it5P`%wmFOL<+Y~cwyU4#pW&^3A+5A^zafxa!AdDJg1fb5?WKsbb<*As&5HoZp{6M+@2(yWeZp`-=H9B&DU zu~ApKFM6z(tdOyh#cXKo=Lx3#KrV}U0VVUImTi%dMIp3|$XE?pqsripxx8swC6-c@ zZ)4GZr`kQ!zuxM#jEJQ>zdfZ#PsA^CZu;fwIbvzU(my=JKz*%-jpPK^Z~vGs zFA`@r^wQIFr50w7&EFCVmZ)R`hi+9^lMqVvjwV)8tcEa1fho9rv&xJpJ!Vpc2+Za6 zCXJIRBER?RAIeBb-{tv1B#!cqKndOeo&gbn48T~Jq{XlseR&J!F$P6zIz13OPdwbd zKaL3@^h|#UO0qAHx9-9=(NZ{CZ5aT37$lGZ!NJyeq8z`& zFAn$8M01Vawomi3CdV; z?{GuozDk~6$Bx~-Y7?!ta=V=;JShQ&)t!?ok~HjdSr#UtL`pqa;-DJl)lJCYREdcm z9raTjB`L*va8`1Lf>rU)$f?oWYKkeGwy1(?2CR1w26KBlarsA;Naq)(;Yre$@mGsK zUUfJBP&~h4?o<3X><-ahXjwVUd@8W2Rc%n$W|z9q?}-cIJ8pQEnPHkg_m#$fDghIv6~2%(mATQ1oIK2R6D3bm%4dtVc9raFb#}+_r0T+`)jWZP6o&k2x_X{I zt~HJ&(<*6cWCLpfYlpr191;XJ45LZ{(>8#qjfqfWIK;S;K?GZ#!pExJ%mdfcx2yHZLJdXp3>l`R9fBgiBTT<7bWeUSgQ`ysZHRdB@IR#oJdF=; zCh`sjHsmS{xvS8klc4$>3Ulb&-+wJ$`|zXYvZ_iC5*s^AP5dR8d{1LHc57GMQHaz}XpyW-T zwulzNYFEI|D!r;Z)qj_sF$aD_^f}zpFTsu8a8h@2e zSn(17>(5*B!Z5FnENY)2Jhc8BGrY)~qIsn8Qkr|Y^H;CvY+FcbQ>AAYZY?2L74BO% zarP#9wF~|ZJzga{Eca&tHzbmyS?WpULNM9cqJz896WK2#(6Y>z2g%p(B6;YAb40Zb z@!lH>m1YWEhi#0>5r3fuB)lMG*xN*WYIi!`0(ZtoYd|Z?L(C_8bM0*V>t=JB5=#3y z(NK3H9SFW;<@c4HSKzXr!L{7E#)=xwnnOAso6a z-8gu#P(b+&VI;-)lGljz;92pcVEw1{joXC7 zjlEDI#U-z%RDW%+R1Ih_$+K4XvX(Y`Du@Q2N!QU^>4567x@pVptgm?xD4@7yyzFXm zN91dXpZvfOI;|F7r>oyrAKOSLnVR4h1v@Hnzo{@Om;>?JqK)gqrH2x;QnM_QXB&f= z-|b~^<5&)&XoQSKC9*UcB_93P`zvo1F>i$y5nR+n-Em4=NpwQX&^}IPfVRLFvSn?@ zgy+X^;*sL{RbC#l%eOT~%e_YoJopR2!72{W9vnpBO-E4~<2_;2zS-F`!BW}LFu{>n zK;=?(ZkZDM2!ig+l~CG-nu4FE9q^C20d}nWV`R}B!9zHW@$vDQBmxy zm28K_jbLem$WKxiSnjp%{bzoDw@D5E_THBx*T+{vqvFK#Nm8k{3ZjQ#6Hro_PtH2( z7)Zg{#Jt*A_TP3)mj`+Db<9KY5WpDOsl0DRCm z=9Z$(wUMXZpB80&ram4DHKf5847{5W@18!WaISBn>HQ1;bL=4{MIWZ?q5F}fMWmYr z+-s-Osgt~-FX(sjF6K1qUT;@;Q=Ejvs+{#Nh4F7X09k5#^W;cYv9U*{pE`I|)uvO; z%WN{ObR51Rwfkc3WBN-!tI=dtm!?L)4U%-$k}Vb=FlG9b2263oid-tM#X@+i#Wef5 zMzB1(^_+{*yzDXfT?w?o z>0;>ihVU>L@&X-c#mxxFlSt?Velp=2Gv4(>I9Q;UxeEz%*Sl#_CBc5Y_BA&C=6smHk;anhueTS)BKx!zh7`6#iSA)>gRLIJ47q(D>K`aF6HR zdJ6z~s^#u9;62t*4Dekm6&%^xvU%dq1kfne5lUHkN!z8uld>2{PU=` z-4`;0Hafftx-zqgadianJIgzV){v?2rHErM|_wCg29d`>_EJU*qYnq`X|v zxIOsXB6XmvFT6l{n0lo!SCHZ76+spanBk>MoECL0Ez(|let5JFfuS+kKT6EM1s{|w ztXgmp6*VIfr@8|950h=ZT{U>)wxsOrnwQaJuU&!*j5Qm}FECnrwjktCNJnKDZStK_ z^CSDUf){qT%$JLQMMXwRdcBC&xn;gPeez3o_Vht~LJyEqb!4Sc>?eIwYUem~5Blfg zN+Xv?jB|2vrJleG4L-vinTSn61lB{>lwy;|>Y*9nMDXEXbqQ3cRe8qV5n%>*s zmix&0^mpMQkd1wTQ7Q^sR%z2)r`_u-HF}XF-4eoQb=P|IPaP%dXo=?a#r z84(NP-EKXFg+^@#LA+;1+SS)?p+23_dKoBQeFTh_USySNd(&UaCHa?PXsi?QL&PS;nlnkWk*v5{uc>J*Ga&S1-Y|^FlG>!1qCi&TcSN zjUII=o{ftEWRdrgx0~o}L2M1IIv6x{%ddF8Zu2mA+t*-x`X&0yl>klcpOKcN*G^KC zcTe#nLWLtDKRt*My>|seH|(wI$^52&FXbW}KxpbHdW93*0qhG1rlSJZg_qdh`KBE~K;ZRT+;c zLkUXzJ^yWI#cR~;hLw?pzWrM>WA7thyIYBc@|f&M15H3=2jx}fIumviUqwYxx-hfb zMlx7F_}%H$%rZs=j|6F|fj4($w8LS)+aIMkJ->*Uxs~jZ7WpYT;zQNeuF*qaW#rv& zx8}3J`^sQ}cq=dD1-f43L}l4a&fEO^9lkszso-p_V}Z=6iD!45OaSRNmV>0vjX2uZ zLPNe}z74lq9c#Rqmb+yn!vs*5#JMRsncK^L;jP{>Yff7AiF>sjMj$YVOnOf>kRn4=xmoTqWoe6H9xO8|Jh zUB?=EMvY#aZ%cpj#u-)D*oE$bV@$0xny#P8Gd$Q5#ClrfpP$%1q7BLS8;a5fbzWK# z{{!w^y;FOk7U;Wi@ndc}YWF_~oymU|Izg^r43+YjidWPscGAG(vc|uV3xq`Je#*N^ z1BuzZXRd<{woHGdws<_W-gD^;b(^@BCS)124Ud=+;f4}71_;5?7o~)w#8!U&9Zthv zAGBakWxmJ%(iPaF`k;1$TrazIFh9;A45Zqll zyWq|LljF5g^LA&c{I1snp{B@>GsT~DG}cT0)a!xyukwJXMUb0%@`Ur7;qL@HICxux zMCm{3dCtu6IoL*Dc{JVScgyz9;eupnGsTFJDdBY*-{jKwe+Pp=WvPJj+e1pjTf)0} z1|hN%(+%GGM>6+*K!x@W(_cdwlM>wYCJ_Z;QECyTGH0$-UdqB557{@i^0!O?zoqT3 z-t}LXu#FEQQbi=Hg!?_x3B3F6S}V`uUKs4V`ar!c^~>hpT`x&*OhwI+Qqt4ppul_j z$rmb!;?AQiD@@noZqc3pq(OSiy4?bRCEw|q=?#s#4 zuKx>*DsEd`%u+e_faHyzK8={??#t|x&yjZ#E-u6mZ0~85R1btk)oF3|#X6+L>}M~6 zw$ZIEC`^r=xqXHoU}r2Bz1u!@4cpw)ps%N~MBUV{yuqjQ%?e}~9Ue5zcvTofJ0hia zzI$T)eV<{^+tkX6dS+WD4fXN2UDfa0-SD%aWYczKv|HLLPgw;)z)RbU?;FK@}3 zqAd7efE^iWrw}WOrk@fr#8yeAXD>HT`5)=5`D^&2-sdAx!63P@?1}&B?ZG+Yx?f4LP!h>=(vj3+iQIeW3KLQQRZQU!lnvDXAYcfO#RDNNfKG5x@XLk z%Lw!GnG^*Ux=sg1>O|yiT41K0pcKEW3|lg<%)mb6m=x>stqgu7&1d1cR!=$foY-q1 zNT=$a2fAPEZEJ-6!}nYB_n8dA2llBbry$OUvzc_i!o2b&#P*ESI@sFo2dC`-o7FOd zo~;E2SmZT*DO|Hx2<{5}LTbHe<1W?DHp8ON_I0<~U>JezqZU zbp3CH+hahiT=4Po9Ex%7b>OS?Pp@?8rPYlu8trvYG>r^`IaV{LU-S-W(eCkU$YJkx zaT;fyw9hLp!1;!ZpD&K(vH^A50UXFwsEG=$u`!07vDI4%&VrqpH7U)YzLi90UFvrh zSO5NasjzS5KsR>4GQRNRpX%UwhnlGVe+WYPImQl3wwkX-yhKVQ!UgT!Ovm6Z^YK5ShxD3n(O&LDQ(2(<7D{1LsYcIE(A3T5GJ7tbdJ^L`$5}%p3 z@?#?cxQINNEAF6~c;wz9{ zL~}$w=`N2H(Cy9)W>=>ZM2D2oKlV#saFe!Cy`CXJ_~j+*Ut$u95B)JG7FuLw6$w~> zZ;+d*X0S9_bt-hf46AA<9*6R6!s9m^5}C}Pc!?t>J@(4M)EXs4DWF@okb+2-t=g@= zABU#~b0_FsnineCvj>9QN}FTUvq=I>ea%S?w)ZJ_XAkbNT*qss59Uv%G~B%L2o^U< zdXwl*_^rDq+BCe!Mvf?)Wt&&b9bh!-(J}XI?4f)YO8fEJ*LEFU7l;sHQF^|%a_qksJb(TvGLKZJ9J#8>di8akv zUUr?lvz#6)*s=RZKu!I}-P=2_chsJ#-LL!6O95HJVloNuN!mNqC&%H6 z-j3qee|`DBUm4M`_f|1YL&?r8xAu|Pe-^bG=g+&o-4v~&I)fGy;^*UB5!6F*DF`FM zvx0Y(*VCRh3JkZ}clf@BeY8KGD7Yu)9@)-(>k%)QtRXQo^zM7(p_XeNJ$s0BRm)Wy z8n!3Xx{t%`7mkb#%CDJ*=5s;SjJwyQROnK5#c`DuqP8cJIcw(3-u;$F{J}1$r6)SZ zU|znEXqh^`f$DejH36pIC&NFXKfacLJT@%cH$#!k2UV3-7l(pNtBco!(PNC&hrgm; zJmqCMzy4zQ*}-W~)HNpBpkOK4Vd}g}(ekoS@gR1%jnZbHo2Y=oPP=4|#_au%bzfSZ zJYr&{!qX25v$3mwMZZPJC5=yP4i7EN*N;rU`~24Y8tdQ1Mt-36-sp#-PrU5pDv@~5 z#^G@xVy>twvRLu|0Fgj$zdpRx4lF&G!4YID$?Z?3Y|^R>glK6@8eu5sD0s~&-Qlm! z705|r9$K)u#V$fAM2{;Kh_L9UP{(2vccZ$zc@fu=Vj*y8(&?~@Skt4_fbfX&`Z&$V z$n57kn8jc|UJiHN_FBzKseJZgdA9c2K@xyQiwQplk(R1SBBq)YOVFBT$)+e_Zpl1{ zS$#5W=shIgF8^_2Lp!)?B-XlF*07<&Rkw5QaeG1E75I+xmNOKmtwMI#9SJ*1 zig`D}WqYVpd8V>Dj^V&Z@7*oH+j}k@XE|(UOkZ;K-m`(+EnUv zp z<3!bbpNX+ZG@$g}BU#vLYWUjIt9G*tC_A{FwDOa8gglhf!@`@y25PG^#kSm189I%IlAZsbola^jvQWKg@3?bl2r07-?p)ru*Dpo?X zmej;Cf|F0IeS!y=leU{Z^tnTwu+t4OMI+JTy*ev95WU;aD59^KWr8O|QEj4%acMSZ zOD5X0lQEqv;XRge$Z(q;K4&&=lau4^L%^Py!4wyoZ?)lqn4~sy0UQY9LoS%+vZc>5H)QW z9wuSgO>(D77^rym%{je>#LF{drqS1d!^c($Bd9}E%|qg}$_W$1g-+4or-S*LCM7Y!#xkkJ*BZgnQ!d!; zlQ4?8M8pu=E|QePWy+YB`!W?61QKWv6wTQKLs<>ouC{YpYUU1{H7=zNW@{`Pq7Ix^ z#1~EuS41SG$PqGNQsRQeNy3MYWrr1#OlgIzSfp+>^MWSHg* zE+Qntbki9Cdv*ovDd&m6hM0N@(8Z=6dJwY`rosr=5wk3dp)w#RFft4okSsGG zF=Rl%U<)|WU%A&Vze>|%)=b>2t@9CevMY#3{O zF&lM^%SgKsRn2C!)ss>V-flS=q83g%sh9Y3w>M$pmjekR8FWBwBbd|Z`BdpeQUKkz zkubsOG#R)d_Lbr*rxo%|B$3pq?!R=_2Vq2Y<9tB$A0K~@C>Bf4jvkQ}%?^Z}OHkSx zjY(kj2NMiuM&%I#9I4eY#TbJRLJN~p^*8BP0CVG)f4cfzfej0fP(N!Ju0GiHNWl30 zZzI%k@LH4<^pFJxSIiJ$g2ytP#+Nl5CPE;sA~p1sjx>hWTG$zM>U%p?NR*(WJjRwR z(!?;*B8O^yek#R55x-Y9RIgec6B}x^sPolc==v2%ur%l+)Hykj6G~F%nHm$~<{Tc{ z=?p7oD*f5B>|L2!qaMN+_G4ccK=!aa1Zm8M5Hccw%L>#~h0Jo$wG4DaT~rLA0ET3| zWq@fDA%5#D0YBj2e03=qzd=(hSd>{l|%6&?JxkN0-LwzRa%WA5(l7> z)2g7U3$dJy2@WbqQN;?i&|}-MuaY=#enzZbeLUOAU5!Zb<%wcB)P-T>qLOn>bM*Np zcdXfm9ok&bt*g`j#4L)n0H}8g=!tc)Ri^ z=z-*G#7BsRb0A=V&T+`VU@36%Vd8<|H8ib#gJ@8;=aZJHKOeg) z${ebl;oZ{SIxN71-i<1rv1rj2G;gtqT|>g+`V9buOj@)-Iy7ZoTIW+^owb@U&p~-c z`sEG?fo_$nTC@Gcz=&@id#z68K49Kt}nDH;s*SmJAc=P&<5_c+`s%M+& zVeK$LC0PKCOlDWKVy7GO0gRAw3U{zjq*K~j<+^HI8`qx%YL47 z;PwSk>m%AA6XHBfaX=BF3z+Gtqxi~@emAh)7OvLvs**v15mKn5!r1ik++IhI*|&lR zlX9{2>tN!`BLtE@vRtYNW_uJ7^uNRV@8tS@zxw=o0ni8lnSew<%5y>lKmcP7^+gF> zB}00BJFl^qbY695m~X?da9oh;I>$X5T)Sxcwlx3<3=Xa8fPBylh%j{^%ll7!!f#Kl z5F89+8vXj7vCT9L$eI|TjRwBjEh)tn96tF_8Bi6BP{o*gamrfMdQGTn5ro_$C&&Jt z>%(4{PiaK;m1y#qm1=&bsElk2gtf*EOD$=V%Ix{e(Sme9zWBe^;5n#`*%h zKPmSOB>@k{XZ|}XqM?(0GJi`x^RxXW{|A%#-{a9gBUL ze&qr|EpHB8yf|(v(f+>110y0bFYcdbh5WK){1b4b^Hkh2#7J*1JJMy24o2) zVFdvUxqHU+ZfOw>!M<1#j1ATW8=g1iK0&GGo5T<>T~7=!Ka8^$=Fu4lE6MF9s6Dvn zDn=fpA%M_C(7tn=m!8-(0N(e?3K9uKw&XOaCwnZ()$KMjT$3`pIL*cnSG4lipxf}C@P zU@ZagFl>PfVXcPq+3-5;bw9`Qryq~;{yW?KFU-5W-Ty`Ym!~9wIeoqn10Ky!ZZCoY z9qdB@tbu63K)@d;CW7XIZg&H;r!%d;PQ zwy)tozFxXMKaKr1Vm|-ga_SXjfR{bX5!$gBw`yAUC$Co3iuWv87X`6!b8Qo23ed+g$p#iyk(n32;iYbn+wyrZH;<5~kcv-ZJC_S0oxG~G4$n;9y3I0hxqD97+y5Wg3B%$kP^Yz+Mb|(1 znqx_4&3)oxUiVCy579@&o7VgmF^##e$;qd^**x}TTnp0E$N&4C@w|B=&Eh80U6-uP zX0u1x>=yPKkUE&o)(8+V>JTu!1jA-IBLX^7KY`~AuK=Nf#g{NP1LOvT53`HP?}9r^ zvM3>Dt1k)qT!=)iH(WTw2!1~xXhDoVBcL%x#S8GCF>wtxl`CohPvOMC%Yi3>vW*zm z44|D8QM!?9>Aiif80HNxlPAsjO-iq_AdU-eEWtXA&*30`7O1^|=mqBN5Ma;;0XL5Z zFzk+im^LzGWbUG0dG`F8=ww~T;11(xAB=A`B|6d78&4MTvMRbAj5m*X@`!P|7*P&7 zA@F6#WGKc6Y}V{wu*1@BQKHR{HM@S^6Ai_ypQ09*O#9Wgy51!Ou%-<{7%LYsblQvn z#^T4z5ga!g(S6T>10Es;j~=9T+JMs!IO-1QULDbDKd67F`kwFam;bK#6ERo#ztzki z+HEAv{!3L?`W>FvTHc;WAY&NJ0KLYmHAoiVHS_Z5zlrhr&3MKvb2-0$$7Fc%1M|il zA=eqvw+^&@G1>+&ehs~{adHGiMfK_+fe{fCbDp0EL3Ngrj1TXi656Y&FgDn+-g*CL zgmn>d1EqfYFdj~f3;Uj7!e=kQPn>;0S}0_YPVFG_Yrj=W-+Y9(r1_pBf5!W76_w|r zxpPS*l2KJ8o`bO1@ZOW8=soYw?0N4u`?_dp>B+hDcD2FnqBgXW5S%T7*6LQsL-BQ` zRbQ9t=+?LWv6+%fRafRdcl*Y*w6%V_mRjU$q>@QL<395A{5ok$|33+nB$pf~`kU~w z0jSoQnVFfH&N*I>(sj={$V1f*^ldKvXE@LDB3SR>020^nQ6!UXD4zH)d5-Jo*$vjN z_t^aZRp9h!l0tp1KOL^(`R3P1imFXIsXqQyfB1X9!)!2LLeAxpooh@F>5n3zw5eHt-z!P08+N-hJI16SL=OkXed@hz&x<{&wJ<1 zRaIBzE%-}#C+xr0cpbK1+V=j_%IB}Z`uUPWmmy!CYOliEqFSR!)m2qd75wkk_u=X` z*;RgDwVBG*v$^apw5q;_9{20E*?jNIf1_IB7OyK+aO})gRkp9u8alPFjJ13FW_x>8 zeP)B>16on*Z}hF$Ac^Ts0h#66+%0V^tdhz*2BQi?@Lc0FIgvKCpc0E#F^x!a#JGckIt+@7;BRd=_|Hj?0~kE(CX+N!#iuX&=Y zpM#jHBC4x_Z_nrR|NZ@z`}`jHiYhDG%*FGqRq6MR?zFqx-L+L$;57`zPNV<`ZJ9Ix z)|tVyQjEdszVa*fhgI(VV_Ij@q8a(Vv*7y9 zLwz-(>ejy}ly*W04x~7L_swQ&26<3seEJFT)}tM;Fo%(-r*zK|3Qf3>=nsXOsjaf# znurT6+~%xHnBV@>gah22s|>!7$qDT-k1B#Z{e}|M6Tl`=GgGXPqh$N##%>$kr#kJ> z;&c$yfa>bY`?XnulIz|3-5Q|VmTa&b1?BEO-tH}80A_M?GChk+s-&N7e}ns;!5orMdbJmf!W(I0Rp=07w~mnQ79LSJMNAM-DTnqC`ZYL!r9I=3;Ez7uPpM zV*8I}FFl4S%afPvNIGypi+kaU!Fm|6e{svgB^r$v14grBx7TIFhJn611)qRLVPKg# z6x^DJF0ZrF&jVX?&R}zmSzVQ9ubI@PT_?kV-dXm0zC1%NC9G+$!QN)f4st8@IRr2V zI!ww45fKp)5ofQOR8dh@f&^4Vae0=j^;Z8#(U_tuwX2r*ZCou8RbTvz%lDT`tLa** zze)P6&lf+U|9Smfgx_^lRsDDGbQ;&-+N!Fn`cLcrvszuxCQQXuU*g)TtNKe-f33b^ z|2o_YR7Gq&?8RGewEWIus;}ek^Ig5RRaO3$!~1`W_gn6&qNBWMs;&RA*R3y&YOn1r zU&pmq&ye+xX{bGRzHg{mT|wpyyI?k}iw+q73=)%Mn^s;cKa#Z_P39OOht)5WDo zkcf)UvVL{_#YARt-^P3|C94f?K-*9+1FtRJOVp9}CP0uuCx4SKTC#5KmLQD*?NQtJ zj`gG@ekwIwQ!zK{n(uUtFb5xO^=a}Vb{<4W6sa9UM87;0@^PDo%^}57g zetuXAsgTg(MN@e6MS}&lSRK=v%dWr=W$434``!)=+wQUvUu&=|ybg-+?cMkQD>G|o zDzZ5d723zN3w|v`b9)1d1S$j#Elc@GBN7s;*D> zW-6-u@7{baw5qH5yH$9#RaZ?F_cpKI+PfC2s;|6uvlsnVs;a80`Dbk7S`kqnD&K?A zn6}khYNr|}uSDnzo!56vZ-q%5Mzb?B5fKp)5fT50eVnrY&D{`8B#>cewJt$~AvDmaQ(_joIHV@KHgB_= z?XP7ue;H2p{`iV0qKcMh-;I|0)!A1(-jJNQ;w+nP65cxAT|Og2pwVANAT^N2H%

)%!HeaY!|TMO5c)+^BXBsAJ}J%%`lZBy}j zm}6o?rY=c;`l0)6)!s{L*U)#{F2;?gD=Zv|Znw*>B1d=W_&4WZsKz%yi?oJ9L4i88 za-Xs!Ql;lxQ9*zgLVt(#2bbXZ%r&(`nHu2#EB>vT%-az6Ur*HzevGb2CjEiXuyY*e zG0t-kKpg}qFsPy7jK=k-u)w$&=u&{oN?f|6axLAU78g_VBZHO@;GHRT@C(`7Db92$ z*zwH1E1E<>Un#eE0>mPZ@$nQHD(M2Qk4N#A&R1x0eX7>I&JWo!9$Q)8Up;0|-45_p)oWF?pUD;HE9tMxT9&0P&1N?(L#*`Q zu@_WQ3P%?!c-4C`IMfZG#TWSJh(#fs7+9iFbV^5-5~Fd+=gf(a?{yo|Y_#kQI)eCHfTDI`NMxg%K<*j1$t_KqJYQH&ME)uW)mhA*K?!#EK z)RNbE^QIGDP?jKUp&w=_C-kDxR1-eS_C5Nom2dan9u{V`eY$NN#3i#A+rn&MtM0vA z#i9*6{gGzJg!QkM<6g$AdBvf9w@SH3{^$LV{U34mKkfc!x7v}J>{{Bty3V@jDwo7fSQF&@#Q}}JnOdEZ$ZhwFI3Uk=Ulfb2_&~}^{n)1IajV-a&+nQiWDfgF=sAoGww|c zUY;)_cfs(ZtJr8VAe$!k`Fl!Aip;&r+WPfjpV1!Im0(zo7j-kt-`;&Xy=K|b(UYYC z=}xI%qVtU8#L@GRK?D*cj$MAPV1w9mHPW)#46@svO_7G4N7DyrLc>x;Wcrc_AakpO z_^3JZlQL>zqc)0p_b4CC)e1eQp2hW{!Se&h&!XguUC3 z z)jXyAy~~xK$zHkqyWQjO*R8kh_Lt$i>h`x-p4X2vc!A6~%_;cuKWECBGLA5x!pGSAMcEO0eCv1V<6t%-o)b0;?~yE*K=)a z|AcoUU&nO0`I2ifCnKEaInHyO>CQ)$h;xdyy2a0NI}z!WD2`7aqnnoUj+W10He<$g zLIPxD{b__NpwK=uu`jeE#l&a+cpq9DG!SAAN86G#9D}J)N_87z?k4BJNB`MQYgQU* z(UsMsq3c?Ok$Ib^)bb>TZ%Ydc@`ZP^+^rwQYu2BF4Ye*>+!eJZZLMXIDM(SNNa z^+o-LA+4^`uS)~0@LP4=ztbBp-lL(nN|&KaVT}3UU6QCspKMXm&;@gmxUBwp;*RU_ zfy7+%>o>$Z=N)YCrfU(Pwk?T#GqQC0RvMX zv-?vKN#U-xZB9V>7%zJ#a(U6G0A4Hpzu|HZ&yPK(Y_IPgm#fw62X}anJ;!GOobSV> zVQ_Yi^WWh4we}17B`z&(>fW>pwC#CX&>XGaIYR7s;qW;{hf`4=I@ELOuA+39@L8A^?{PKgn*#}%s1%QBD`e`dDN?T2E2o}A*@s4aGRhWq+T zM<>MZ+6|_fmnPG%NilZq&a*ZzS*|k6%#E@sDgKTz&RIr6RQiEcHC&}7YfqNWdNg|s zdL?bI^*Pe+bsTl>MFbdF!AA*aN0U?O$>&m7ef}2@)!lYC{P&(?+|%!^?}q}2N1Jxn+)Q4MvS(2x;8Qj#%R&qY0MuJiSN}Qq!tWSG)iwB6yW<-KG4Y1(pkhI`F z^7j077Aqt&_t7C855Z-$dw&bk_}wno%suQ_n|Oy_L%waB-{XOJLK1lI#m>t3UiJ&Y@w7fpPdONRGN1KAahE@DLuCFWm z+wo_DxY}&8^ER&0+SS%UX3}PDcHi}=wTiaXqhSth_Qm{1CMGc_T$8n&!=dP^iGll$a3PqF&N>72vixh^QV;#_E@7zq*{2 z*oRUTmf`<@6+o!eagY`4GJyvgJN}t6K%F7Lc9IhP);G}}8p1iV+(8);j8q_nB#c@t z!IP>ku$9fL%M=9U3VN9VonqAO!anm435;)g08|iOVYUWHa|D1kIW_qj8rc&84Kvf{ zEJ-;eD$4grRcsfg6fWW3n^g5EE(LnNh`NZt!*#<)!?ZTdNqsHdvcoywCFH{8$$&5s zc2>y>sZ1Ur=eZpZe4x0`<}pt}w*KUs40q?J_r(v7h(0~R!X<%&SkXTo*NJGwGbqFD z?c)=>dwh--N31}fH8j`2)jlcN0KJPWse_k~YF43sda8)xc()U(O z3Bq$CMg}4S7C=0M5V(ruOG%`9Z=0Zbj-C!8bS)I?XxYi829Y9a)Dq3!F1SIg7HBvu z>oYZ+=eOJ113-R=$|hQdu!g${N(_SSUG3$L12PMted_C$y$)s;%V{DML;uEJ(AxyY%$XV#HI4UJg z?NDs)c+}0#b*rM>@M}}x(u#_O%bNr!!X7PvVE-rvRK}Qij@<5MXpsU4ggTI>c3}mv z&I9bgSWHkTCW!(BfkZ?BAfykX8+T0EP4b2zb?rDzGPN zscIx5Vy(IRg|8bvGdg;PT%|4`RHe9FXKdCo*a_UGB1%em8*)q2c3r;T6-ezJ6%#`ur>Ro~cR3gU40!~_2|w6>QQ19F?YjQTZhPu#Jx8cujlD0|ZD|m0M(qoq z9XJxLX&Bc4EMt1lS(xzDbuWl_rH&dwU>S8mDT_KxZQ$wEk@0nW`($>7e!0kxE>9fN zPEJk{G{oZja&Jc8j8E2$ykp)qh&a&Xs14#tX=x&&T8>pFEQF*4f-)>3Mj()23lStp zvI*X`I9iyCLcwvZgS+T79H}tmgGf`OI}N7JB&U_x1!!tVK~E52L4gqgtSC3-9964O z7ZU3j85C>^7bVb#@S6CCQtEzA(~scoOWKq}9Tuy5!zkyXffCNx+&hmv z=iyms0ty_chL39_v_mVDt;iUzIb(2B^$l{48`l9xA)1WbtH*5I79q`_Xydm5HbA(u z%kmSvdyKvU9C&_vajDfYfdjmdE}N63JpuN5LVB;Ho}(_K z{Y>V0$IO-U-f5$szu;bd9X0K+!MI35=%zhxoOO>D|(`d|H%`$X82)PI;n zpcbj-e{8r1e`-^!j*_Y>9aVZL>(4bEcpf%*xEJx&?cwwy?IQh|{GX%atb2%t<_oY5 zMG8NX2hpl32OxbQ?7>8~+5B}%oGEcdprLFJ4|mSJ3*Zg9|KXz0Ki+@$>{sNx;_Nk( zi#!O0!^td8Aq^U%T0#kg$kmt{@{&`Z)BQvuia$i$z;r@nfih5??LdP0j0kY25kZ}( ziDZzfBB&z0S@wdCeSpZ%b!%i=YbuDI`g*r+wSFCQ{IKi_ zG3^yX(la4#SZGmkvTjFYSPpLZXNRzAg)oX8;dJw(Y~z(ChYd&a%emm)XPhXCS9~3B znE&OfA28PqrL46KAkty6o4NW;`^|fX^9Ab-pRat9R21Uxc1)Lpe94fr4A57SnVRG3 zV)Az{s}^QpO@%lh{66qcwOr`C_he9hu0DO%c1v9w!03AzJ{Y{f>D-cVPq!`7im?Rt-U^5Ayv#vi&c0dWg51(J7dH=ctEiXTEi^7Yp}2V^EhB zgFZRKrZR)OZVCYc9;UA&UFV3G<)#NRhXnKKWvra7Wbc;~wb^ipyh$nk`NsAb+>0f= z>@wAOolT#!9Z7r&#>znE3&qVT0O_uE{q`vDR)-EQWopYda|6=b?-HgaJS4TiUIlS7 zs{89c7+(j|k666Ev~PkT@MZTcvHPfQedm%KgEq0HfB_`_{(!5!f5$2)H}_UDc8 z`&4ZH{cjeXx17%7OcM%iww>n6_k~PgALbmWkj$#^YA(sM*`=4o*0}nd^8K|AB{8qE zY>3(o7lg-LCNa9nWygSZUQFenTc_wS+dryrplAFIlO$5VSjmB&3h^8}RHdSe170s7 z?0J2=)|EJ9t>oAX0d9JD`=5^mty1?8>gR&{;QkjbJ(rnHqqnf!a+Ya3EB5KCGC=We z6Bd}kd~ib;5#0X=2wODAnfh*?R%%59+-de`A_)h!F#DBZ?%4FQKFcj+>`X$N{u4+1 z3B`BRK(ZZ=2_QvE1Jo5W*jAB9wu|^-b@|&jt{i<^^QbT|Hjm2Y`=QD*<~d6ISC54v z9#l8K_H)y%w^aJA6c_EigJ#MhAG`hIpU`aFLri?{-p%~qVh`^JFO$jco~VC2Y!khk zgXp|u6kRi96uujLhCrD9uXlJTQJ|?f;LHIhrlMKq4#qg-V~C;1|cv7v>bxTC$X- zVG6AR#ft`OefQr|l&f%ipN17?qI{NH7^A(#`0G_x5(ot0(K1ybp;ygp&i;S=tq4Ey+E#AnG;5Zm4{|}po@b&KHimdqL z5JP2>!255uqn!HOuH|ipy)~&ufNpyK#Z=Wy34QP(|@ebQ#ZzQ`S>ryc5dVG(a`vLbY+vv|7~7=Nb1S% zHvJ9NWyfxnFCj8y$!7OAdk8J!M2Qk4Nk5+)x`K^BAc6&aANF7Ma0##)d%qvR!8ZfJ zr|IFdHGCa!M`?ol+`MjA{^M(($Kj}Jo$cXTCLZ*QTE9D}->skb$4RZyd2;sU1Y5y~ z*c1WF(;JY<$#OGNa(4J?em(Nwk@Z5wb=_(A&bnNhk+aJ}*R9S7N=rt|Yp>*T9am(TLcdVRkcg^!>0$Hd{u zoAzihpDEuMYt^Px_)b^h1t@AncV#$2%)znr${TE(F& zK#687$=J|9tR1L zFp(^f$_(@8V;`aAwG%TJoMKptIw>q{74j`2w0IAYB;$@jfb1C9jNh7t)9u+}->N_3 zw|$y3U@HH=tgfn{mw4uRH!D-~7kXCfTl3eqO>AK~+Uag=ev(?rrr1s7GA%d#oWhBv z#XgM-m7azvLyYA$lNLHxJGr#i2lc4>ZdS@BPTrpdrFrFYU+I%k((;ttya&~)I&-3P zqDLZ2)*G!=Mv&+4Ti90SG1-Sb&Sk~-;qUN#E^E_Xa?G#wjilai@l`e6?b0Tit+uY#qI&Sw|3tQ`C$jvG61YR=xTnbypvcQu{L&U!ET?jQZ4y#Anje(!A8 zm*MVBb5G__qrW=`zP#zPRN1uH%$36HpWWn3_3!;gUNw1Lm%6(yHp5;T2HbcvK0hsP zPt5aO!=mxyG`Xb?TzgZzKTaAMd+8rybZ|6KO zczgt3v;MjZXcv9c*Sv~D^;qhtCxtg=wNuf`&Y#SpkiJC8i`&ph+bJoC>y^Upl>>({Sdzdz0Mw5yfgeebr?Uxw!? zeFBvC7sD>6M`zvby)U5ZdjDJgqW!0+p)C{Vzx+X@+9C`_BX*bpr^Wn_)9%g&!IgBP z$O`nK1Q$5`pw6F;Ecrw6m^JS=*|)`(t)Id#>*q<$$zC!Z^;*jg1CHaREBl;uaiq9) zTwE`n8W!6C1?k+F&~N_^Y!u+e<{?r~deI+EeE4tgt=qvR58l z(;FiPA+6?mu?WTJez<>lLeLXs2N(;DFXvVth2Mt%O#&H#jx}+Q!}KD`_-C)hK`BtJr%g( zV2o#5$-oTFCo|Rr<_0uz0}JsOP!Y~?M}0Yfs2ABB1<@ldtl+>{hoF1?r0gVb2?IgN zo#H*-f)peM65+7u9S21~28c2TSk2Mc@sx7`MJ?8MM1}UB_`;RvWE-dmTgx*3b*L403$Z z5ROC=7?9+V1aa(po9qC#of1V9Fsy)I0Ra;Q#9yJ;_T2T!`VsmQ%+8`6gjC_-#c!!Y z$3mg24M=hwP?wysm5w5^T(hiQR;ah>~d2Z79R zxK9O`AYbW?!pLI*Vi>+ioWiV(D5WXy@^^U*jH6x(!Ud_C^*M9jR$eQrb=u6n&tI== z4rD0_^3-|SiRszei;YD@?Ck2LN|h>9sZym^JEGA7ETGkZ2vP{b+@_f&jAW(;qhft^ zl5%MvRnH=_vy;x#X$Y_ExISLs)`)~v1~5H$LFS*^K>#v{ zYY()%&rz>-HD{D#tIG+<3HrTn)(Z~?ix2i;6gxddvLGBV-C=JS9>EjVgAPE0m(SEP zHw`Bl%=hiDsX%K0$OSAWFu$cksF8=yUuBDv!A&e^wO{nPXb3vS7VC8dzk}IY^$_Bl zxt~^V-A5I`#u~Ka6RFejFqZ`Ctv0(a9Fk3=*dAR1Oo(Attr5UqIk<6W2C|sI)sEbW zTX>UAbO9AQJvt&eU)S~iQ$Nab%j{A-7A<6x?E*$ELqC|Zh=B`MS?@EI zcDcl#VS>&LPqTk$$_;?OiGgGgHvCr#x2pY<`LX9*g``?W5PLIOz3QX& zHgPJuJ)V%;*NvWFZ*0BcNsSn3Joxzyc=C)uw+|I?^y5DxXY!p7y2ltugw>;omCHcE z;e6NcP6Gd(Z<@>Zy92PIuVJ44UN{aK49KrugB)R%8I7eV#}<;`(PG8Du}J)Fdw#;X zA_mfb2aN+h`QkQe9kfurV6{rkjstDBkaG9CGG?e7#wN|I7bCDN??B0H*kEjv&&~xh z%d_J#K98{fg{Mywx!bbVcr>=#1(g4}559LtoSO67wvFB1e>&BAf*jtLlSNxAkGA7o zZ8(bwwqN@1d7!U^88P`C;maOTX;u8?=y*Kp7beMGed1H8uWg0Cv0Kr+Q+TFXc6{mD zrhAjQ$7=|izlW6@;LJ2*sZ^VFp@aDD2G6E3+sjj5D}@7x*(QhHHPz1M zV5)w?Gu7Sji$%kvtNHNA<0I#9oTmKGqonja_uZ|S4Cs)bqF!LEseA0wJI`ql?IW#o z*gN&r#Aix6=5UX@ad1`X>8wtjTM~a&w_^PzjM_9Ysq-ku&2b`Qc-^P*r1duTy1K1) z%U8~Tz82SU8xfz@X?+B;DW(%Ml6{#_qiO2MqTef^@m#p;6~gFZ$|^NWTN7sHhamS$ zVZD5U+rvv)^LftY;n_4s*=n^DFaGX~lBigEHR~)twq26V$wl3!PHgQ?aM5wm-8|L* zGT#o}tiZ$#FzhxN>xSkkewE)Fpvr|E23yG04!BA;*8BMH-k85-zqlVOAe>(EV~Wka zxCoCo`_$>6<7x9e?d_y!cfH-lURC;~cpNUS{_y-ZQpMB#(U|B473s=V9TXKKYsZym%$>NYxtn%$M&Xe|Q z#*<+B_voB|&}?}T|C!5#Y0y_n6N)Aa&F=4e=e9r`=}wU&``V>+y5YUH*=piyIJd5x zpU;uG%9yqAC763wCS9)ZN|!B z@y=A5t$nQUna8ABCZ#iY`2?D&t_Q)5|1~5Zy21&Yv6tJxUVfW*C#X!e4WH$R-O>5_ z-fkX8%ZdA5epx>k?GTt}!Ag-Yb5u zZ+irfiF%E6EiIFH&z4=pM#jrR+;3KFptV2R(MDT4#*$Co#AaFwj`E<<&2iF;!6K>%SF$?njLC&FM@x z#Wcf)y~Vfw?Dx+tG9~GS3iM_2?fYcsywx=lmZcz)4I!>RrnbLRUgGF$({#l_jwdv# zS>tvQ)w&lm_9Xjues+ZFruUfd6Nr?}3fXL8*&I&eg=G(p zElws>3W*?%$`;G<v-c{)QM8arSz17p*{Vz(*!^BzZX8q>m&>>*;VVSK8B?dZ7Zgw zVqD>RtKRrVm{sTpIt~*vuj?;p|BBHs8hWi)zWnxv=6QS!zaW)*kFZxW*7$)b6P_Nvva0EOO*-q@QfN9D@w0m_F3fmLkKc+iuw>G(RJ4^b?I%&JG#V& zo9YOA;HKhp%`?F~QUhH=2TV6_FHw^d$%lFv+L}r-d>*w?7{>(G@=}fPHn)zg>!iNG z_;$N?3U9UBJWf8@r2g%!ztP%VJw*+VAqvtHfin_I0O~bSr;fwd1lP9|{UHz(E)UcY zY)%Lk3`llB9TO$P>c|b5RIk;(a(>j zF4UxMk+KE^EP@KZJ0|6b|a#M>BGd_x3W_0Y5rINTevNbZBhtbhJG4)Vk; z=JoMZ;uwkkt44rA2_1FmvmZ<}1{O#eUci%$QVMM{01_cuKm|}9E}k0Ds`OrnhJ?+t z37sG%?SMMRCx%$V|5J|dmjQ{7Ajp7SoQ$a0WWbrU2tigR0w4@6tdD@N-%z~EtE$S4 zw4YX39@M&7v}Qg78e9XCc)*S-`J-Ko5r7cA!0y^5aUDn2v8X8zjn0#ZCMmfQLIZ^? z4fUwBIiY+&33GLZd6Ho6?j1<&Vtm}jhQ`Lm3Oy-dX+e=j2H!a2>n((8fBk}{E)0%3 zvvPM1e8m|3QzO)hd7@cAMeJU<1q#N}8BSMkvO6!e|v9o*-%UC1G?Z0{518!By>3uN>Mq@;9Fvya<*)*xSnQ`EEE$(0m|4@ev(4=ET0w8$ zliP)vH@aeM>iu%4gInF`QRK*Kd5F0D*Q2?#)c@deHv=Jlb3Ydz5Pe--1P@a z@ADfkx36Zj3<78v0_o~wL0zBUAD@0ag|dJAI0;>^92Uf~D^#>A;8&Q+NGzSNF=~ir z0=QgPXHwf<5uY1HDqM&E>P5q_(huecss~I95TcK7Jtl-=Uf(jhb@}4e9tH{HhCK}K zv=AJcd(n0|k&EW@ch{a(8s%b+nBcWcP@O=9y22tv2o5GT^93@lq2XKY+h{R45gxUF z7yMR`SE*tXRjc$Et~*Ze$|ooO`v*@h?f&y6K;4dNb_EJuN7B$hHlN4SeH<_wC-kqi z0s~iU!#++Jf?5w1n8#X$hG~{fQ!3-k%JXA6xOx^1IGf~gC%}## z(2Ya&p&M7u=%Sf5HeEV4H8<0RSM}!u_vgzS5rAMFkcg?#g6+4vJV9DoQpduQ7A8LL z2p%q-5{YEeC?R~5W|wCBY8kq7&Wr9r&&5k``0AxS91u`WBzEh4c^JjmeIcGP2drE~ zmsj1u4Ixl1z};Qua6lS5*qkf=L>*Ees4Z)%c$79YKU83-C_|m1G$0UEE8mrXhv1#V z?K4^foi3Fw9EnUaCFKMv{q`ICdsM{?`@6f9!mIsWpXk@?L(ei?R|BsK?=}azTcm;U z>-Zb7#)ru4LnvI1D}CEDNetC1s}Q1fjY?P<{(i{O)Ud6@k=VXGrMyTaC?DXqE!-1P zJU2NCe(%2m7@4nLON>w|-a%;rLDYm}+Tw48w5!i>tufPj7qTJ8!-Onk1uoxAwYR-L(A;@g7f-cn zy(h2B3{SXaAszB6tb6t0#SoGW$d$#d^hcu9}N#sP9u z-x^%?G*b!Q3USw{6_4WQaW%XZohtC{=;T4kgt&6z1yYIo$l!wnFFg&%QHy?~^c#5l zwkp&a>VJsy1ZR3Me(Zj>e_O)FaAe6~c*sUeZe-A5fg#|E{n&6HJJ6VF)t_E@!hxJCUub(qm zg!SkVjqKf5{BNIQyYnP^3mkehj;1(PPMF-|73RV+)fUO%Vwq)bwY>C2@3`~ zP<6Ebsdru?@D-g?c6i|#jVvcqwq`Q5v-`WE>p#|9+J}6*g>DVIWGy0&A3-Sw42l3` z9)JAj;C1D@a&SgeHids~b0@|HCD7JxB*{!^9U^W>dr$`{%r8rpm}9wF$6h?u`1C zjV5J0kDcyGg3{b2=mN{2aDVZo-UFy_?+l#=qTfbPCyR3eM3VOheb-b*6`|teMXYAR z<$|sQniL8sEF@&<_E=rzHZPfcUz79$J*u=~VQ9h8R38JLQ|KuuV%*Se?(=e}+ZceJ z;jBF^mK0V`#2+U+j)j3oi@n~LM+URRJ>^5USH*G*Zlle`U~F$er<0Q1Tjjhbjt0Va zfh;SgOv(mggVyRxIj-rvIf7}X2L*;|SaIkf#>MGASuGqV19DP)`OdAu%UpD{5}AM# zS~}iV78gB5T@`f2RvOwkAV}({EoS}9Ro8YbFPk`f3oX`7SYDuxIQcTZKBfRvbYZ`t za{a-m0d}bPFR#^;lNQOr+{W@Yyg|ihQ!2aehTFo#Py?-(!fx&PSh5tFW|5V?wijc9)#|MFjg&IwJOMCeF(-%r&t} zNHdG}H!Hl^*I*sJbN7xrVDA_=az+gC!{!$}nouw#6I#7X7WaD3L`+^YhK}#lBThkG z4;Ma}k)LT^pFAfPi_X5P@OiQ7x!cN~?K`?ao$U{7dbaB*E+&bUXXYCReIJz%KVfXk zHBp+YFYy1IHiS_=i+_$F$|Se(T6}UQuH6T@7D>{vg3!FF4X}jt-szzHUbyW?!b0|bDd8-1SvZV$ygY+Lj6Iuu)9v3PXhi~lU8uWAH1VWpdB09= zqk*V!*dQ3+Z;A3i(3cgVrGpfVqCrM3Mpn0sqGe9`yJ@>fsTlsEku($bc|3Sf7o`X35;r1p>`nZlT!EtxZs3-+HS@}niiA9$& zUkY1ujZmtKgg5`m?qOg-lguox6AO`2#~|ba#C2{^N#SBmYJJ5V#k&> z6_)#aPT2sw08OpfLaI{O#1$fa}3woR*ejb`~Q&-tmd&$hBnt7hTFxWP8j$PZv)$@l>AE+i%5FH&||L*jyp>U~^2wl=s z@v2qpL$(a58%>U4kyglmYRbQ*W%(lZzJ^6z1rcO*6@yqcYF6Hn6T`;R%n!eQyJT|t z0?{5(1YR}NB#gRVQrQef;dJ@y8w#FvKbJmJl@XCU40?0UWqnN@U7gG%yWP+Faa<2J z*R{?vRgd}!d59yTQ&w~eSCt&7Kj-+`0=m2z5 znw}TCj!i7_NI8J^{STv1cmY5hlJNWwsSn4D!w3Ztn!LbMRMWZ;wV=x6U}~_iywKUx z+gdXj@C?=n;y~w9hUW4%GT8*ep`^41r>g|jD1T?OIS(zItLa{rv>y$$aLK39DsH|J zJn|S*XD*k4#4o>5vM%e2QBJ(5;?X(RU2^x=+|a)A5(Z6=&2K~0&Y{&4+!9I^s!J$& zRq?_|@ccla6CR6!gO(bkb}1X$(cHF+Qwj%fiGZDJo*mk$}dXm6BW{lFg04lGxv*l%lLL_@D+dQx z@28pi-3w<*6FgdGj6UHSf_X0=QydVz3H6#bihnLwoR(+VPR$J1!{nr}8b3~a8fl@9&Zu1?B;7M(ltToTvgU6Hy3c!}jy^F#PtAXvDdcvW zEq?q0dA+n!HvV85%n-^x=-MP*H`xb#o#!#~>aZZ;N$%jlh;{YWy<9t!%MZSOf2LuB zPK-&!KegdZU%6K(?wfkd@cwi2Wx?0h#()dOsVs6BHqt}OMM^w$#=m11J*H?kTKKwc z!*L_Cs*WD>wRYs22jisH^^Nw$h13A7yy-G0B%PAm0-020^Zs=I#bpM;QQDZ@?WNBB zJfK{i#pri94I)FI>GQncwqbJA!|r=)Fvw9h!PjpFG2w|Zeeie|+d|$0tt@od6-IsF zHDKhJ)@D4!%d;_BvY)jvNNNAwq|7(H&9&CWe0STb-IH77W6s+TM^u-(}$oY_EeCCnSjOzZ93G3*&f@g-R3C?u| zv8T_o_&ge!8JZLAiLGD(79%LeXYGS7`sYUXVNO<$aJA9tZL9vu#>5Kli$+POFfgoF z6ZieoFRc&znO#U?p^p7JukQ6~T4ExSEsqB}J(N9r%|iU+t4!_Ab#cC+mScscv_q%K8YaOC$Q9H^SSINuTj^wt zUDb#%n@^#}K-ancFpNvBOwD*JJF#;@eyDoby-m03xY3vB_{x2^X_0%=VDVGZ_HF0i zi%y`H9ECQ##b1q9pYea)?FWXv+v%oHE%pHGG^QkRUj)1Udu>jPsn+a zVW4&82A8%Hl2)NY?=ib9)yJ!3}HgO8&|!{QQtAB7)Y0;Xb2(qfh}2fWG*~*lLW?qd=Qm%S)`o ziBKe$gv~>MQNd#*CoEfRL}6M`qNPlX1zLx-tVJZXEU83*RX1!5H&jYegtbhBZKPDf z2@6wx?To^y&6P0}T8j&X6{t)~RFGq&P{P;MSxd@Wmq6>QKoBBF2pP02p%qZn@gp<| zqmj|WRV(|2)rSqETced#3v8-|#cRwXGzIe;_!ZEhKna(Jgyj*CHEd8R`-?0kL{tz2 z=lcarTErU!sefbU0wbj)VM+u*DJxJ^)WgGRtN>9Wmtj(4P!ceZ72p+&l@&0o3n?Rs zXdsn^72xGnP}c-hl%=c`N}@C=m49zg5{8f0G?yeBM%F7UheuKdQWh?2fl{L*5d8s- z(Gqg_(d)606O2f^!Afj^V5?lxWNGN98SV8s_zJcGAUXlOm;1G4q|nT8q-(YuW;T}?8qmv-`@%36P8 zlcUy56FGwB3#pLi)ZY@lx=4JyUs+aFN%#$u9sy+)U5e2j(Mw!`zazj|b7^Mo>1$|! zF<9l6{*u89dJ~;NnfG-KeIBT1YT_@EzIe{ESD-jdvbxU!X^@noS@sh}q}hq?a0dR+ z>2v`11w76(%G1R0p49CCQ;$j87V#bTt9IsE;1bFb{;S(8%B5b$Sq>5?bL>NP{pVdD z&>u&>;GlE2bezWpl02&pQ)1!KcfML%DC(&0xWRBpCmIC!!GWKjD~LHSF>Z{yjT(nC zKN{LicHtRrkD!wf8fRJ+8@3Re492a?pnec|eXUGO0rXdIquwusB&0b$P55;l@@=`$$g>D%zdin?%774@Qw07r1 zSY6aa9ZQ-H0?d7;45wh^kb)vQYzkig24n)Gd^sb(e%!sf@(=M)bmM~L*bFmWB0wfZ zrFC|a+_+!ny$5rBqM-bH9bYv|DI(a32xw>A^WCeq9-mb&3W`ZE_~w|4cJQA=A^&`V zBB|?TYIP`UgmRJ<9Y>IH_n;Mf@?m=ef)D_O-FEHGu>E}(+M!2K?Q#vuNG3g(2}jAu z5Htin3_>iR1nvHf%SJSPV_?QVVceW7A@5hrozyF$8any2klYG;SEa!6A1m7 z%^MZkLqe2DDhPKo!U6o=*;JO_UlgO7?2HfSG~(ZZ^JFgu3~cUVnL89C{QEa?oSwn*U&JW1x(x_oCy z+4rsXA{M!G^&q+k$_EJ|5Y!y3*6rwY#1+v5t51^U;2}Qu~t% zlG?Hl5un*l_DV8IF9S`vo1ur?FCZYmsYVgx?G&VXyB8P~Xx7lf0NJ+jHF*rc7XSyV zZgyR&QJbVaWXLk8h_f0P~ z{!)n~4QZ&X({>R$D8%3H;>Kyvu-M560N=w?&ns8ARKwEw0l7xM5Ljp zwp{nlV4tw+qh_|mYoK`XRYHTI0#II<c%Gt?wh{gJe&L>ve?#DY)Y=OXvTae8P+;&|zmgO2Wj z42fZm+w2d?m|7g!Vqw`AF6>8}ukz_Nx>O-Vjfr2S+?#?tB=bZW+WWVjEx1PioS(++?jO)Q z*NzA~RHj%BT4jp6@e2V%rd**gd+X>juH3!FoN%WAqJ^%wuB*bY8%_d%=*%{ELJ zU3Az4%c|`^sv#SyPCI2VXPcFnX=2g(HPpl`O1HJt#&&wnklsZ#i8bgRMcVFh&lD~}=2^r?6?2&o@9lGwN zYlV3+h|W(5#Q1D`*OPElfRpT^v6dbVA8lODwfOu&_BQ6_l^KLmKmiy85RM+UiO}?y z2~YygPliGG{YwOWBv(^MBHDa-cNrX?KP{j|5Pg8^7}$@Mh&?7BnI4|p{WDJLQvd*a zcFs*>UVg6roHK}5NZgtIUR00AUa$0Bo2jnrZ@O6TtV#MHL@y~5Fu(ESas)&LFn&fg z*n>s6h2N2nK{_jiTwQ7P_^{oG`s7SR(`IhUeePuE?q`9}E8Is{EL~daKh)25wN@~v z@V%x(Dy}4R#2J^5ZaVh{iF!9*!O0~xk#`+R?4`Vo`FDD8j$U@imAj#OjcUs)!U+ z;3}%BlA|b)0qThL3H<6P#8iL=2*H%={812uqZFv9>4k=c>~HAd;Z9;Y%@@ktsF3g; z)})jJx5h(^$Y=}s8#M+Jzivb5B~ zvnjY1hF*U>o`6p-%5yMS|6Z-Q+kZRx6~81 zA(Nh1X~(+4Rh~u5oyECPhA2{=xPpbiAgnGR0ir=T=qN)9#2$e^l-2hZ)Ip4>ItKh` z&4VltcQYbUoDD(VZ;T)yjOz?qLmaXGHyvKC|5*bjy^t{Sk00VdgCVhku;G<;Aicqo zF^PD&uQ#HM*B73`PndxM&FLmZY^ zz*u{@LnBRmg0+ekcxz2#xn_U_D&(KxNCCrP!hQ)jyL0*7d*jU`E<%bO)BBdjD8Qq@&Q2F9#Qy`Nif z1W*;{gCRXT9z9tKV%~!32dk(U!4?02qrjUhV`>->ATn@) z>!XvcS%KS?8^Nbn)?}p9GGjt0rWy(1lUNr^0V0zp^H(MYym!;eCT=1Q_)P0}t(vDx zR#URVH%C8sCt3rN#rgyc?*v(u5o5>~nL074WIjm{KONNPybB?!P^q@L9(Z_)hY@UJ zIv5aU9r$eVj-@lHbnlw{NiL>gtuOEg=k=lWKqTH!H1CHZq7ol( z#)1?gFA2DsKUY&D2tVnc9aP*vDIu4HsCr6Q$b_Hs=42j_2F6tFhe9V`lZwha7RiQ{OrZ?c`}nnO z=QI*mL<6l)5?*LDOE&U3-RJWClY|&p^`09yFahrDfV<81@vyb_ImnmzY4R7dlA8t+ zuJmz{Z&Lu*&QTtcFF7#Z9X#MbKc`z3AU`aOLNEm0zeiF8Rx8AD4v#>~>B%Z&*E z|G@u+*qd6!+XAR>2xy`oX%cMl$>(MCNtbBJ&CSgnJGMzFy}zT?n09)MF2Vf@#g?!R z0{$soPj}u7Yc25cqiP-zLT5$mq(KNH08;4M4tkMMrT?jf?$H2D+)yN&4iX^-gFus7 zD8J8INE`ng`lw<0&q3JA2H|On&;qLJsXD5m$>ep9GLa|yAUUhx#Pq+tTN`jw^C;w& zviqQI5ZMAzkvVP3_s`@qjQJOMR8@z;z!5eT;i*p46_&?G*2Pzm)e*liuJ`UEkJ1~v zFIm0}9M!a~IonK6yN6FJOIuZ6`6D>;j6F*h8BW{>KD4Y2@7Pl(d$nm^Ac~CoSJtv5 z?%|Ck_~9=_fuEDz;Ux~*0wFTzOvXi4=nwGEw)!n)0>YdQN+)P^CgJY|1q zz165~^g!95Z?f~zcy8_DYPUxpLd?G7ZX-E3YY!5ccYbqI(ReJC1Fj=S|8(DX^JITm z*H@HqMh0kW98?nnn$pmJd57WYtbE;K8)Mg}YhN#K`FFisVMF=xsntxEL@tx*|BsEE zXf1nMOtZp^{hN}Jk>UG27=+xIY-+RM;D>%}u}o8W0NPE#^0pnkaX3Dgnh9B> z#^yKZBt`PP5Ba z&?59wT|GQopY;AwW~vd?kLr}aecs?PA*pXEIM}UUF?rC-8j8+EBI8--^D~RUeU`pC2 zUg#Or^BQ3%lFd<9NNKz9tezsQs;!Er+pY9l%^ZM-hv(hqCpY4@JB8iS&oWt7Hej$S zdWIe$kad<$uV07orLNnxO?XTXm3cK3;} zRH>FmE?KE6GFX}Yh_>z9c;3{wlvz(Fn*A^>st20oCx)Bll1QNN^(7#{`;;1(Z7H3P zxMo7rpZ@XIevoNZ?}g68Xy~Va)iX(neppx+G;eHWnZ{KCkV!ogOFg191R%XMJ>Wn} zmj9&b?Hn7cZ}})yE!Ipp$(h%WTi;6#nC1c-|7^{kNG1?rmLI z%zE_U#`Adeq6VstgS(|@=h$G>8nf6s);$Ur4q{$vkpA!BC6`w7`P*txynF8~xUg6^ z_j&^9W|?O7DK6|)xbbF~AK);Li1;u)aA9g{=1sd_XatgGE9=?Y+F8XrBnDe{G71ef zv1X;E`SL}6&J8$Ns^zPT6HqVA8X_r7G;DhscxI*?=rPpE-fI6ykYhSGTCPd&C%MyC z(dP`L&w|HsGKi2UQeFL@qUGmJu{)o-wt4Tr*Ic?;$9ui^FDRzf*pD%{MRGGs9_L}f z?{9;PS$=qBAxV7u>$grC{AXY&*!p zNfP%QGX_?g$&T3?Xo|kEhaORAYKMMqW8Homl4|GOH8;b5?Q?jPe1~uNjw;N^8l5Ot zs&3Cd&{!_j6kVu9w*XF6Od_I`*86Jmcg|=S?CO0^S_(9yG>3bdJPd1VuwL5$5dHwk z`FMEv5jUPi8=?Qzd5NPGmAPjDGeP?MHzpUoa7^x@vGOD!z&JGA|}zVX_(8yTLWe>Efe!1u(Ijz8LPe9D%i`3JA1lL&lbEtBBp5r438v? zjJURX5j1}q-plnD%79ia{aj=pG>6$ABcNysLh!KcSk}KW3&#)f4znI@JIHavDVuH{ zJk)e3�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%0APWhk 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�D%oO?^g)X z;I;Ta)p>2*?o+{M!TCH_Y~`Y->qYGIl^*2psWy%gRj+?&Ojo3xX#K#kBp%K8lU}i=; zI1PxXuDd~Tea=9KVgO0J4ml3^XDl$$$#U!Vrnlc?baLl&?T5eL0suIAz_x*%_v;0E^(@BSxmK3qDUFIqNu2` zR|f{`9tf8-t4wj;+J!MwR^acf9bG%JP4dkNuv4re;fM;1I3#MTB4&_CB^1SPG?|o@ zRV}*TT!MR(b&mM)qWl?d?OU)1nvj{T4wqJ~lcQ+ATelz+Tp6`-=ru0eCAg6eI+-@w z93gk!H!{KsHx8|6(p|Q~<*QRkjsq%pOv2_mE z>~b}u1m6|89hERfF%}|=rD|nI7T%4v9a?O0c&va+t)?{1gxfeWN>z3))WarkhGvRv zQjFhYVH1jNz21YE8HMCpZW`M5kCFRRx3LHq_rCzY)cc)IdSDFz9%<*)K$ySv1?1>X zL=cHYqwsGw@i86+@DF%(K#uvJ80qcmt^6=>USF>?nZXu5!`W;QXw zDKtFrw8)A|zC8Eu|D=5{#l!+A9yl|bLYI-mw%WAh7*{Eb&PuAPs;a8)WI6^#gxqQrNeUz)#Uxn@h|Sr80^opD ztPy}Lk}QIOwy8?3Fi3OI+8|>jhFTHuJm4G?3hJ-Yb#<5_t1j|Z< zD3sNP+KFMLHbfNy#gwYrwAT3zIKgBTHzNy!c4ls>rkWzEtya>Cs*FTMM=(Ip$XS*d z7^4$5vP7uLLN(di-D3jXsa2UE2fw?f4%u;%NNp7ZLjZ;ey-^Wc36Rt*D3gH#LlP`f zMT)Wz+0|gsB}owp4bmSJ&4CDI*u!haYh|OVY~5I}V1p7E<%LJf@nxGQ$);6!$=|-48oXhVnap?h?fZ{P(;X5P#~#s2su*-p)mp_ z7KFell9{6MfV~W+w ziH@#bH+N&I8-+Qnwe?M%*-4!Gc&K5A!a9LUNbYtUNd9N%*^ZTChj7I8FsYX4c?*5jtJ94ynb#!oG(4=u;AnWm%6;htc*Uiqg%jO%J zE0Gb^>bY`2OZad(-HD1#!s;fzq41r}t5i^|(~f$T3GG;*eswoP`)K4b)>K9CB|$XjEc(<}u2OqKKw42S$ciOr?Oa zkmC)v&zCAWDGFU(Yc}&V8EvFf2AP<$LbWToI zn4UbAZW^y)WHKcjM+uP1vdLP9sAN!wBPE0~OVSW�E7TidP4dDJvy5Oq;3^J3d{< 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 diff --git a/package/darwin/osx32/.gitignore b/package/darwin/osx32/.gitignore new file mode 100644 index 000000000..e67764bf4 --- /dev/null +++ b/package/darwin/osx32/.gitignore @@ -0,0 +1 @@ +libstdc++* diff --git a/package/darwin/osx64/.gitignore b/package/darwin/osx64/.gitignore new file mode 100644 index 000000000..e67764bf4 --- /dev/null +++ b/package/darwin/osx64/.gitignore @@ -0,0 +1 @@ +libstdc++* From adff13f4abab1dc3a3665fe5ecde56117c5f0b85 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 27 Jul 2016 21:44:25 -0400 Subject: [PATCH 052/413] Lua: re-enable C++ exceptions (re 42c620b) --- depends/lua/include/luaconf.h | 1 - 1 file changed, 1 deletion(-) diff --git a/depends/lua/include/luaconf.h b/depends/lua/include/luaconf.h index 6578a6d07..1c19bbeb4 100644 --- a/depends/lua/include/luaconf.h +++ b/depends/lua/include/luaconf.h @@ -11,7 +11,6 @@ #include #include -#define LUA_USE_LONGJMP //TODO: this is bad #define LUA_COMPAT_APIINTCASTS #define LUA_COMPAT_IPAIRS From 41a81f902104ad20a50ce62be1edf10586df099c Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 28 Jul 2016 11:00:52 -0400 Subject: [PATCH 053/413] Fix some more warnings (GCC 4.8) --- library/include/MemAccess.h | 2 +- library/modules/EventManager.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/include/MemAccess.h b/library/include/MemAccess.h index 36100b400..3022688f9 100644 --- a/library/include/MemAccess.h +++ b/library/include/MemAccess.h @@ -207,7 +207,7 @@ namespace DFHack * attempt to copy a string from source address to target address. may truncate or leak, depending on platform * @return length copied */ - size_t copySTLString(const void * address, const uint32_t target) + size_t copySTLString(const void * address, const uintptr_t target) { std::string * strsrc = (std::string *) address; std::string * str = (std::string *) target; diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index 9133b48bb..dfb978022 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -348,7 +348,7 @@ static void manageTickEvent(color_ostream& out) { break; EventHandler handle = (*tickQueue.begin()).second; tickQueue.erase(tickQueue.begin()); - handle.eventHandler(out, (void*)tick); + handle.eventHandler(out, (void*)intptr_t(tick)); toRemove.insert(handle); } if ( toRemove.empty() ) @@ -546,7 +546,7 @@ static void manageUnitDeathEvent(color_ostream& out) { continue; for ( auto i = copy.begin(); i != copy.end(); i++ ) { - (*i).second.eventHandler(out, (void*)unit->id); + (*i).second.eventHandler(out, (void*)intptr_t(unit->id)); } livingUnits.erase(unit->id); } @@ -582,7 +582,7 @@ static void manageItemCreationEvent(color_ostream& out) { if ( item->flags.bits.spider_web ) continue; for ( auto i = copy.begin(); i != copy.end(); i++ ) { - (*i).second.eventHandler(out, (void*)item->id); + (*i).second.eventHandler(out, (void*)intptr_t(item->id)); } } nextItem = *df::global::item_next_id; @@ -609,7 +609,7 @@ static void manageBuildingEvent(color_ostream& out) { buildings.insert(a); for ( auto b = copy.begin(); b != copy.end(); b++ ) { EventHandler bob = (*b).second; - bob.eventHandler(out, (void*)a); + bob.eventHandler(out, (void*)intptr_t(a)); } } nextBuilding = *df::global::building_next_id; @@ -625,7 +625,7 @@ static void manageBuildingEvent(color_ostream& out) { for ( auto b = copy.begin(); b != copy.end(); b++ ) { EventHandler bob = (*b).second; - bob.eventHandler(out, (void*)id); + bob.eventHandler(out, (void*)intptr_t(id)); } a = buildings.erase(a); } @@ -708,7 +708,7 @@ static void manageInvasionEvent(color_ostream& out) { for ( auto a = copy.begin(); a != copy.end(); a++ ) { EventHandler handle = (*a).second; - handle.eventHandler(out, (void*)(nextInvasion-1)); + handle.eventHandler(out, (void*)intptr_t(nextInvasion-1)); } } @@ -831,7 +831,7 @@ static void manageReportEvent(color_ostream& out) { df::report* report = reports[a]; for ( auto b = copy.begin(); b != copy.end(); b++ ) { EventHandler handle = (*b).second; - handle.eventHandler(out, (void*)report->id); + handle.eventHandler(out, (void*)intptr_t(report->id)); } lastReport = report->id; } From 98230e90789879fbbeaf87afe94b6b9eadcb2f3b Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 28 Jul 2016 20:52:14 +0530 Subject: [PATCH 054/413] Send surface material with the worldmap in remotefortressreader.cpp --- plugins/proto/RemoteFortressReader.proto | 3 + plugins/remotefortressreader.cpp | 142 +++++++++++++++++++---- 2 files changed, 124 insertions(+), 21 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index c5c778b1f..889159682 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -408,6 +408,7 @@ message WorldMap optional WorldPoles world_poles = 22; repeated RiverTile river_tiles = 23; repeated int32 water_elevation = 24; + repeated RegionTile region_tiles = 25; } message RegionTile @@ -423,6 +424,8 @@ message RegionTile optional int32 salinity = 9; optional RiverTile river_tiles = 10; optional int32 water_elevation = 11; + optional MatPair surface_material = 12; + repeated MatPair plant_materials = 13; } message RegionMap diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 7a853db82..3e372547d 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -58,6 +58,9 @@ #include "df/world_region.h" #include "df/army.h" #include "df/army_flags.h" +#include "df/world_geo_biome.h" +#include "df/world_geo_layer.h" +#include "df/world_population.h" #include "df/unit.h" #include "df/creature_raw.h" @@ -128,8 +131,10 @@ static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage * static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, MaterialList *out); static command_result GetBuildingDefList(color_ostream &stream, const EmptyMessage *in, BuildingList *out); static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, WorldMap *out); +static command_result GetWorldMapNew(color_ostream &stream, const EmptyMessage *in, WorldMap *out); static command_result GetWorldMapCenter(color_ostream &stream, const EmptyMessage *in, WorldMap *out); static command_result GetRegionMaps(color_ostream &stream, const EmptyMessage *in, RegionMaps *out); +static command_result GetRegionMapsNew(color_ostream &stream, const EmptyMessage *in, RegionMaps *out); static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage *in, CreatureRawList *out); static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in, PlantRawList *out); static command_result CopyScreen(color_ostream &stream, const EmptyMessage *in, ScreenCapture *out); @@ -229,9 +234,10 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("ResetMapHashes", ResetMapHashes); svc->addFunction("GetItemList", GetItemList); svc->addFunction("GetBuildingDefList", GetBuildingDefList); - svc->addFunction("GetWorldMap", GetWorldMap); - svc->addFunction("GetRegionMaps", GetRegionMaps); - svc->addFunction("GetRegionMapsNew", GetRegionMaps); + svc->addFunction("GetWorldMap", GetWorldMap); + svc->addFunction("GetWorldMapNew", GetWorldMapNew); + svc->addFunction("GetRegionMaps", GetRegionMaps); + svc->addFunction("GetRegionMapsNew", GetRegionMapsNew); svc->addFunction("GetCreatureRaws", GetCreatureRaws); svc->addFunction("GetWorldMapCenter", GetWorldMapCenter); svc->addFunction("GetPlantRaws", GetPlantRaws); @@ -1931,6 +1937,116 @@ static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, return CR_OK; } +static void SetRegionTile(RegionTile * out, df::region_map_entry * e1) +{ + df::world_region * region = df::world_region::find(e1->region_id); + df::world_geo_biome * geoBiome = df::world_geo_biome::find(e1->geo_index); + out->set_rainfall(e1->rainfall); + out->set_vegetation(e1->vegetation); + out->set_temperature(e1->temperature); + out->set_evilness(e1->evilness); + out->set_drainage(e1->drainage); + out->set_volcanism(e1->volcanism); + out->set_savagery(e1->savagery); + out->set_salinity(e1->salinity); + if (region->type == world_region_type::Lake) + out->set_water_elevation(region->lake_surface); + else + out->set_water_elevation(99); + + int topLayer = 0; + for (int i = 0; i < geoBiome->layers.size(); i++) + { + auto layer = geoBiome->layers[i]; + if (layer->top_height == 0) + { + topLayer = layer->mat_index; + break; + } + } + auto surfaceMat = out->mutable_surface_material(); + surfaceMat->set_mat_index(topLayer); + surfaceMat->set_mat_type(0); + + for (int i = 0; i < region->population.size(); i++) + { + auto pop = region->population[i]; + if (pop->type != world_population_type::Grass) + continue; + + auto plantMat = out->add_plant_materials(); + + plantMat->set_mat_index(pop->plant); + plantMat->set_mat_type(419); + } +} + +static command_result GetWorldMapNew(color_ostream &stream, const EmptyMessage *in, WorldMap *out) +{ + if (!df::global::world->world_data) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + if (!data->region_map) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + int width = data->world_width; + int height = data->world_height; + out->set_world_width(width); + out->set_world_height(height); + out->set_name(Translation::TranslateName(&(data->name), false)); + out->set_name_english(Translation::TranslateName(&(data->name), true)); + auto poles = data->flip_latitude; + switch (poles) + { + case df::world_data::None: + out->set_world_poles(WorldPoles::NO_POLES); + break; + case df::world_data::North: + out->set_world_poles(WorldPoles::NORTH_POLE); + break; + case df::world_data::South: + out->set_world_poles(WorldPoles::SOUTH_POLE); + break; + case df::world_data::Both: + out->set_world_poles(WorldPoles::BOTH_POLES); + break; + default: + break; + } + for (int yy = 0; yy < height; yy++) + for (int xx = 0; xx < width; xx++) + { + df::region_map_entry * map_entry = &data->region_map[xx][yy]; + df::world_region * region = data->regions[map_entry->region_id]; + + auto regionTile = out->add_region_tiles(); + regionTile->set_elevation(map_entry->elevation); + SetRegionTile(regionTile, map_entry); + auto clouds = out->add_clouds(); + clouds->set_cirrus(map_entry->clouds.bits.cirrus); + clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); + clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); + clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); + clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); + } + DFCoord pos = GetMapCenter(); + out->set_center_x(pos.x); + out->set_center_y(pos.y); + out->set_center_z(pos.z); + + + out->set_cur_year(World::ReadCurrentYear()); + out->set_cur_year_tick(World::ReadCurrentTick()); + return CR_OK; +} + static void AddRegionTiles(WorldMap * out, df::region_map_entry * e1, df::world_data * worldData) { df::world_region * region = worldData->regions[e1->region_id]; @@ -1948,22 +2064,6 @@ static void AddRegionTiles(WorldMap * out, df::region_map_entry * e1, df::world_ out->add_water_elevation(99); } -static void AddRegionTiles(RegionTile * out, df::region_map_entry * e1, df::world_data * worldData) -{ - df::world_region * region = worldData->regions[e1->region_id]; - out->set_rainfall(e1->rainfall); - out->set_vegetation(e1->vegetation); - out->set_temperature(e1->temperature); - out->set_evilness(e1->evilness); - out->set_drainage(e1->drainage); - out->set_volcanism(e1->volcanism); - out->set_savagery(e1->savagery); - out->set_salinity(e1->salinity); - if (region->type == world_region_type::Lake) - out->set_water_elevation(region->lake_surface); - else - out->set_water_elevation(99); -} static void AddRegionTiles(WorldMap * out, df::coord2d pos, df::world_data * worldData) { @@ -1988,7 +2088,7 @@ static void AddRegionTiles(RegionTile * out, df::coord2d pos, df::world_data * w pos.x = worldData->world_width - 1; if (pos.y >= worldData->world_height) pos.y = worldData->world_height - 1; - AddRegionTiles(out, &worldData->region_map[pos.x][pos.y], worldData); + SetRegionTile(out, &worldData->region_map[pos.x][pos.y]); } static df::coord2d ShiftCoords(df::coord2d source, int direction) @@ -2235,7 +2335,7 @@ static command_result GetRegionMapsNew(color_ostream &stream, const EmptyMessage df::world_region_details * region = data->region_details[i]; if (!region) continue; - WorldMap * regionMap = out->add_world_maps(); + RegionMap * regionMap = out->add_region_maps(); CopyLocalMap(data, region, regionMap); } return CR_OK; From 71e4f4ec626a83f75a269edc7a70f892996121ae Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 28 Jul 2016 11:17:55 -0400 Subject: [PATCH 055/413] Fix pointer-size-related compile errors in dev plugins --- plugins/devel/eventExample.cpp | 12 ++++++------ plugins/devel/memview.cpp | 4 ++-- plugins/devel/rprobe.cpp | 2 +- plugins/devel/vectors.cpp | 28 ++++++++++++++-------------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/plugins/devel/eventExample.cpp b/plugins/devel/eventExample.cpp index 35c5253b4..d64969c91 100644 --- a/plugins/devel/eventExample.cpp +++ b/plugins/devel/eventExample.cpp @@ -128,26 +128,26 @@ void jobCompleted(color_ostream& out, void* job) { } void timePassed(color_ostream& out, void* ptr) { - out.print("Time: %d\n", (int32_t)(ptr)); + out.print("Time: %d\n", (intptr_t)(ptr)); } void unitDeath(color_ostream& out, void* ptr) { - out.print("Death: %d\n", (int32_t)(ptr)); + out.print("Death: %d\n", (intptr_t)(ptr)); } void itemCreate(color_ostream& out, void* ptr) { - int32_t item_index = df::item::binsearch_index(df::global::world->items.all, (int32_t)ptr); + int32_t item_index = df::item::binsearch_index(df::global::world->items.all, (intptr_t)ptr); if ( item_index == -1 ) { out.print("%s, %d: Error.\n", __FILE__, __LINE__); } df::item* item = df::global::world->items.all[item_index]; df::item_type type = item->getType(); df::coord pos = item->pos; - out.print("Item created: %d, %s, at (%d,%d,%d)\n", (int32_t)(ptr), ENUM_KEY_STR(item_type, type).c_str(), pos.x, pos.y, pos.z); + out.print("Item created: %d, %s, at (%d,%d,%d)\n", (intptr_t)(ptr), ENUM_KEY_STR(item_type, type).c_str(), pos.x, pos.y, pos.z); } void building(color_ostream& out, void* ptr) { - out.print("Building created/destroyed: %d\n", (int32_t)ptr); + out.print("Building created/destroyed: %d\n", (intptr_t)ptr); } void construction(color_ostream& out, void* ptr) { @@ -168,7 +168,7 @@ void syndrome(color_ostream& out, void* ptr) { } void invasion(color_ostream& out, void* ptr) { - out.print("New invasion! %d\n", (int32_t)ptr); + out.print("New invasion! %d\n", (intptr_t)ptr); } void unitAttack(color_ostream& out, void* ptr) { diff --git a/plugins/devel/memview.cpp b/plugins/devel/memview.cpp index 07158babc..f33ff110f 100644 --- a/plugins/devel/memview.cpp +++ b/plugins/devel/memview.cpp @@ -51,7 +51,7 @@ size_t convert(const std::string& p,bool ishex=false) conv>>ret; return ret; } -bool isAddr(uint32_t *trg,vector & ranges) +bool isAddr(uintptr_t *trg,vector & ranges) { if(trg[0]%4==0) for(size_t i=0;i & parameters) int c = sizeof(*rd) / sizeof(int32_t); for (int j = 0; j < c; j++) { if (j % 8 == 0) - out << endl << setfill('0') << setw(8) << hex << (int)(rd+j) << ": "; + out << endl << setfill('0') << setw(8) << hex << (intptr_t)(rd+j) << ": "; out << " " << setfill('0') << setw(8) << hex << p[j]; } out << setfill(' ') << setw(0) << dec << endl; diff --git a/plugins/devel/vectors.cpp b/plugins/devel/vectors.cpp index c7e81dfe7..52c74e83b 100644 --- a/plugins/devel/vectors.cpp +++ b/plugins/devel/vectors.cpp @@ -50,7 +50,7 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) return CR_OK; } -static bool hexOrDec(string &str, uint32_t &value) +static bool hexOrDec(string &str, uintptr_t &value) { if (str.find("0x") == 0 && sscanf(str.c_str(), "%x", &value) == 1) return true; @@ -69,7 +69,7 @@ static bool mightBeVec(vector &ranges, // Vector length might not be a multiple of 4 if, for example, // it's a vector of uint8_t or uint16_t. However, the actual memory // allocated to the vector should be 4 byte aligned. - if (((int)vec->start % 4 != 0) || ((int)vec->alloc_end % 4 != 0)) + if (((intptr_t)vec->start % 4 != 0) || ((intptr_t)vec->alloc_end % 4 != 0)) return false; for (size_t i = 0; i < ranges.size(); i++) @@ -130,7 +130,7 @@ static void vectorsUsage(color_ostream &con) static void printVec(color_ostream &con, const char* msg, t_vecTriplet *vec, uint32_t start, uint32_t pos, std::vector &ranges) { - uint32_t length = (int)vec->end - (int)vec->start; + uint32_t length = (intptr_t)vec->end - (intptr_t)vec->start; uint32_t offset = pos - start; con.print("%8s offset %06p, addr %010p, start %010p, length %u", @@ -158,7 +158,7 @@ command_result df_vectors (color_ostream &con, vector & parameters) return CR_FAILURE; } - uint32_t start = 0, bytes = 0; + uintptr_t start = 0, bytes = 0; if (!hexOrDec(parameters[0], start)) { @@ -172,7 +172,7 @@ command_result df_vectors (color_ostream &con, vector & parameters) return CR_FAILURE; } - uint32_t end = start + bytes; + uintptr_t end = start + bytes; // 4 byte alignment. while (start % 4 != 0) @@ -200,10 +200,10 @@ command_result df_vectors (color_ostream &con, vector & parameters) { con.print("Scanning %u bytes would read past end of memory " "range.\n", bytes); - uint32_t diff = end - (int)range.end; + size_t diff = end - (intptr_t)range.end; con.print("Cutting bytes down by %u.\n", diff); - end = (uint32_t) range.end; + end = (uintptr_t) range.end; } startInRange = true; break; @@ -215,11 +215,11 @@ command_result df_vectors (color_ostream &con, vector & parameters) return CR_FAILURE; } - uint32_t pos = start; + uintptr_t pos = start; - const uint32_t ptr_size = sizeof(void*); + const size_t ptr_size = sizeof(void*); - for (uint32_t pos = start; pos < end; pos += ptr_size) + for (uintptr_t pos = start; pos < end; pos += ptr_size) { // Is it an embeded vector? if (pos <= ( end - sizeof(t_vecTriplet) )) @@ -238,7 +238,7 @@ command_result df_vectors (color_ostream &con, vector & parameters) // Is it a vector pointer? if (pos <= (end - ptr_size)) { - uint32_t ptr = * ( (uint32_t*) pos); + uintptr_t ptr = * ( (uintptr_t*) pos); if (inAnyRange(ranges, (void *) ptr)) { @@ -275,7 +275,7 @@ command_result df_clearvec (color_ostream &con, vector & parameters) return CR_FAILURE; } - uint32_t start = 0, bytes = 0; + uintptr_t start = 0, bytes = 0; if (!hexOrDec(parameters[0], start)) { @@ -301,7 +301,7 @@ command_result df_clearvec (color_ostream &con, vector & parameters) for (size_t i = 0; i < parameters.size(); i++) { std::string addr_str = parameters[i]; - uint32_t addr; + uintptr_t addr; if (!hexOrDec(addr_str, addr)) { con << "'" << addr_str << "' not a number." << std::endl; @@ -329,7 +329,7 @@ command_result df_clearvec (color_ostream &con, vector & parameters) else { // Is it a pointer to a vector? - addr = * ( (uint32_t*) addr); + addr = * ( (uintptr_t*) addr); vec = (t_vecTriplet*) addr; if (inAnyRange(ranges, (void *) addr) && mightBeVec(ranges, vec)) From eeb7f0548332c339b3ad8aec6381e23cbed841d5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 28 Jul 2016 11:37:24 -0400 Subject: [PATCH 056/413] vectors: Fix pointer parsing and display --- plugins/devel/vectors.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/devel/vectors.cpp b/plugins/devel/vectors.cpp index 52c74e83b..717f4bdae 100644 --- a/plugins/devel/vectors.cpp +++ b/plugins/devel/vectors.cpp @@ -52,9 +52,11 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) static bool hexOrDec(string &str, uintptr_t &value) { - if (str.find("0x") == 0 && sscanf(str.c_str(), "%x", &value) == 1) + std::stringstream ss; + ss << str; + if (str.find("0x") == 0 && (ss >> std::hex >> value)) return true; - else if (sscanf(str.c_str(), "%u", &value) == 1) + else if (ss >> std::dec >> value) return true; return false; @@ -128,10 +130,10 @@ static void vectorsUsage(color_ostream &con) } static void printVec(color_ostream &con, const char* msg, t_vecTriplet *vec, - uint32_t start, uint32_t pos, std::vector &ranges) + uintptr_t start, uintptr_t pos, std::vector &ranges) { - uint32_t length = (intptr_t)vec->end - (intptr_t)vec->start; - uint32_t offset = pos - start; + uintptr_t length = (intptr_t)vec->end - (intptr_t)vec->start; + uintptr_t offset = pos - start; con.print("%8s offset %06p, addr %010p, start %010p, length %u", msg, offset, pos, vec->start, length); From afde73a6739da0172925ba590232edee29b890ed Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 28 Jul 2016 11:40:02 -0400 Subject: [PATCH 057/413] memview: Fix pointer size on x64 --- plugins/devel/memview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/devel/memview.cpp b/plugins/devel/memview.cpp index f33ff110f..53ee86755 100644 --- a/plugins/devel/memview.cpp +++ b/plugins/devel/memview.cpp @@ -70,7 +70,7 @@ void outputHex(uint8_t *buf,uint8_t *lbuf,size_t len,size_t start,color_ostream con.print("0x%08X ",i+start); for(size_t j=0;(j Date: Thu, 28 Jul 2016 16:36:02 -0400 Subject: [PATCH 058/413] Fix support for integer fields in Lua 5.3 --- library/DataStaticsFields.cpp | 38 +++++++++------- library/LuaTypes.cpp | 17 ++++++- library/include/DataIdentity.h | 83 +++++++++++++++++++++++++--------- library/include/LuaTools.h | 6 +++ 4 files changed, 103 insertions(+), 41 deletions(-) diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index 9115784d7..71221effe 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -17,28 +17,30 @@ #pragma GCC diagnostic ignored "-Winvalid-offsetof" namespace df { -#define NUMBER_IDENTITY_TRAITS(type) \ - number_identity identity_traits::identity(#type); +#define NUMBER_IDENTITY_TRAITS(category, type) \ + category##_identity identity_traits::identity(#type); +#define INTEGER_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(integer, type) +#define FLOAT_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(float, type) #ifndef STATIC_FIELDS_GROUP - NUMBER_IDENTITY_TRAITS(char); - NUMBER_IDENTITY_TRAITS(int8_t); - NUMBER_IDENTITY_TRAITS(uint8_t); - NUMBER_IDENTITY_TRAITS(int16_t); - NUMBER_IDENTITY_TRAITS(uint16_t); - NUMBER_IDENTITY_TRAITS(int32_t); - NUMBER_IDENTITY_TRAITS(uint32_t); - NUMBER_IDENTITY_TRAITS(int64_t); - NUMBER_IDENTITY_TRAITS(uint64_t); + INTEGER_IDENTITY_TRAITS(char); + INTEGER_IDENTITY_TRAITS(int8_t); + INTEGER_IDENTITY_TRAITS(uint8_t); + INTEGER_IDENTITY_TRAITS(int16_t); + INTEGER_IDENTITY_TRAITS(uint16_t); + INTEGER_IDENTITY_TRAITS(int32_t); + INTEGER_IDENTITY_TRAITS(uint32_t); + INTEGER_IDENTITY_TRAITS(int64_t); + INTEGER_IDENTITY_TRAITS(uint64_t); #ifdef _WIN32 - NUMBER_IDENTITY_TRAITS(long); - NUMBER_IDENTITY_TRAITS(unsigned long); + INTEGER_IDENTITY_TRAITS(long); + INTEGER_IDENTITY_TRAITS(unsigned long); #else - NUMBER_IDENTITY_TRAITS(intptr_t); - NUMBER_IDENTITY_TRAITS(uintptr_t); + INTEGER_IDENTITY_TRAITS(intptr_t); + INTEGER_IDENTITY_TRAITS(uintptr_t); #endif - NUMBER_IDENTITY_TRAITS(float); - NUMBER_IDENTITY_TRAITS(double); + FLOAT_IDENTITY_TRAITS(float); + FLOAT_IDENTITY_TRAITS(double); bool_identity identity_traits::identity; stl_string_identity identity_traits::identity; @@ -60,6 +62,8 @@ namespace df { buffer_container_identity buffer_container_identity::base_instance; #endif #undef NUMBER_IDENTITY_TRAITS +#undef INTEGER_IDENTITY_TRAITS +#undef FLOAT_IDENTITY_TRAITS } #define TID(type) (&identity_traits< type >::identity) diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index e8d07dc2f..71fca0b6b 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -115,12 +115,25 @@ void enum_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int va base_type->lua_write(state, fname_idx, ptr, val_index); } -void df::number_identity_base::lua_read(lua_State *state, int fname_idx, void *ptr) +void df::integer_identity_base::lua_read(lua_State *state, int fname_idx, void *ptr) +{ + lua_pushinteger(state, read(ptr)); +} + +void df::integer_identity_base::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) +{ + if (!lua_isinteger(state, val_index)) + field_error(state, fname_idx, "integer expected", "write"); + + write(ptr, lua_tointeger(state, val_index)); +} + +void df::float_identity_base::lua_read(lua_State *state, int fname_idx, void *ptr) { lua_pushnumber(state, read(ptr)); } -void df::number_identity_base::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) +void df::float_identity_base::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) { if (!lua_isnumber(state, val_index)) field_error(state, fname_idx, "number expected", "write"); diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index 32bbf0d5d..a04311ac4 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -196,6 +196,29 @@ namespace df std::string getFullName() { return name; } + virtual void lua_read(lua_State *state, int fname_idx, void *ptr) = 0; + virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) = 0; + + }; + + class DFHACK_EXPORT integer_identity_base : public number_identity_base { + public: + integer_identity_base(size_t size, const char *name) + : number_identity_base(size, name) {} + + virtual void lua_read(lua_State *state, int fname_idx, void *ptr); + virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); + + protected: + virtual int64_t read(void *ptr) = 0; + virtual void write(void *ptr, int64_t val) = 0; + }; + + class DFHACK_EXPORT float_identity_base : public number_identity_base { + public: + float_identity_base(size_t size, const char *name) + : number_identity_base(size, name) {} + virtual void lua_read(lua_State *state, int fname_idx, void *ptr); virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); @@ -205,9 +228,20 @@ namespace df }; template - class number_identity : public number_identity_base { + class integer_identity : public integer_identity_base { + public: + integer_identity(const char *name) : integer_identity_base(sizeof(T), name) {} + + protected: + virtual int64_t read(void *ptr) { return int64_t(*(T*)ptr); } + virtual void write(void *ptr, int64_t val) { *(T*)ptr = T(val); } + }; + + template + class float_identity : public float_identity_base { public: - number_identity(const char *name) : number_identity_base(sizeof(T), name) {} + float_identity(const char *name) : float_identity_base(sizeof(T), name) {} + protected: virtual double read(void *ptr) { return double(*(T*)ptr); } virtual void write(void *ptr, double val) { *(T*)ptr = T(val); } @@ -472,30 +506,33 @@ namespace df }; #endif -#define NUMBER_IDENTITY_TRAITS(type) \ +#define NUMBER_IDENTITY_TRAITS(category, type) \ template<> struct DFHACK_EXPORT identity_traits { \ - static number_identity identity; \ - static number_identity_base *get() { return &identity; } \ - }; - - NUMBER_IDENTITY_TRAITS(char); - NUMBER_IDENTITY_TRAITS(int8_t); - NUMBER_IDENTITY_TRAITS(uint8_t); - NUMBER_IDENTITY_TRAITS(int16_t); - NUMBER_IDENTITY_TRAITS(uint16_t); - NUMBER_IDENTITY_TRAITS(int32_t); - NUMBER_IDENTITY_TRAITS(uint32_t); - NUMBER_IDENTITY_TRAITS(int64_t); - NUMBER_IDENTITY_TRAITS(uint64_t); + static category##_identity identity; \ + static category##_identity_base *get() { return &identity; } \ + }; + +#define INTEGER_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(integer, type) +#define FLOAT_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(float, type) + + INTEGER_IDENTITY_TRAITS(char); + INTEGER_IDENTITY_TRAITS(int8_t); + INTEGER_IDENTITY_TRAITS(uint8_t); + INTEGER_IDENTITY_TRAITS(int16_t); + INTEGER_IDENTITY_TRAITS(uint16_t); + INTEGER_IDENTITY_TRAITS(int32_t); + INTEGER_IDENTITY_TRAITS(uint32_t); + INTEGER_IDENTITY_TRAITS(int64_t); + INTEGER_IDENTITY_TRAITS(uint64_t); #ifdef _WIN32 - NUMBER_IDENTITY_TRAITS(long); - NUMBER_IDENTITY_TRAITS(unsigned long); + INTEGER_IDENTITY_TRAITS(long); + INTEGER_IDENTITY_TRAITS(unsigned long); #else - NUMBER_IDENTITY_TRAITS(intptr_t); - NUMBER_IDENTITY_TRAITS(uintptr_t); + INTEGER_IDENTITY_TRAITS(intptr_t); + INTEGER_IDENTITY_TRAITS(uintptr_t); #endif - NUMBER_IDENTITY_TRAITS(float); - NUMBER_IDENTITY_TRAITS(double); + FLOAT_IDENTITY_TRAITS(float); + FLOAT_IDENTITY_TRAITS(double); template<> struct DFHACK_EXPORT identity_traits { static bool_identity identity; @@ -538,6 +575,8 @@ namespace df }; #undef NUMBER_IDENTITY_TRAITS +#undef INTEGER_IDENTITY_TRAITS +#undef FLOAT_IDENTITY_TRAITS // Container declarations diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index ae35cb52b..3945ae524 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -286,6 +286,12 @@ namespace DFHack {namespace Lua { #undef NUMBER_PUSH #else template inline void Push(lua_State *state, T value) { + lua_pushinteger(state, lua_Number(value)); + } + inline void Push(lua_State *state, float value) { + lua_pushnumber(state, lua_Number(value)); + } + inline void Push(lua_State *state, double value) { lua_pushnumber(state, lua_Number(value)); } #endif From b7856fd9f287203598fd52d6a37a4af25c04d1bf Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 28 Jul 2016 22:04:46 -0400 Subject: [PATCH 059/413] Use enable_if for Lua::Push specializations --- library/include/LuaTools.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index 3945ae524..428cbf1f7 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -28,6 +28,7 @@ distribution. #include #include #include +#include #include "DataDefs.h" @@ -285,13 +286,14 @@ namespace DFHack {namespace Lua { NUMBER_PUSH(float) NUMBER_PUSH(double) #undef NUMBER_PUSH #else - template inline void Push(lua_State *state, T value) { - lua_pushinteger(state, lua_Number(value)); - } - inline void Push(lua_State *state, float value) { - lua_pushnumber(state, lua_Number(value)); + template + inline typename std::enable_if::value>::type + Push(lua_State *state, T value) { + lua_pushinteger(state, value); } - inline void Push(lua_State *state, double value) { + template + inline typename std::enable_if::value>::type + Push(lua_State *state, T value) { lua_pushnumber(state, lua_Number(value)); } #endif From dc79e2477b2b5b49748d76eadba3d692ba675772 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 29 Jul 2016 00:02:51 -0400 Subject: [PATCH 060/413] Expose long/[u]intptr_t to lua and fix some integer return values --- library/LuaApi.cpp | 2 +- library/LuaWrapper.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 74019c4e1..387ac4d97 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2384,7 +2384,7 @@ static int internal_getVTable(lua_State *L) const char *name = luaL_checkstring(L, 1); uintptr_t addr = (uintptr_t)Core::getInstance().vinfo->getVTable(name); if (addr) - lua_pushnumber(L, addr); + lua_pushinteger(L, addr); else lua_pushnil(L); return 1; diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 0c5848408..813dec6b7 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -451,6 +451,7 @@ static const char *const primitive_types[] = { "ptr-string", "int8_t", "uint8_t", "int16_t", "uint16_t", "int32_t", "uint32_t", "int64_t", "uint64_t", + "intptr_t", "uintptr_t", "long", "bool", "float", "double", "pointer", "ptr-vector", @@ -465,6 +466,8 @@ static type_identity *const primitive_identities[] = { df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), @@ -572,7 +575,7 @@ static int meta_sizeof(lua_State *state) if (lua_isnil(state, 1) || lua_islightuserdata(state, 1)) { lua_pushnil(state); - lua_pushnumber(state, (size_t)lua_touserdata(state, 1)); + lua_pushinteger(state, (size_t)lua_touserdata(state, 1)); return 2; } @@ -595,7 +598,7 @@ static int meta_sizeof(lua_State *state) // Add the address if (lua_isuserdata(state, 1)) { - lua_pushnumber(state, (size_t)get_object_ref(state, 1)); + lua_pushinteger(state, (size_t)get_object_ref(state, 1)); return 2; } else From e8fe72826f4bda2e54940960787958d6b0a965a2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 29 Jul 2016 00:05:12 -0400 Subject: [PATCH 061/413] Add new integer types to memscan and update find-offsets --- library/lua/memscan.lua | 11 ++++++++++- scripts | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua index 87e2ad58c..47a860f83 100644 --- a/library/lua/memscan.lua +++ b/library/lua/memscan.lua @@ -157,8 +157,17 @@ function MemoryArea.new(astart, aend) uint32_t = CheckedArray.new('uint32_t',astart,aend), int64_t = CheckedArray.new('int64_t',astart,aend), uint64_t = CheckedArray.new('uint64_t',astart,aend), - float = CheckedArray.new('float',astart,aend) + float = CheckedArray.new('float',astart,aend), + intptr_t = CheckedArray.new('intptr_t',astart,aend), + uintptr_t = CheckedArray.new('uintptr_t',astart,aend), } + if dfhack.getOSType() == 'windows' then + -- always 32 bits on Windows + obj.long = obj.int32_t + else + -- size of pointer on Linux/OS X + obj.long = obj.intptr_t + end setmetatable(obj, MemoryArea) return obj end diff --git a/scripts b/scripts index b9f223612..43bf43767 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit b9f223612bbcebfa8aa3de368fd5deadc1d4589d +Subproject commit 43bf437671380c78d4e0a6c55c6b94316dce930c From 55970a71ab7696493b4c3ab2956c3c6539fdf9f1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 29 Jul 2016 11:06:16 -0400 Subject: [PATCH 062/413] Fix Lua::Push for enums --- library/include/LuaTools.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index 428cbf1f7..c8237eb56 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -287,7 +287,7 @@ namespace DFHack {namespace Lua { #undef NUMBER_PUSH #else template - inline typename std::enable_if::value>::type + inline typename std::enable_if::value || std::is_enum::value>::type Push(lua_State *state, T value) { lua_pushinteger(state, value); } From 497503b7074c203135dbeeedff4891e4354ba865 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 29 Jul 2016 19:12:14 -0400 Subject: [PATCH 063/413] Update scripts (find-offsets) --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 43bf43767..b1e7544d8 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 43bf437671380c78d4e0a6c55c6b94316dce930c +Subproject commit b1e7544d87a59e86ae74a2468b18c0b319526932 From 6e1777e1e37a1f3df71f4a22e006ce19c74f3aae Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 29 Jul 2016 19:13:19 -0400 Subject: [PATCH 064/413] Remove _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS Fixed by #959 --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a854a74aa..64883688e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,7 +177,6 @@ ELSEIF(MSVC) # for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /vmm /MP") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od") - ADD_DEFINITIONS(-D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS) ENDIF() # use shared libraries for protobuf From 625fbbec1d7261bfc76ba9b299f84414b8ffca01 Mon Sep 17 00:00:00 2001 From: Carter Bray Date: Sun, 31 Jul 2016 17:01:47 -0700 Subject: [PATCH 065/413] Automatically detect architecture based on Visual Studio generator DFHACK_BUILD_ARCH is no longer cached on Windows since it is not possible to build Win32 targets with the Win64 generator or vice versa. No change for GCC builds. --- CMakeLists.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c2db0902..fbafbf659 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,7 +67,17 @@ add_definitions ( "/D_CRT_NONSTDC_NO_WARNINGS") add_definitions( "/wd4503") endif() -SET(DFHACK_BUILD_ARCH "32" CACHE STRING "Architecture to build ('32' or '64')") +# Automatically detect architecture based on Visual Studio generator +IF(MSVC AND NOT DEFINED DFHACK_BUILD_ARCH) + IF(${CMAKE_GENERATOR} MATCHES "Win64") + SET(DFHACK_BUILD_ARCH "64") + ELSE() + SET(DFHACK_BUILD_ARCH "32") + ENDIF() +ELSE() + SET(DFHACK_BUILD_ARCH "32" CACHE STRING "Architecture to build ('32' or '64')") +ENDIF() + IF("${DFHACK_BUILD_ARCH}" STREQUAL "32") SET(DFHACK_BUILD_32 1) SET(DFHACK_BUILD_64 0) From 3b9d37abe5765934def3ba1726b35dde1d5e0aed Mon Sep 17 00:00:00 2001 From: Carter Bray Date: Sun, 31 Jul 2016 17:01:52 -0700 Subject: [PATCH 066/413] Suppress integer conversion warnings inside protobuf source --- depends/protobuf/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index 085af746f..5b54c8335 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -202,6 +202,9 @@ LIST(APPEND LIBPROTOBUF_FULL_SRCS ${LIBPROTOBUF_LITE_SRCS}) IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -Wno-sign-compare") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-result") +ELSEIF(MSVC) + # Disable warnings for integer conversion to smaller type + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") ENDIF() INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) From 9da2dcb8a26f7d953ea73a0c0e85ed370f900c8e Mon Sep 17 00:00:00 2001 From: Carter Bray Date: Sun, 31 Jul 2016 17:01:57 -0700 Subject: [PATCH 067/413] Fix raw_vcall on Win64 builds MSVC's call conventions on x64 are the same for normal function calls and member function calls (with the addition of the implicit 'this' parameter). --- plugins/ruby/ruby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index adc451a19..127a49b69 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -1023,7 +1023,7 @@ static VALUE rb_dfmemory_set_clear(VALUE self, VALUE set) /* call an arbitrary object virtual method */ -#ifdef WIN32 +#if defined(_WIN32) && !defined(_WIN64) __declspec(naked) static int raw_vcall(void *that, void *fptr, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5) { From 44913609c8caad7aa8e8240b75273f7e8dc148de Mon Sep 17 00:00:00 2001 From: Carter Bray Date: Sun, 31 Jul 2016 17:02:02 -0700 Subject: [PATCH 068/413] Fix format string warnings --- library/LuaApi.cpp | 2 +- library/VTableInterpose.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 387ac4d97..df077ccc1 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2373,7 +2373,7 @@ static int internal_setAddress(lua_State *L) // Print via printerr, so that it is definitely logged to stderr.log. uintptr_t iaddr = addr - Core::getInstance().vinfo->getRebaseDelta(); - fprintf(stderr, "Setting global '%s' to %x (%x)\n", name.c_str(), addr, iaddr); + fprintf(stderr, "Setting global '%s' to %p (%p)\n", name.c_str(), (void*)addr, (void*)iaddr); fflush(stderr); return 1; diff --git a/library/VTableInterpose.cpp b/library/VTableInterpose.cpp index 96cbfff9c..c547800c2 100644 --- a/library/VTableInterpose.cpp +++ b/library/VTableInterpose.cpp @@ -309,7 +309,7 @@ VMethodInterposeLinkBase::VMethodInterposeLinkBase(virtual_identity *host, int v */ fprintf(stderr, "Bad VMethodInterposeLinkBase arguments: %d %p (%s)\n", - vmethod_idx, uintptr_t(interpose_method), name_str); + vmethod_idx, interpose_method, name_str); fflush(stderr); abort(); } From 9189e3dc7e765fad822708c8869163cc1b4af4b7 Mon Sep 17 00:00:00 2001 From: Japa Date: Tue, 2 Aug 2016 10:30:17 +0530 Subject: [PATCH 069/413] Send world buildings through remotefortressreader.cpp --- library/xml | 2 +- plugins/proto/RemoteFortressReader.proto | 39 +++++++++++++++++++ plugins/remotefortressreader.cpp | 48 ++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 7d312334c..84f5de34c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 7d312334c320022cd6275cddcdb8a64d4ed8d722 +Subproject commit 84f5de34c1a269420204c81f3244a70843bb9c5c diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 889159682..7422d4962 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -411,6 +411,44 @@ message WorldMap repeated RegionTile region_tiles = 25; } +enum SiteRealizationBuildingType +{ + cottage_plot = 0; + castle_wall = 1; + castle_tower = 2; + castle_courtyard = 3; + house = 4; + temple = 5; + tomb = 6; + shop_house = 7; + warehouse = 8; + market_square = 9; + pasture = 10; + waste = 11; + courtyard = 12; + well = 13; + vault = 14; + great_tower = 15; + trenches = 16; + tree_house = 17; + hillock_house = 18; + mead_hall = 19; + fortress_entrance = 20; + library = 21; + tavern = 22; +} + +message SiteRealizationBuilding +{ + optional int32 id = 1; + optional SiteRealizationBuildingType type = 2; + optional int32 min_x = 3; + optional int32 min_y = 4; + optional int32 max_x = 5; + optional int32 max_y = 6; + optional MatPair material = 7; +} + message RegionTile { optional int32 elevation = 1; @@ -426,6 +464,7 @@ message RegionTile optional int32 water_elevation = 11; optional MatPair surface_material = 12; repeated MatPair plant_materials = 13; + repeated SiteRealizationBuilding buildings = 14; } message RegionMap diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 3e372547d..9ab407e7d 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -61,6 +61,9 @@ #include "df/world_geo_biome.h" #include "df/world_geo_layer.h" #include "df/world_population.h" +#include "df/world_site.h" +#include "df/world_site_realization.h" +#include "df/site_realization_building.h" #include "df/unit.h" #include "df/creature_raw.h" @@ -2251,10 +2254,13 @@ static void CopyLocalMap(df::world_data * worldData, df::world_region_details* w south = region; } + RegionTile* outputTiles[17][17]; + for (int yy = 0; yy < 17; yy++) for (int xx = 0; xx < 17; xx++) { auto tile = out->add_tiles(); + outputTiles[xx][yy] = tile; //This is because the bottom row doesn't line up. if (xx == 16 && yy == 16 && southEast != NULL) { @@ -2303,6 +2309,48 @@ static void CopyLocalMap(df::world_data * worldData, df::world_region_details* w east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); } + + auto regionMap = worldData->region_map[pos_x][pos_y]; + + for (int i = 0; i < regionMap.sites.size(); i++) + { + df::world_site* site = regionMap.sites[i]; + + if (site->realization == NULL) + continue; + + int region_min_x = pos_x * 16; + int region_min_y = pos_y * 16; + + auto realization = site->realization; + for (int site_x = 0; site_x < 17; site_x++) + for (int site_y = 0; site_y < 17; site_y++) + { + int region_x = site->global_min_x - region_min_x + site_x; + int region_y = site->global_min_y - region_min_y + site_y; + + if (region_x < 0 || region_y < 0 || region_x >= 16 || region_y >= 16) + continue; + + for (int j = 0; j < realization->building_map[site_x][site_y].buildings.size(); j++) + { + auto in_building = realization->building_map[site_x][site_y].buildings[j]; + auto out_building = outputTiles[region_x][region_y]->add_buildings(); + + out_building->set_id(in_building->id); + out_building->set_type((SiteRealizationBuildingType)in_building->type); + out_building->set_min_x(in_building->min_x - (site_x * 48)); + out_building->set_min_y(in_building->min_y - (site_y * 48)); + out_building->set_max_x(in_building->max_x - (site_x * 48)); + out_building->set_max_y(in_building->max_y - (site_y * 48)); + + auto mat = out_building->mutable_material(); + mat->set_mat_type(in_building->item.mat_type); + mat->set_mat_index(in_building->item.mat_index); + } + + } + } } static command_result GetRegionMaps(color_ostream &stream, const EmptyMessage *in, RegionMaps *out) From 2fda01d90befa6e3e76ae1b92c208c977c860398 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 3 Aug 2016 10:22:30 +0530 Subject: [PATCH 070/413] Add support for site towers. --- library/xml | 2 +- plugins/proto/RemoteFortressReader.proto | 33 ++++++++++++++++++++++++ plugins/remotefortressreader.cpp | 16 ++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 84f5de34c..650adfc5a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 84f5de34c1a269420204c81f3244a70843bb9c5c +Subproject commit 650adfc5a91fc3088568b297e170126942cf73db diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 7422d4962..1d0b5da90 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -438,6 +438,36 @@ enum SiteRealizationBuildingType tavern = 22; } +message SiteRealizationBuildingWall +{ + optional int32 start_x = 1; + optional int32 start_y = 2; + optional int32 start_z = 3; + optional int32 end_x = 4; + optional int32 end_y = 5; + optional int32 end_z = 6; +} + +message SiteRealizationBuildingTower +{ + optional int32 roof_z = 1; + optional bool round = 2; + optional bool goblin = 3; +} + +message TrenchSpoke +{ + optional int32 mound_start = 1; + optional int32 trench_start = 2; + optional int32 trench_end = 3; + optional int32 mound_end = 4; +} + +message SiteRealizationBuildingTrenches +{ + repeated TrenchSpoke spokes = 1; +} + message SiteRealizationBuilding { optional int32 id = 1; @@ -447,6 +477,9 @@ message SiteRealizationBuilding optional int32 max_x = 5; optional int32 max_y = 6; optional MatPair material = 7; + optional SiteRealizationBuildingWall wall_info = 8; + optional SiteRealizationBuildingTower tower_info = 9; + optional SiteRealizationBuildingTrenches trench_info = 10; } message RegionTile diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 9ab407e7d..2af3d6105 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -64,6 +64,9 @@ #include "df/world_site.h" #include "df/world_site_realization.h" #include "df/site_realization_building.h" +#include "df/site_realization_building_info_castle_towerst.h" +#include "df/site_realization_building_info_castle_wallst.h" +#include "df/site_realization_building_info_trenchesst.h" #include "df/unit.h" #include "df/creature_raw.h" @@ -2347,6 +2350,19 @@ static void CopyLocalMap(df::world_data * worldData, df::world_region_details* w auto mat = out_building->mutable_material(); mat->set_mat_type(in_building->item.mat_type); mat->set_mat_index(in_building->item.mat_index); + + STRICT_VIRTUAL_CAST_VAR(tower_info, df::site_realization_building_info_castle_towerst, in_building->building_info); + if (tower_info) + { + mat->set_mat_index(tower_info->wall_item.mat_index); + mat->set_mat_type(tower_info->wall_item.mat_type); + + auto out_tower = out_building->mutable_tower_info(); + out_tower->set_roof_z(tower_info->roof_z); + out_tower->set_round(tower_info->shape.bits.round); + out_tower->set_goblin(tower_info->shape.bits.goblin); + } + } } From 8a97b54bcdb248e2d9b35765cfb0fb34e8371f20 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 3 Aug 2016 16:32:51 +0530 Subject: [PATCH 071/413] Send wall info --- plugins/proto/RemoteFortressReader.proto | 2 ++ plugins/remotefortressreader.cpp | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 1d0b5da90..996e01a30 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -498,6 +498,8 @@ message RegionTile optional MatPair surface_material = 12; repeated MatPair plant_materials = 13; repeated SiteRealizationBuilding buildings = 14; + repeated MatPair stone_materials = 15; + repeated MatPair tree_materials = 16; } message RegionMap diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 2af3d6105..0b3d0fb12 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -148,7 +148,6 @@ static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEve void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos); -void FindChangedBlocks(); const char* growth_locations[] = { "TWIGS", @@ -2362,7 +2361,21 @@ static void CopyLocalMap(df::world_data * worldData, df::world_region_details* w out_tower->set_round(tower_info->shape.bits.round); out_tower->set_goblin(tower_info->shape.bits.goblin); } + STRICT_VIRTUAL_CAST_VAR(wall_info, df::site_realization_building_info_castle_wallst, in_building->building_info); + if (wall_info) + { + mat->set_mat_index(wall_info->wall_item.mat_index); + mat->set_mat_type(wall_info->wall_item.mat_type); + + auto out_wall = out_building->mutable_wall_info(); + out_wall->set_start_x(wall_info->start_x - (site_x * 48)); + out_wall->set_start_y(wall_info->start_y - (site_y * 48)); + out_wall->set_start_z(wall_info->start_z); + out_wall->set_end_x(wall_info->end_x - (site_x * 48)); + out_wall->set_end_y(wall_info->end_y - (site_y * 48)); + out_wall->set_end_z(wall_info->end_z); + } } } From 697aa54fa672fe343c305280efcde3ef5225389d Mon Sep 17 00:00:00 2001 From: Japa Date: Fri, 5 Aug 2016 00:40:10 +0530 Subject: [PATCH 072/413] Sent tree and stone layers through remotefortressreader.cpp, and correct town placement. --- plugins/remotefortressreader.cpp | 42 ++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 0b3d0fb12..6933826c7 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1966,7 +1966,14 @@ static void SetRegionTile(RegionTile * out, df::region_map_entry * e1) if (layer->top_height == 0) { topLayer = layer->mat_index; - break; + } + if (layer->type != geo_layer_type::SOIL + && layer->type != geo_layer_type::SOIL_OCEAN + && layer->type != geo_layer_type::SOIL_SAND) + { + auto mat = out->add_stone_materials(); + mat->set_mat_index(layer->mat_index); + mat->set_mat_type(0); } } auto surfaceMat = out->mutable_surface_material(); @@ -1976,13 +1983,20 @@ static void SetRegionTile(RegionTile * out, df::region_map_entry * e1) for (int i = 0; i < region->population.size(); i++) { auto pop = region->population[i]; - if (pop->type != world_population_type::Grass) - continue; + if (pop->type == world_population_type::Grass) + { + auto plantMat = out->add_plant_materials(); - auto plantMat = out->add_plant_materials(); + plantMat->set_mat_index(pop->plant); + plantMat->set_mat_type(419); + } + else if (pop->type == world_population_type::Tree) + { + auto plantMat = out->add_tree_materials(); - plantMat->set_mat_index(pop->plant); - plantMat->set_mat_type(419); + plantMat->set_mat_index(pop->plant); + plantMat->set_mat_type(419); + } } } @@ -2314,16 +2328,24 @@ static void CopyLocalMap(df::world_data * worldData, df::world_region_details* w auto regionMap = worldData->region_map[pos_x][pos_y]; - for (int i = 0; i < regionMap.sites.size(); i++) + for (int i = 0; i < worldData->sites.size(); i++) { - df::world_site* site = regionMap.sites[i]; - - if (site->realization == NULL) + df::world_site* site = worldData->sites[i]; + if (!site) continue; int region_min_x = pos_x * 16; int region_min_y = pos_y * 16; + if ((site->global_min_x > (region_min_x + 16)) || + (site->global_min_y > (region_min_y + 16)) || + (site->global_max_x < (region_min_x)) || + (site->global_max_y < (region_min_y))) + continue; + + if (site->realization == NULL) + continue; + auto realization = site->realization; for (int site_x = 0; site_x < 17; site_x++) for (int site_y = 0; site_y < 17; site_y++) From ef569dc5a1521af1eba5e586d6d3e9ad0149d3b9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 Aug 2016 17:09:25 -0400 Subject: [PATCH 073/413] Pass OS and architecture to ruby codegen explicitly - Passing the architecture is needed to determine sizeof(long) - Passing the OS prevents potential issues when cross-compiling between Windows and non-Windows (although this is unlikely) --- plugins/ruby/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ruby/CMakeLists.txt b/plugins/ruby/CMakeLists.txt index 3aeac6dc5..dfb0dc3c4 100644 --- a/plugins/ruby/CMakeLists.txt +++ b/plugins/ruby/CMakeLists.txt @@ -22,7 +22,7 @@ ENDIF (APPLE OR UNIX) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RUBYAUTOGEN} - COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/codegen.pl ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml ${CMAKE_CURRENT_BINARY_DIR}/${RUBYAUTOGEN} + COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/codegen.pl ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml ${CMAKE_CURRENT_BINARY_DIR}/${RUBYAUTOGEN} ${CMAKE_SYSTEM_NAME} ${DFHACK_BUILD_ARCH} # cmake quirk: depending on codegen.out.xml or generate_headers only is not enough, needs both # test by manually patching any library/xml/moo.xml, run make ruby-autogen-rb -j2, and check build/plugins/ruby/ruby-autogen.rb for patched xml data DEPENDS generate_headers ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml ${CMAKE_CURRENT_SOURCE_DIR}/codegen.pl From dbd2e7192056cdd72a5427acc9d128af03dc6f2b Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 Aug 2016 17:12:07 -0400 Subject: [PATCH 074/413] Ruby codegen integer improvements - Add uint64_t - Add special case for long on different platforms - Require OS and architecture to be specified NOTE: integer alignment on x64 is probably still incorrect --- plugins/ruby/codegen.pl | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/plugins/ruby/codegen.pl b/plugins/ruby/codegen.pl index 8a670718e..7d0a745c0 100755 --- a/plugins/ruby/codegen.pl +++ b/plugins/ruby/codegen.pl @@ -7,13 +7,32 @@ use XML::LibXML; our @lines_rb; -my $os; -if ($^O =~ /linux/i or $^O =~ /darwin/i) { +my $os = $ARGV[2] or die('os not provided (argv[2])'); +if ($os =~ /linux/i or $os =~ /darwin/i) { $os = 'linux'; -} else { +} elsif ($os =~ /windows/i) { $os = 'windows'; +} else { + die "Unknown OS: " . $ARGV[2] . "\n"; +} + +my $arch = $ARGV[3] or die('arch not provided (argv[3])'); +if ($arch =~ /64/i) { + $arch = 64; +} elsif ($arch =~ /32/i) { + $arch = 32; +} else { + die "Unknown architecture: " . $ARGV[3] . "\n"; } -$os = $ARGV[2] if ($ARGV[2]); + +# 32 bits on Windows and 32-bit *nix, 64 bits on 64-bit *nix +my $SIZEOF_LONG; +if ($os eq 'windows' || $arch == 32) { + $SIZEOF_LONG = 4; +} else { + $SIZEOF_LONG = 8; +} + sub indent_rb(&) { my ($sub) = @_; @@ -486,7 +505,7 @@ sub render_class_vmethod_ret { { # raw method call returns an int32, mask according to actual return type my $retsubtype = $ret->getAttribute('ld:subtype'); - my $retbits = $ret->getAttribute('ld:bits'); + my $retbits = sizeof($ret) * 8; push @lines_rb, "val = $call"; if ($retsubtype eq 'bool') { @@ -582,7 +601,7 @@ sub get_field_align { my $meta = $field->getAttribute('ld:meta'); if ($meta eq 'number') { - $al = $field->getAttribute('ld:bits')/8; + $al = sizeof($field); # linux aligns int64_t to 4, windows to 8 # floats are 4 bytes so no pb $al = 4 if ($al > 4 and ($os eq 'linux' or $al != 8)); @@ -655,6 +674,10 @@ sub sizeof { my $meta = $field->getAttribute('ld:meta'); if ($meta eq 'number') { + if ($field->getAttribute('ld:subtype') eq 'long') { + return $SIZEOF_LONG; + } + return $field->getAttribute('ld:bits')/8; } elsif ($meta eq 'pointer') { @@ -859,7 +882,9 @@ sub render_item_number { $subtype ||= $g->getAttribute('base-type') if ($g); $subtype = 'int32_t' if (!$subtype); - if ($subtype eq 'int64_t') { + if ($subtype eq 'uint64_t') { + push @lines_rb, 'number 64, false'; + } elsif ($subtype eq 'int64_t') { push @lines_rb, 'number 64, true'; } elsif ($subtype eq 'uint32_t') { push @lines_rb, 'number 32, false'; @@ -877,6 +902,8 @@ sub render_item_number { push @lines_rb, 'number 8, true'; $initvalue ||= 'nil'; $typename ||= 'BooleanEnum'; + } elsif ($subtype eq 'long') { + push @lines_rb, 'number ' . $SIZEOF_LONG . ', true'; } elsif ($subtype eq 's-float') { push @lines_rb, 'float'; return; From ddbb1b5bb8ba6fa9f7be339e5614a475e56d42c3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 Aug 2016 17:29:24 -0400 Subject: [PATCH 075/413] ruby: Update sizes for some types Many are still incomplete on x64, especially on Windows --- plugins/ruby/codegen.pl | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/plugins/ruby/codegen.pl b/plugins/ruby/codegen.pl index 7d0a745c0..2d3b8c420 100755 --- a/plugins/ruby/codegen.pl +++ b/plugins/ruby/codegen.pl @@ -33,6 +33,7 @@ if ($os eq 'windows' || $arch == 32) { $SIZEOF_LONG = 8; } +my $SIZEOF_PTR = ($arch == 64) ? 8 : 4; sub indent_rb(&) { my ($sub) = @_; @@ -681,7 +682,7 @@ sub sizeof { return $field->getAttribute('ld:bits')/8; } elsif ($meta eq 'pointer') { - return 4; + return $SIZEOF_PTR; } elsif ($meta eq 'static-array') { my $count = $field->getAttribute('count'); @@ -716,36 +717,36 @@ sub sizeof { if ($subtype eq 'stl-vector') { if ($os eq 'linux') { - return 12; + return ($arch == 64) ? 24 : 12; } elsif ($os eq 'windows') { - return 16; + return ($arch == 64) ? 32 : 16; # TODO: fix on x64 } else { print "sizeof stl-vector on $os\n"; } } elsif ($subtype eq 'stl-bit-vector') { if ($os eq 'linux') { - return 20; + return ($arch == 64) ? 40 : 20; } elsif ($os eq 'windows') { - return 20; + return ($arch == 64) ? 40 : 20; # TODO: fix on x64 } else { print "sizeof stl-bit-vector on $os\n"; } } elsif ($subtype eq 'stl-deque') { if ($os eq 'linux') { - return 40; + return ($arch == 64) ? 80 : 40; } elsif ($os eq 'windows') { - return 24; + return ($arch == 64) ? 48 : 24; # TODO: fix on x64 } else { print "sizeof stl-deque on $os\n"; } } elsif ($subtype eq 'df-linked-list') { - return 12; + return 3 * $SIZEOF_PTR; } elsif ($subtype eq 'df-flagarray') { - return 8; + return 4 + $SIZEOF_PTR; } elsif ($subtype eq 'df-static-flagarray') { return $field->getAttribute('count'); } elsif ($subtype eq 'df-array') { - return 8; # XXX 6 ? + return 4 + $SIZEOF_PTR; # XXX 4->2 ? } else { print "sizeof container $subtype\n"; } @@ -753,18 +754,20 @@ sub sizeof { } elsif ($meta eq 'primitive') { my $subtype = $field->getAttribute('ld:subtype'); - if ($subtype eq 'stl-string') { if ($os eq 'linux') { - return 4; + if ($subtype eq 'stl-string') { + if ($os eq 'linux') { + return ($arch == 64) ? 8 : 4; } elsif ($os eq 'windows') { - return 28; + return 28; # TODO: fix on x64 } else { print "sizeof stl-string on $os\n"; } print "sizeof stl-string\n"; - } elsif ($subtype eq 'stl-fstream') { if ($os eq 'linux') { - return 284; + } elsif ($subtype eq 'stl-fstream') { + if ($os eq 'linux') { + return 284; # TODO: fix on x64 } elsif ($os eq 'windows') { - return 184; + return 184; # TODO: fix on x64 } else { print "sizeof stl-fstream on $os\n"; } From dde6901534d95ade48b2605e6d5301ee43818a9b Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 Aug 2016 17:50:49 -0400 Subject: [PATCH 076/413] x86: fix lua address display --- library/LuaWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 813dec6b7..992ab355c 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -996,7 +996,7 @@ static int meta_ptr_tostring(lua_State *state) lua_getfield(state, UPVAL_METATABLE, "__metatable"); const char *cname = lua_tostring(state, -1); - lua_pushstring(state, stl_sprintf("<%s: 0x%llx>", cname, (uintptr_t)ptr).c_str()); + lua_pushstring(state, stl_sprintf("<%s: %p>", cname, (void*)ptr).c_str()); return 1; } From ee7357b60efb81915cbdd7de8a9335c52c03a2e0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 Aug 2016 17:51:08 -0400 Subject: [PATCH 077/413] x86: fix vector validity check --- library/lua/memscan.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua index 47a860f83..534830724 100644 --- a/library/lua/memscan.lua +++ b/library/lua/memscan.lua @@ -332,7 +332,7 @@ end -- Validation function is_valid_vector(ref,size) - local ints = df.reinterpret_cast('uint64_t', ref) + local ints = df.reinterpret_cast('uintptr_t', ref) return ints[0] <= ints[1] and ints[1] <= ints[2] and (size == nil or (ints[1] - ints[0]) % size == 0) end From aeac8b4fef595fb12fa0f9092808c0d739ab7610 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 Aug 2016 18:04:42 -0400 Subject: [PATCH 078/413] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 369dfdd86..402889961 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 369dfdd862da961c74d35174cb55fed3d96a29c0 +Subproject commit 40288996152af8460e747a7479ebc6dc0e617cd9 From 5fef2ad075aa384b1a86627d6fb1fbed4a1e6fee Mon Sep 17 00:00:00 2001 From: Carter Bray Date: Sun, 7 Aug 2016 10:11:17 -0700 Subject: [PATCH 079/413] Add windows container sizes to ruby codegen --- plugins/ruby/codegen.pl | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/plugins/ruby/codegen.pl b/plugins/ruby/codegen.pl index 2d3b8c420..3e41f93c9 100755 --- a/plugins/ruby/codegen.pl +++ b/plugins/ruby/codegen.pl @@ -716,10 +716,8 @@ sub sizeof { my $subtype = $field->getAttribute('ld:subtype'); if ($subtype eq 'stl-vector') { - if ($os eq 'linux') { + if ($os eq 'linux' or $os eq 'windows') { return ($arch == 64) ? 24 : 12; - } elsif ($os eq 'windows') { - return ($arch == 64) ? 32 : 16; # TODO: fix on x64 } else { print "sizeof stl-vector on $os\n"; } @@ -727,7 +725,7 @@ sub sizeof { if ($os eq 'linux') { return ($arch == 64) ? 40 : 20; } elsif ($os eq 'windows') { - return ($arch == 64) ? 40 : 20; # TODO: fix on x64 + return ($arch == 64) ? 32 : 16; } else { print "sizeof stl-bit-vector on $os\n"; } @@ -735,7 +733,7 @@ sub sizeof { if ($os eq 'linux') { return ($arch == 64) ? 80 : 40; } elsif ($os eq 'windows') { - return ($arch == 64) ? 48 : 24; # TODO: fix on x64 + return ($arch == 64) ? 40 : 20; } else { print "sizeof stl-deque on $os\n"; } @@ -758,7 +756,7 @@ sub sizeof { if ($os eq 'linux') { return ($arch == 64) ? 8 : 4; } elsif ($os eq 'windows') { - return 28; # TODO: fix on x64 + return ($arch == 64) ? 32 : 24; } else { print "sizeof stl-string on $os\n"; } @@ -767,7 +765,7 @@ sub sizeof { if ($os eq 'linux') { return 284; # TODO: fix on x64 } elsif ($os eq 'windows') { - return 184; # TODO: fix on x64 + return ($arch == 64) ? 280 : 192; } else { print "sizeof stl-fstream on $os\n"; } From 298d16238ebfb484a8e622ef93fb7b0754137bc1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 8 Aug 2016 11:45:00 -0400 Subject: [PATCH 080/413] Remove a few unneeded includes in DataStaticsFields.cpp --- library/DataStaticsFields.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index 71221effe..11a270251 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -1,20 +1,14 @@ -#include "Internal.h" -#include "DataDefs.h" -#include "MiscUtils.h" -#include "VersionInfo.h" +#include #ifndef STATIC_FIELDS_GROUP -#include "df/world.h" -#include "df/world_data.h" -#include "df/ui.h" +#include "DataDefs.h" #endif -#include "DataIdentity.h" #include "DataFuncs.h" -#include - +#ifdef __GNUC__ #pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif namespace df { #define NUMBER_IDENTITY_TRAITS(category, type) \ From e22b3b1de7dcdf1d1ee98a4b28eaf3a6339609ed Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 8 Aug 2016 11:46:20 -0400 Subject: [PATCH 081/413] Use non-fixed-width types in integer identity_traits definitions In some situations (e.g. 32-bit Linux), "intptr_t" is defined as "int", which is equivalent to "int32_t", leading to issues with duplicate definitions. In other situations with GCC, "intptr_t" is "long", which isn't covered by any intNN_t types. Also, definitions for "long" already had to be added on Windows, because no fixed-width types in MSVC are equivalent to "long". Switching to non-fixed-width types should hopefully cover all of these situations. If this doesn't cover any integer types that we need, it will be caught quickly, e.g. by references to integer_traits in LuaWrapper.cpp. --- library/DataStaticsFields.cpp | 21 ++++++++------------- library/include/DataIdentity.h | 21 ++++++++------------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index 11a270251..8ff0770fc 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -18,21 +18,16 @@ namespace df { #ifndef STATIC_FIELDS_GROUP INTEGER_IDENTITY_TRAITS(char); - INTEGER_IDENTITY_TRAITS(int8_t); - INTEGER_IDENTITY_TRAITS(uint8_t); - INTEGER_IDENTITY_TRAITS(int16_t); - INTEGER_IDENTITY_TRAITS(uint16_t); - INTEGER_IDENTITY_TRAITS(int32_t); - INTEGER_IDENTITY_TRAITS(uint32_t); - INTEGER_IDENTITY_TRAITS(int64_t); - INTEGER_IDENTITY_TRAITS(uint64_t); -#ifdef _WIN32 + INTEGER_IDENTITY_TRAITS(signed char); + INTEGER_IDENTITY_TRAITS(unsigned char); + INTEGER_IDENTITY_TRAITS(short); + INTEGER_IDENTITY_TRAITS(unsigned short); + INTEGER_IDENTITY_TRAITS(int); + INTEGER_IDENTITY_TRAITS(unsigned int); INTEGER_IDENTITY_TRAITS(long); INTEGER_IDENTITY_TRAITS(unsigned long); -#else - INTEGER_IDENTITY_TRAITS(intptr_t); - INTEGER_IDENTITY_TRAITS(uintptr_t); -#endif + INTEGER_IDENTITY_TRAITS(long long); + INTEGER_IDENTITY_TRAITS(unsigned long long); FLOAT_IDENTITY_TRAITS(float); FLOAT_IDENTITY_TRAITS(double); diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index a04311ac4..556731e46 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -516,21 +516,16 @@ namespace df #define FLOAT_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(float, type) INTEGER_IDENTITY_TRAITS(char); - INTEGER_IDENTITY_TRAITS(int8_t); - INTEGER_IDENTITY_TRAITS(uint8_t); - INTEGER_IDENTITY_TRAITS(int16_t); - INTEGER_IDENTITY_TRAITS(uint16_t); - INTEGER_IDENTITY_TRAITS(int32_t); - INTEGER_IDENTITY_TRAITS(uint32_t); - INTEGER_IDENTITY_TRAITS(int64_t); - INTEGER_IDENTITY_TRAITS(uint64_t); -#ifdef _WIN32 + INTEGER_IDENTITY_TRAITS(signed char); + INTEGER_IDENTITY_TRAITS(unsigned char); + INTEGER_IDENTITY_TRAITS(short); + INTEGER_IDENTITY_TRAITS(unsigned short); + INTEGER_IDENTITY_TRAITS(int); + INTEGER_IDENTITY_TRAITS(unsigned int); INTEGER_IDENTITY_TRAITS(long); INTEGER_IDENTITY_TRAITS(unsigned long); -#else - INTEGER_IDENTITY_TRAITS(intptr_t); - INTEGER_IDENTITY_TRAITS(uintptr_t); -#endif + INTEGER_IDENTITY_TRAITS(long long); + INTEGER_IDENTITY_TRAITS(unsigned long long); FLOAT_IDENTITY_TRAITS(float); FLOAT_IDENTITY_TRAITS(double); From 9c28d1a08509faa50af20bf88edecb99b711805a Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 8 Aug 2016 16:49:22 -0400 Subject: [PATCH 082/413] Improve CMake file downloads - Files are redownloaded if their expected MD5 changes in CMakeLists.txt - Refactored some --- CMake/DownloadFile.cmake | 48 +++++++++++++++++ CMakeLists.txt | 110 ++++++++++++++++++--------------------- 2 files changed, 100 insertions(+), 58 deletions(-) create mode 100644 CMake/DownloadFile.cmake diff --git a/CMake/DownloadFile.cmake b/CMake/DownloadFile.cmake new file mode 100644 index 000000000..1a8a40562 --- /dev/null +++ b/CMake/DownloadFile.cmake @@ -0,0 +1,48 @@ +# Helper to download files as needed + +function(file_md5_if_exists FILE VAR) + if(EXISTS "${FILE}") + file(MD5 "${FILE}" "${VAR}") + set(${VAR} "${${VAR}}" PARENT_SCOPE) + else() + set(${VAR} "" PARENT_SCOPE) + endif() +endfunction() + +function(download_file URL DEST EXPECTED_MD5) + get_filename_component(FILENAME "${URL}" NAME) + file_md5_if_exists("${DEST}" CUR_MD5) + + if(NOT "${EXPECTED_MD5}" STREQUAL "${CUR_MD5}") + message("* Downloading ${FILENAME}") + file(DOWNLOAD "${URL}" "${DEST}" EXPECTED_MD5 "${EXPECTED_MD5}" SHOW_PROGRESS) + endif() +endfunction() + +# Download a file and uncompress it +function(download_file_unzip URL ZIP_TYPE ZIP_DEST ZIP_MD5 UNZIP_DEST UNZIP_MD5) + get_filename_component(FILENAME "${URL}" NAME) + file_md5_if_exists("${UNZIP_DEST}" CUR_UNZIP_MD5) + + # Redownload if the MD5 of the uncompressed file doesn't match + if(NOT "${UNZIP_MD5}" STREQUAL "${CUR_UNZIP_MD5}") + download_file("${URL}" "${ZIP_DEST}" "${ZIP_MD5}") + + if(EXISTS "${ZIP_DEST}") + message("* Decompressing ${FILENAME}") + if("${ZIP_TYPE}" STREQUAL "gz") + execute_process(COMMAND gunzip --force "${ZIP_DEST}") + else() + message(SEND_ERROR "Unknown ZIP_TYPE: ${ZIP_TYPE}") + endif() + if(NOT EXISTS "${UNZIP_DEST}") + message(SEND_ERROR "File failed to unzip to ${UNZIP_DEST}") + else() + file(MD5 "${UNZIP_DEST}" CUR_UNZIP_MD5) + if(NOT "${UNZIP_MD5}" STREQUAL "${CUR_UNZIP_MD5}") + message(SEND_ERROR "MD5 mismatch: ${UNZIP_DEST}: expected ${UNZIP_MD5}, got ${CUR_UNZIP_MD5}") + endif() + endif() + endif() + endif() +endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c2db0902..c984c9e1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -203,68 +203,62 @@ endif() #### download depends #### +include(CMake/DownloadFile.cmake) + if(WIN32) - # Download zlib on Windows - set(ZLIB_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/depends/zlib/lib/win${DFHACK_BUILD_ARCH}) - if(NOT EXISTS ${ZLIB_DOWNLOAD_DIR}/zlib.lib) - if(${DFHACK_BUILD_ARCH} STREQUAL "64") - message("Downloading win64-zlib.lib") - file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win64-zlib.lib" - ${ZLIB_DOWNLOAD_DIR}/zlib.lib - EXPECTED_MD5 "a3b2fc6b68efafa89b0882e354fc8418") - else() - message("Downloading win32-zlib.lib") - file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-zlib.lib" - ${ZLIB_DOWNLOAD_DIR}/zlib.lib - EXPECTED_MD5 "f4ebaa21d9de28566e88b1edfcdff901") - endif() - endif() - # Move zlib to the build folder so possible 32 and 64-bit builds - # in the same source tree don't conflict - file(COPY ${CMAKE_SOURCE_DIR}/depends/zlib - DESTINATION ${CMAKE_BINARY_DIR}/depends/) - file(COPY ${ZLIB_DOWNLOAD_DIR}/zlib.lib - DESTINATION ${CMAKE_BINARY_DIR}/depends/zlib/lib/) - - - # Do the same for SDLreal.dll - # (DFHack doesn't require this at build time, so no need to move it to the build folder) - set(SDLREAL_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/package/windows/win${DFHACK_BUILD_ARCH}) - if(NOT EXISTS ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll) - if(${DFHACK_BUILD_ARCH} STREQUAL "64") - message("Downloading win64-SDL.dll") - file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win64-SDL.dll" - ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll - EXPECTED_MD5 "1ae242c4b94cb03756a1288122a66faf") - else() - message("Downloading win32-SDL.dll") - file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-SDL.dll" - ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll - EXPECTED_MD5 "5a09604daca6b2b5ce049d79af935d6a") - endif() - endif() + # Download zlib on Windows + set(ZLIB_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/depends/zlib/lib/win${DFHACK_BUILD_ARCH}) + if(${DFHACK_BUILD_ARCH} STREQUAL "64") + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win64-zlib.lib" + ${ZLIB_DOWNLOAD_DIR}/zlib.lib + "a3b2fc6b68efafa89b0882e354fc8418") + else() + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-zlib.lib" + ${ZLIB_DOWNLOAD_DIR}/zlib.lib + "f4ebaa21d9de28566e88b1edfcdff901") + endif() + + # Move zlib to the build folder so possible 32 and 64-bit builds + # in the same source tree don't conflict + file(COPY ${CMAKE_SOURCE_DIR}/depends/zlib + DESTINATION ${CMAKE_BINARY_DIR}/depends/) + file(COPY ${ZLIB_DOWNLOAD_DIR}/zlib.lib + DESTINATION ${CMAKE_BINARY_DIR}/depends/zlib/lib/) + + + # Do the same for SDLreal.dll + # (DFHack doesn't require this at build time, so no need to move it to the build folder) + set(SDLREAL_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/package/windows/win${DFHACK_BUILD_ARCH}) + if(${DFHACK_BUILD_ARCH} STREQUAL "64") + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win64-SDL.dll" + ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll + "1ae242c4b94cb03756a1288122a66faf") + else() + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-SDL.dll" + ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll + "5a09604daca6b2b5ce049d79af935d6a") + endif() endif() if(APPLE) - # libstdc++ (GCC 4.8.5 for OS X 10.6) - # fixes crash-on-unwind bug in DF's libstdc++ - set(LIBSTDCXX_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/package/darwin/osx${DFHACK_BUILD_ARCH}) - # check for existence of uncompressed library - if(NOT EXISTS ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib) - if(${DFHACK_BUILD_ARCH} STREQUAL "64") - message("Downloading osx64-libstdcxx.6.dylib.gz") - file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/osx64-libstdcxx.6.dylib.gz" - ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz - EXPECTED_MD5 "cf26ed588be8e83c8e3a49919793b416") - execute_process(COMMAND gunzip ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz) - else() - message("Downloading osx32-libstdcxx.6.dylib.gz") - file(DOWNLOAD "https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/osx32-libstdcxx.6.dylib.gz" - ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz - EXPECTED_MD5 "40f3d83871b114f0279240626311621b") - execute_process(COMMAND gunzip ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz) - endif() - endif() + # libstdc++ (GCC 4.8.5 for OS X 10.6) + # fixes crash-on-unwind bug in DF's libstdc++ + set(LIBSTDCXX_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/package/darwin/osx${DFHACK_BUILD_ARCH}) + if(${DFHACK_BUILD_ARCH} STREQUAL "64") + download_file_unzip("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/osx64-libstdcxx.6.dylib.gz" + "gz" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz + "cf26ed588be8e83c8e3a49919793b416" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib + "16dc6dbd4ecde7f9b95bb6dc91f07404") + else() + download_file_unzip("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/osx32-libstdcxx.6.dylib.gz" + "gz" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib.gz + "40f3d83871b114f0279240626311621b" + ${LIBSTDCXX_DOWNLOAD_DIR}/libstdc++.6.dylib + "c3f5678b8204917e03870834902c3e8b") + endif() endif() #### expose depends #### From b211177a272febd1588a9f4ffe7b2f69280e9c7d Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 Aug 2016 10:05:46 -0400 Subject: [PATCH 083/413] Fix version in docs for non-stable releases --- conf.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/conf.py b/conf.py index 10df1b551..dc033016f 100644 --- a/conf.py +++ b/conf.py @@ -19,6 +19,7 @@ import fnmatch from io import open from itertools import starmap import os +import re import shlex # pylint:disable=unused-import import sys @@ -149,13 +150,15 @@ author = 'The DFHack Team' def get_version(): """Return the DFHack version string, from CMakeLists.txt""" version = release = '' #pylint:disable=redefined-outer-name + pattern = re.compile(r'set\((df_version|dfhack_release)\s+"(.+?)"\)') try: with open('CMakeLists.txt') as f: for s in f.readlines(): - if fnmatch.fnmatch(s.upper(), 'SET(DF_VERSION "?.??.??")\n'): - version = s.upper().replace('SET(DF_VERSION "', '') - elif fnmatch.fnmatch(s.upper(), 'SET(DFHACK_RELEASE "r*")\n'): - release = s.upper().replace('SET(DFHACK_RELEASE "', '').lower() + for match in pattern.findall(s.lower()): + if match[0] == 'df_version': + version = match[1] + elif match[0] == 'dfhack_release': + release = match[1] return (version + '-' + release).replace('")\n', '') except IOError: return 'unknown' From aa47484b2abc1ac1a0e53582565152c696317d9d Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 Aug 2016 18:49:39 -0400 Subject: [PATCH 084/413] Enable bit32 library Deprecated in Lua 5.3, but still contains some useful things, like extract() Also helps maintain backward-compatibility with scripts that target older DF versions (e.g. Mifki's dfremote project) --- depends/lua/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/depends/lua/CMakeLists.txt b/depends/lua/CMakeLists.txt index bd244a126..8b9ce8e2e 100644 --- a/depends/lua/CMakeLists.txt +++ b/depends/lua/CMakeLists.txt @@ -3,6 +3,9 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLUA_USE_APICHECK") +# Make bit32 library available (for things like bit32.extract()) +ADD_DEFINITIONS(-DLUA_COMPAT_BITLIB) + IF(WIN32) ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE ) ELSE() From b9092c94f570216d2635fc550f65e6ecac3df836 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 Aug 2016 19:10:38 -0400 Subject: [PATCH 085/413] Don't search for 32-bit zlib when targeting 64-bit Linux --- CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c984c9e1f..cd3e576d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -267,9 +267,12 @@ endif() # find and make available libz if(NOT UNIX) # Windows # zlib is in here so 32-bit and 64-bit builds in the same source tree are possible - SET(ZLIB_ROOT ${CMAKE_BINARY_DIR}/depends/zlib/) + set(ZLIB_ROOT ${CMAKE_BINARY_DIR}/depends/zlib/) else() - set(ZLIB_ROOT /usr/lib/i386-linux-gnu) + if(NOT APPLE AND DFHACK_BUILD_32) + # 32-bit Linux + set(ZLIB_ROOT /usr/lib/i386-linux-gnu) + endif() endif() find_package(ZLIB REQUIRED) From 02eef951474871ca9726d5aef300a8ab298c21d3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 Aug 2016 20:00:31 -0400 Subject: [PATCH 086/413] Fix base address for Darwin x64 --- library/include/Memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/include/Memory.h b/library/include/Memory.h index 1016f2966..33d40c3cc 100644 --- a/library/include/Memory.h +++ b/library/include/Memory.h @@ -7,7 +7,7 @@ #endif #elif defined(_DARWIN) #ifdef DFHACK64 - #define DEFAULT_BASE_ADDR 0x1000 + #define DEFAULT_BASE_ADDR 0x100000000 #else #define DEFAULT_BASE_ADDR 0x1000 #endif From 53a0d73d2359b244999163afc3638e9bf649d0f8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 Aug 2016 20:09:50 -0400 Subject: [PATCH 087/413] Add new title-folder plugin --- NEWS.rst | 7 +++ docs/Plugins.rst | 6 ++ plugins/CMakeLists.txt | 1 + plugins/title-folder.cpp | 116 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 plugins/title-folder.cpp diff --git a/NEWS.rst b/NEWS.rst index 106cae801..2d3dd858a 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -30,6 +30,13 @@ Changelog .. contents:: :depth: 2 +DFHack future +============= + +New Plugins +----------- +- `title-folder`: shows DF folder name in window title bar when enabled + DFHack 0.43.03-r1 ================= diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 1a353acbd..efd5da0e6 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -601,6 +601,12 @@ resume Allows automatic resumption of suspended constructions, along with colored UI hints for construction status. +.. _title-folder: + +title-folder +============= +Displays the DF folder name in the window title bar when enabled. + .. _title-version: title-version diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index bc66bda75..f36b0fa0b 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -139,6 +139,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(stocks stocks.cpp) DFHACK_PLUGIN(strangemood strangemood.cpp) DFHACK_PLUGIN(tiletypes tiletypes.cpp Brushes.h) + DFHACK_PLUGIN(title-folder title-folder.cpp) DFHACK_PLUGIN(title-version title-version.cpp) DFHACK_PLUGIN(trackstop trackstop.cpp) # DFHACK_PLUGIN(treefarm treefarm.cpp) diff --git a/plugins/title-folder.cpp b/plugins/title-folder.cpp new file mode 100644 index 000000000..ee69ccc5a --- /dev/null +++ b/plugins/title-folder.cpp @@ -0,0 +1,116 @@ +#include "Console.h" +#include "Core.h" +#include "DataDefs.h" +#include "Export.h" +#include "MemAccess.h" +#include "PluginManager.h" + +using namespace DFHack; + +DFHACK_PLUGIN("title-folder"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +// SDL frees the old window title when changed +static std::string original_title; + +static DFLibrary *sdl_handle = NULL; +static const std::vector sdl_libs { + "SDLreal.dll", + "SDL.framework/SDL", + "libSDL-1.2.so.0" +}; + +void (*_SDL_WM_GetCaption)(const char**, const char**) = NULL; +void SDL_WM_GetCaption(const char **title, const char **icon) { + _SDL_WM_GetCaption(title, icon); +} + +void (*_SDL_WM_SetCaption)(const char*, const char*) = NULL; +void SDL_WM_SetCaption(const char *title, const char *icon) { + _SDL_WM_SetCaption(title, icon); +} + +DFhackCExport command_result plugin_enable (color_ostream &out, bool state); +DFhackCExport command_result plugin_shutdown (color_ostream &out); + +DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) +{ + for (auto it = sdl_libs.begin(); it != sdl_libs.end(); ++it) + { + if ((sdl_handle = OpenPlugin(it->c_str()))) + break; + } + if (!sdl_handle) + { + out.printerr("title-folder: Could not load SDL.\n"); + return CR_FAILURE; + } + + #define bind(name) \ + _##name = (decltype(_##name))LookupPlugin(sdl_handle, #name); \ + if (!_##name) { \ + out.printerr("title-folder: Bind failed: " #name "\n"); \ + plugin_shutdown(out); \ + return CR_FAILURE; \ + } + + bind(SDL_WM_GetCaption); + bind(SDL_WM_SetCaption); + #undef bind + + const char *title = NULL; + SDL_WM_GetCaption(&title, NULL); + if (!title) + { + out.printerr("title-folder: Failed to get original title\n"); + plugin_shutdown(out); + return CR_FAILURE; + } + original_title = title; + + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown (color_ostream &out) +{ + if (is_enabled) + { + plugin_enable(out, false); + } + if (sdl_handle) + { + ClosePlugin(sdl_handle); + sdl_handle = NULL; + } + return CR_OK; +} + +DFhackCExport command_result plugin_enable (color_ostream &out, bool state) +{ + if (state == is_enabled) + return CR_OK; + + if (state) + { + std::string path = Core::getInstance().p->getPath(); + std::string folder; + size_t pos = path.find_last_of('/'); + if (pos == std::string::npos) + pos = path.find_last_of('\\'); + + if (pos != std::string::npos) + folder = path.substr(pos + 1); + else + folder = path; + + std::string title = original_title + " (" + folder + ")"; + SDL_WM_SetCaption(title.c_str(), NULL); + } + else + { + SDL_WM_SetCaption(original_title.c_str(), NULL); + } + + is_enabled = state; + return CR_OK; +} From 1b11c46a98699d534fe1b3573f2949e668831dc8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 10 Aug 2016 15:24:07 -0400 Subject: [PATCH 088/413] ruby.cpp: uint32_t -> uintptr_t --- plugins/ruby/ruby.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 127a49b69..340f38c58 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -572,7 +572,7 @@ static VALUE rb_dfget_global_address(VALUE self, VALUE name) static VALUE rb_dfget_vtable(VALUE self, VALUE name) { - return rb_uint2inum((uint32_t)Core::getInstance().vinfo->getVTable(rb_string_value_ptr(&name))); + return rb_uint2inum((uintptr_t)Core::getInstance().vinfo->getVTable(rb_string_value_ptr(&name))); } // read the c++ class name from a vtable pointer, inspired from doReadClassName @@ -622,7 +622,7 @@ static VALUE rb_dfmalloc(VALUE self, VALUE len) if (!ptr) return Qnil; memset(ptr, 0, FIX2INT(len)); - return rb_uint2inum((uint32_t)ptr); + return rb_uint2inum((uintptr_t)ptr); } static VALUE rb_dffree(VALUE self, VALUE ptr) @@ -746,7 +746,7 @@ static VALUE rb_dfmemory_pagealloc(VALUE self, VALUE len) { void *ret = Core::getInstance().p->memAlloc(rb_num2ulong(len)); - return (ret == (void*)-1) ? Qnil : rb_uint2inum((uint32_t)ret); + return (ret == (void*)-1) ? Qnil : rb_uint2inum((uintptr_t)ret); } // free memory from pagealloc @@ -789,7 +789,7 @@ static VALUE rb_dfmemory_pageprotect(VALUE self, VALUE ptr, VALUE len, VALUE pro static VALUE rb_dfmemory_stlstring_new(VALUE self) { std::string *ptr = new std::string; - return rb_uint2inum((uint32_t)ptr); + return rb_uint2inum((uintptr_t)ptr); } static VALUE rb_dfmemory_stlstring_delete(VALUE self, VALUE addr) { @@ -821,7 +821,7 @@ static VALUE rb_dfmemory_write_stlstring(VALUE self, VALUE addr, VALUE val) static VALUE rb_dfmemory_vec_new(VALUE self) { std::vector *ptr = new std::vector; - return rb_uint2inum((uint32_t)ptr); + return rb_uint2inum((uintptr_t)ptr); } static VALUE rb_dfmemory_vec_delete(VALUE self, VALUE addr) { @@ -844,7 +844,7 @@ static VALUE rb_dfmemory_vec8_length(VALUE self, VALUE addr) static VALUE rb_dfmemory_vec8_ptrat(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); - return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx))); + return rb_uint2inum((uintptr_t)&v->at(FIX2INT(idx))); } static VALUE rb_dfmemory_vec8_insertat(VALUE self, VALUE addr, VALUE idx, VALUE val) { @@ -868,7 +868,7 @@ static VALUE rb_dfmemory_vec16_length(VALUE self, VALUE addr) static VALUE rb_dfmemory_vec16_ptrat(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); - return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx))); + return rb_uint2inum((uintptr_t)&v->at(FIX2INT(idx))); } static VALUE rb_dfmemory_vec16_insertat(VALUE self, VALUE addr, VALUE idx, VALUE val) { @@ -892,7 +892,7 @@ static VALUE rb_dfmemory_vec32_length(VALUE self, VALUE addr) static VALUE rb_dfmemory_vec32_ptrat(VALUE self, VALUE addr, VALUE idx) { std::vector *v = (std::vector*)rb_num2ulong(addr); - return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx))); + return rb_uint2inum((uintptr_t)&v->at(FIX2INT(idx))); } static VALUE rb_dfmemory_vec32_insertat(VALUE self, VALUE addr, VALUE idx, VALUE val) { @@ -911,7 +911,7 @@ static VALUE rb_dfmemory_vec32_deleteat(VALUE self, VALUE addr, VALUE idx) static VALUE rb_dfmemory_vecbool_new(VALUE self) { std::vector *ptr = new std::vector; - return rb_uint2inum((uint32_t)ptr); + return rb_uint2inum((uintptr_t)ptr); } static VALUE rb_dfmemory_vecbool_delete(VALUE self, VALUE addr) { @@ -983,7 +983,7 @@ static VALUE rb_dfmemory_bitarray_set(VALUE self, VALUE addr, VALUE idx, VALUE v static VALUE rb_dfmemory_set_new(VALUE self) { std::set *ptr = new std::set; - return rb_uint2inum((uint32_t)ptr); + return rb_uint2inum((uintptr_t)ptr); } static VALUE rb_dfmemory_set_delete(VALUE self, VALUE set) From acc4a6a0b15fcdb98a225afe38ff5bac8b07a787 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 10 Aug 2016 15:48:47 -0400 Subject: [PATCH 089/413] Set CMAKE_POSITION_INDEPENDENT_CODE Needed on 64-bit Linux --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 441ad607e..a55940eff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,6 +175,7 @@ SET(DFHACK_DEVDOC_DESTINATION hack) OPTION(BUILD_LIBRARY "Build the library that goes into DF." ON) OPTION(BUILD_PLUGINS "Build the plugins." ON) +SET(CMAKE_POSITION_INDEPENDENT_CODE TRUE) IF(UNIX) ## flags for GCC # default to hidden symbols From 215afa34f3c4754184a7355df2ab6da79d4ea1d3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 10 Aug 2016 23:50:00 -0400 Subject: [PATCH 090/413] Update for 64-bit unit changes Includes xml, stonesense, scripts Ref DFHack/df-structures@25cb373 --- library/modules/Buildings.cpp | 9 +++--- library/modules/Units.cpp | 20 +++++++------ library/xml | 2 +- plugins/cursecheck.cpp | 6 ++-- plugins/devel/nestboxes.cpp | 2 +- plugins/fastdwarf.cpp | 14 +++++---- plugins/petcapRemover.cpp | 10 +++---- plugins/siege-engine.cpp | 53 ++++++++++++++++++----------------- plugins/stonesense | 2 +- plugins/strangemood.cpp | 35 ++++++++++++----------- plugins/zone.cpp | 11 ++++---- scripts | 2 +- 12 files changed, 87 insertions(+), 79 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 0d4de546d..d964c8a58 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -77,6 +77,7 @@ using namespace DFHack; #include "df/ui.h" #include "df/ui_look_list.h" #include "df/unit.h" +#include "df/unit_relationship_type.h" #include "df/world.h" using namespace df::enums; @@ -224,7 +225,7 @@ bool Buildings::setOwner(df::building *bld, df::unit *unit) auto &blist = bld->owner->owned_buildings; vector_erase_at(blist, linear_index(blist, bld)); - if (auto spouse = df::unit::find(bld->owner->relations.spouse_id)) + if (auto spouse = df::unit::find(bld->owner->relationship_ids[df::unit_relationship_type::Spouse])) { auto &blist = spouse->owned_buildings; vector_erase_at(blist, linear_index(blist, bld)); @@ -237,7 +238,7 @@ bool Buildings::setOwner(df::building *bld, df::unit *unit) { unit->owned_buildings.push_back(bld); - if (auto spouse = df::unit::find(unit->relations.spouse_id)) + if (auto spouse = df::unit::find(unit->relationship_ids[df::unit_relationship_type::Spouse])) { auto &blist = spouse->owned_buildings; if (bld->canUseSpouseRoom() && linear_index(blist, bld) < 0) @@ -1269,14 +1270,14 @@ bool Buildings::isHospital(df::building * building) return false; return ((df::building_civzonest*) building)->zone_flags.bits.hospital != 0; } - + bool Buildings::isAnimalTraining(df::building * building) { if (!isActivityZone(building)) return false; return ((df::building_civzonest*) building)->zone_flags.bits.animal_training != 0; } - + // returns building of pen/pit at cursor position (NULL if nothing found) df::building* Buildings::findPenPitAt(df::coord coord) { diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index a8e4c7452..0596d529f 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -70,6 +70,7 @@ using namespace std; #include "df/ui.h" #include "df/unit_inventory_item.h" #include "df/unit_misc_trait.h" +#include "df/unit_relationship_type.h" #include "df/unit_skill.h" #include "df/unit_soul.h" #include "df/unit_wound.h" @@ -170,9 +171,9 @@ void Units::CopyCreature(df::unit * source, t_unit & furball) // labors memcpy(&furball.labors, &source->status.labors, sizeof(furball.labors)); - furball.birth_year = source->relations.birth_year; - furball.birth_time = source->relations.birth_time; - furball.pregnancy_timer = source->relations.pregnancy_timer; + furball.birth_year = source->birth_year; + furball.birth_time = source->birth_time; + furball.pregnancy_timer = source->pregnancy_timer; // appearance furball.nbcolors = source->appearance.colors.size(); if(furball.nbcolors>MAX_COLORS) @@ -1085,10 +1086,10 @@ double Units::getAge(df::unit *unit, bool true_age) return -1; double year_ticks = 403200.0; - double birth_time = unit->relations.birth_year + unit->relations.birth_time/year_ticks; + double birth_time = unit->birth_year + unit->birth_time/year_ticks; double cur_time = *cur_year + *cur_year_tick / year_ticks; - if (!true_age && unit->relations.curse_year >= 0) + if (!true_age && unit->curse_year >= 0) { if (auto identity = getIdentity(unit)) { @@ -1453,7 +1454,8 @@ int Units::computeMovementSpeed(df::unit *unit) // Activity state - if (unit->relations.draggee_id != -1) speed += 1000; + if (unit->relationship_ids[df::unit_relationship_type::Draggee] != -1) + speed += 1000; if (unit->flags1.bits.on_ground) speed += 2000; @@ -1522,7 +1524,7 @@ int Units::computeMovementSpeed(df::unit *unit) if (is_adventure) { auto player = vector_get(world->units.active, 0); - if (player && player->id == unit->relations.group_leader_id) + if (player && player->id == unit->relationship_ids[df::unit_relationship_type::GroupLeader]) speed = std::min(speed, computeMovementSpeed(player)); } @@ -1551,14 +1553,14 @@ float Units::computeSlowdownFactor(df::unit *unit) { if (!unit->flags1.bits.marauder && casteFlagSet(unit->race, unit->caste, caste_raw_flags::MEANDERER) && - !(unit->relations.following && isCitizen(unit)) && + !(unit->following && isCitizen(unit)) && linear_index(unit->inventory, &df::unit_inventory_item::mode, df::unit_inventory_item::Hauled) < 0) { coeff *= 4.0f; } - if (unit->relations.group_leader_id < 0 && + if (unit->relationship_ids[df::unit_relationship_type::GroupLeader] < 0 && unit->flags1.bits.active_invader && !unit->job.current_job && !unit->flags3.bits.no_meandering && unit->profession != profession::THIEF && unit->profession != profession::MASTER_THIEF && diff --git a/library/xml b/library/xml index 402889961..d5036d833 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 40288996152af8460e747a7479ebc6dc0e617cd9 +Subproject commit d5036d8336d266bcb13e27e702a0acada01227a4 diff --git a/plugins/cursecheck.cpp b/plugins/cursecheck.cpp index 82404b288..263f91490 100644 --- a/plugins/cursecheck.cpp +++ b/plugins/cursecheck.cpp @@ -229,7 +229,7 @@ command_result cursecheck (color_ostream &out, vector & parameters) } // non-cursed creatures have curse_year == -1 - if(unit->relations.curse_year != -1) + if(unit->curse_year != -1) { cursecount++; @@ -268,8 +268,8 @@ command_result cursecheck (color_ostream &out, vector & parameters) } out.print("born in %d, cursed in %d to be a %s. (%s%s%s)\n", - unit->relations.birth_year, - unit->relations.curse_year, + unit->birth_year, + unit->curse_year, cursetype.c_str(), // technically most cursed creatures are undead, // therefore output 'active' if they are not completely dead diff --git a/plugins/devel/nestboxes.cpp b/plugins/devel/nestboxes.cpp index f4f423515..d29e97558 100644 --- a/plugins/devel/nestboxes.cpp +++ b/plugins/devel/nestboxes.cpp @@ -48,7 +48,7 @@ static void eggscan(color_ostream &out) if (nb->claimed_by != -1) { df::unit* u = df::unit::find(nb->claimed_by); - if (u && u->relations.pregnancy_timer > 0) + if (u && u->pregnancy_timer > 0) fertile = true; } for (int j = 1; j < nb->contained_items.size(); j++) diff --git a/plugins/fastdwarf.cpp b/plugins/fastdwarf.cpp index e0b2882b6..e8ae85c99 100644 --- a/plugins/fastdwarf.cpp +++ b/plugins/fastdwarf.cpp @@ -1,16 +1,17 @@ #include "Core.h" #include "Console.h" +#include "DataDefs.h" #include "Export.h" #include "PluginManager.h" #include "modules/Units.h" #include "modules/Maps.h" -#include "DataDefs.h" -#include "df/world.h" +#include "df/map_block.h" #include "df/unit.h" #include "df/unit_action.h" -#include "df/map_block.h" +#include "df/unit_relationship_type.h" #include "df/units_other_id.h" +#include "df/world.h" using std::string; using std::vector; @@ -56,11 +57,12 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) if (enable_teledwarf) do { // skip dwarves that are dragging creatures or being dragged - if ((unit->relations.draggee_id != -1) || (unit->relations.dragger_id != -1)) + if ((unit->relationship_ids[df::unit_relationship_type::Draggee] != -1) || + (unit->relationship_ids[df::unit_relationship_type::Dragger] != -1)) break; // skip dwarves that are following other units - if (unit->relations.following != 0) + if (unit->following != 0) break; // skip unconscious units @@ -105,7 +107,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) for (size_t j = 0; j < world->units.other[units_other_id::ANY_RIDER].size(); j++) { df::unit *rider = world->units.other[units_other_id::ANY_RIDER][j]; - if (rider->relations.rider_mount_id == unit->id) + if (rider->relationship_ids[df::unit_relationship_type::RiderMount] == unit->id) rider->pos = unit->pos; } } diff --git a/plugins/petcapRemover.cpp b/plugins/petcapRemover.cpp index c059db4c3..d35906a05 100644 --- a/plugins/petcapRemover.cpp +++ b/plugins/petcapRemover.cpp @@ -67,7 +67,7 @@ void impregnateMany() { if ( unit->flags1.bits.dead || unit->flags1.bits.active_invader || unit->flags2.bits.underworld || unit->flags2.bits.visitor_uninvited || unit->flags2.bits.visitor ) continue; popcount[unit->race]++; - if ( unit->relations.pregnancy_genes ) { + if ( unit->pregnancy_genes ) { //already pregnant //for player convenience and population stability, count the fetus toward the population cap popcount[unit->race]++; @@ -122,14 +122,14 @@ void impregnateMany() { bool impregnate(df::unit* female, df::unit* male) { if ( !female || !male ) return false; - if ( female->relations.pregnancy_genes ) + if ( female->pregnancy_genes ) return false; df::unit_genes* preg = new df::unit_genes; *preg = male->appearance.genes; - female->relations.pregnancy_genes = preg; - female->relations.pregnancy_timer = pregtime; //300000 for dwarves - female->relations.pregnancy_caste = male->caste; + female->pregnancy_genes = preg; + female->pregnancy_timer = pregtime; //300000 for dwarves + female->pregnancy_caste = male->caste; return true; } diff --git a/plugins/siege-engine.cpp b/plugins/siege-engine.cpp index 4ad8fa341..323e4292e 100644 --- a/plugins/siege-engine.cpp +++ b/plugins/siege-engine.cpp @@ -22,40 +22,41 @@ #include #include -#include "df/graphic.h" +#include "df/building_drawbuffer.h" #include "df/building_siegeenginest.h" -#include "df/builtin_mats.h" -#include "df/world.h" +#include "df/building_stockpilest.h" #include "df/buildings_other_id.h" -#include "df/job.h" -#include "df/building_drawbuffer.h" -#include "df/ui.h" -#include "df/viewscreen_dwarfmodest.h" -#include "df/ui_build_selector.h" -#include "df/flow_info.h" -#include "df/report.h" -#include "df/proj_itemst.h" -#include "df/unit.h" -#include "df/unit_soul.h" -#include "df/unit_skill.h" -#include "df/physical_attribute_type.h" -#include "df/creature_raw.h" +#include "df/builtin_mats.h" #include "df/caste_raw.h" #include "df/caste_raw_flags.h" -#include "df/identity.h" +#include "df/creature_raw.h" +#include "df/flow_info.h" +#include "df/flow_type.h" #include "df/game_mode.h" -#include "df/unit_misc_trait.h" -#include "df/job.h" -#include "df/job_item.h" +#include "df/graphic.h" +#include "df/identity.h" +#include "df/invasion_info.h" #include "df/item_actual.h" #include "df/items_other_id.h" -#include "df/building_stockpilest.h" +#include "df/job.h" +#include "df/job.h" +#include "df/job_item.h" +#include "df/material.h" +#include "df/physical_attribute_type.h" +#include "df/proj_itemst.h" +#include "df/report.h" #include "df/stockpile_links.h" -#include "df/workshop_profile.h" #include "df/strain_type.h" -#include "df/material.h" -#include "df/flow_type.h" -#include "df/invasion_info.h" +#include "df/ui.h" +#include "df/ui_build_selector.h" +#include "df/unit.h" +#include "df/unit_misc_trait.h" +#include "df/unit_relationship_type.h" +#include "df/unit_skill.h" +#include "df/unit_soul.h" +#include "df/viewscreen_dwarfmodest.h" +#include "df/workshop_profile.h" +#include "df/world.h" #include "MiscUtils.h" @@ -1193,7 +1194,7 @@ struct UnitPath { { if (unit->flags1.bits.rider) { - auto mount = df::unit::find(unit->relations.rider_mount_id); + auto mount = df::unit::find(unit->relationship_ids[df::unit_relationship_type::RiderMount]); if (mount) { diff --git a/plugins/stonesense b/plugins/stonesense index bd6e8f9f9..9270ceb54 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit bd6e8f9f90af1586f5b1eb0003d7e0e133acecc8 +Subproject commit 9270ceb5463657a6d039bdc3389fe69c78a0784b diff --git a/plugins/strangemood.cpp b/plugins/strangemood.cpp index 783f73d1f..2a0ed8509 100644 --- a/plugins/strangemood.cpp +++ b/plugins/strangemood.cpp @@ -2,6 +2,7 @@ #include "Core.h" #include "Console.h" +#include "DataDefs.h" #include "Export.h" #include "PluginManager.h" #include "modules/Gui.h" @@ -11,24 +12,24 @@ #include "modules/Translation.h" #include "modules/Random.h" -#include "DataDefs.h" +#include "df/builtin_mats.h" +#include "df/caste_raw.h" +#include "df/caste_raw_flags.h" +#include "df/creature_raw.h" #include "df/d_init.h" -#include "df/world.h" +#include "df/entity_raw.h" +#include "df/general_ref_unit_workerst.h" +#include "df/historical_entity.h" +#include "df/job.h" +#include "df/job_item.h" +#include "df/map_block.h" #include "df/ui.h" #include "df/unit.h" -#include "df/unit_soul.h" -#include "df/unit_skill.h" #include "df/unit_preference.h" -#include "df/map_block.h" -#include "df/job.h" -#include "df/job_item.h" -#include "df/historical_entity.h" -#include "df/entity_raw.h" -#include "df/builtin_mats.h" -#include "df/general_ref_unit_workerst.h" -#include "df/creature_raw.h" -#include "df/caste_raw.h" -#include "df/caste_raw_flags.h" +#include "df/unit_relationship_type.h" +#include "df/unit_skill.h" +#include "df/unit_soul.h" +#include "df/world.h" using std::string; using std::vector; @@ -579,9 +580,9 @@ command_result df_strangemood (color_ostream &out, vector & parameters) df::unit *cur = moodable_units[i]; if (cur->flags1.bits.had_mood) continue; - if (cur->relations.dragger_id != -1) + if (cur->relationship_ids[df::unit_relationship_type::Dragger] != -1) continue; - if (cur->relations.draggee_id != -1) + if (cur->relationship_ids[df::unit_relationship_type::Draggee] != -1) continue; tickets.push_back(i); for (int j = 0; j < 5; j++) @@ -699,7 +700,7 @@ command_result df_strangemood (color_ostream &out, vector & parameters) } unit->mood = type; - unit->relations.mood_copy = unit->mood; + unit->mood_copy = unit->mood; Gui::showAutoAnnouncement(announcement_type::STRANGE_MOOD, unit->pos, msg, color, bright); // TODO: make sure unit drops any wrestle items diff --git a/plugins/zone.cpp b/plugins/zone.cpp index 7772968a3..fe98e8811 100644 --- a/plugins/zone.cpp +++ b/plugins/zone.cpp @@ -72,6 +72,7 @@ #include "df/general_ref_building_civzone_assignedst.h" #include #include +#include "df/unit_relationship_type.h" #include "df/unit_soul.h" #include "df/unit_wound.h" #include "df/viewscreen_dwarfmodest.h" @@ -982,7 +983,7 @@ command_result assignUnitToCage(color_ostream& out, df::unit* unit, df::building } // don't assign owned pets to a cage. the owner will release them, resulting into infinite hauling (df bug) - if(unit->relations.pet_owner_id != -1) + if(unit->relationship_ids[df::unit_relationship_type::Pet] != -1) return CR_OK; // check if unit is already pastured or caged, remove refs where necessary @@ -2362,8 +2363,8 @@ bool compareUnitAgesYounger(df::unit* i, df::unit* j) int32_t age_j = (int32_t) getAge(j, true); if(age_i == 0 && age_j == 0) { - age_i = i->relations.birth_time; - age_j = j->relations.birth_time; + age_i = i->birth_time; + age_j = j->birth_time; } return (age_i < age_j); } @@ -2373,8 +2374,8 @@ bool compareUnitAgesOlder(df::unit* i, df::unit* j) int32_t age_j = (int32_t) getAge(j, true); if(age_i == 0 && age_j == 0) { - age_i = i->relations.birth_time; - age_j = j->relations.birth_time; + age_i = i->birth_time; + age_j = j->birth_time; } return (age_i > age_j); } diff --git a/scripts b/scripts index b1e7544d8..9558feba7 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit b1e7544d87a59e86ae74a2468b18c0b319526932 +Subproject commit 9558feba77c57168a7970e1ebcbc1c7b3a82ab97 From a1ff432bf8165d29c6f76857147f72c050006690 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 10 Aug 2016 23:58:45 -0400 Subject: [PATCH 091/413] Restore fixed-width types in string representations of lua fields e.g. tostring(df.new('int16_t')) was returning "" --- library/DataStaticsFields.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index 8ff0770fc..d6a622a9e 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -11,23 +11,23 @@ #endif namespace df { -#define NUMBER_IDENTITY_TRAITS(category, type) \ - category##_identity identity_traits::identity(#type); -#define INTEGER_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(integer, type) -#define FLOAT_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(float, type) +#define NUMBER_IDENTITY_TRAITS(category, type, name) \ + category##_identity identity_traits::identity(name); +#define INTEGER_IDENTITY_TRAITS(type, name) NUMBER_IDENTITY_TRAITS(integer, type, name) +#define FLOAT_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(float, type, #type) #ifndef STATIC_FIELDS_GROUP - INTEGER_IDENTITY_TRAITS(char); - INTEGER_IDENTITY_TRAITS(signed char); - INTEGER_IDENTITY_TRAITS(unsigned char); - INTEGER_IDENTITY_TRAITS(short); - INTEGER_IDENTITY_TRAITS(unsigned short); - INTEGER_IDENTITY_TRAITS(int); - INTEGER_IDENTITY_TRAITS(unsigned int); - INTEGER_IDENTITY_TRAITS(long); - INTEGER_IDENTITY_TRAITS(unsigned long); - INTEGER_IDENTITY_TRAITS(long long); - INTEGER_IDENTITY_TRAITS(unsigned long long); + INTEGER_IDENTITY_TRAITS(char, "char"); + INTEGER_IDENTITY_TRAITS(signed char, "int8_t"); + INTEGER_IDENTITY_TRAITS(unsigned char, "uint8_t"); + INTEGER_IDENTITY_TRAITS(short, "int16_t"); + INTEGER_IDENTITY_TRAITS(unsigned short, "uint16_t"); + INTEGER_IDENTITY_TRAITS(int, "int32_t"); + INTEGER_IDENTITY_TRAITS(unsigned int, "uint32_t"); + INTEGER_IDENTITY_TRAITS(long, "long"); + INTEGER_IDENTITY_TRAITS(unsigned long, "unsigned long"); + INTEGER_IDENTITY_TRAITS(long long, "int64_t"); + INTEGER_IDENTITY_TRAITS(unsigned long long, "uint64_t"); FLOAT_IDENTITY_TRAITS(float); FLOAT_IDENTITY_TRAITS(double); From eef6f9bfb7468096fbe4f7618463368338cbd87f Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 Aug 2016 00:01:52 -0400 Subject: [PATCH 092/413] Add df.new() support for char and unsigned long --- library/LuaWrapper.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 992ab355c..f7b2bbb1c 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -449,10 +449,12 @@ Lua::ObjectClass Lua::IsDFObject(lua_State *state, int val_index) static const char *const primitive_types[] = { "string", "ptr-string", + "char", "int8_t", "uint8_t", "int16_t", "uint16_t", "int32_t", "uint32_t", "int64_t", "uint64_t", - "intptr_t", "uintptr_t", "long", - "bool", "float", "double", + "intptr_t", "uintptr_t", "long", "unsigned long", + "bool", + "float", "double", "pointer", "ptr-vector", "bit-vector", @@ -462,12 +464,13 @@ static const char *const primitive_types[] = { static type_identity *const primitive_identities[] = { df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), - df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), df::identity_traits::get(), From fe6968f01d7de19e4fcbec41fbc73099045eb6bd Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 Aug 2016 11:57:42 -0400 Subject: [PATCH 093/413] Fix script-docs.py error with missing opening token --- travis/script-docs.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/travis/script-docs.py b/travis/script-docs.py index 2bce4bfd2..33b2818c8 100644 --- a/travis/script-docs.py +++ b/travis/script-docs.py @@ -42,6 +42,11 @@ def check_file(fname): else: print('Error: no documentation in: ' + fname) return 1 + + if not doclines: + print('Error: missing or malformed documentation in: ' + fname) + return 1 + title, underline = [d for d in doclines if d and '=begin' not in d and '[====[' not in d][:2] if underline != '=' * len(title): From 9b495fe08b2604e246e59eb285dea235af4dd101 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 Aug 2016 12:51:18 -0400 Subject: [PATCH 094/413] Add load-save.lua Ref #755 --- NEWS.rst | 4 ++++ scripts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS.rst b/NEWS.rst index 2d3dd858a..97daeee32 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -37,6 +37,10 @@ New Plugins ----------- - `title-folder`: shows DF folder name in window title bar when enabled +New Scripts +----------- +- `load-save`: loads a save non-interactively + DFHack 0.43.03-r1 ================= diff --git a/scripts b/scripts index 9558feba7..274e7c372 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 9558feba77c57168a7970e1ebcbc1c7b3a82ab97 +Subproject commit 274e7c372c83611d8fad53345a0cb9ad2a1f10df From 5ab930ba4dc7b6614aea5ad6c9c417b55a47d2e0 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 11 Aug 2016 16:56:34 -0500 Subject: [PATCH 095/413] labormanager: small tweaks Handle cloth crafts correctly; handle pit jobs correctly; handle bookcase construction correctly; deal with new break behavior better; change assignment of clean labor; tweak hauling assignments slightly to avoid overallocation; assign pull lever to everyone and clean to all nonbusy dwarfs --- plugins/devel/labormanager.cpp | 73 ++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index cb5f11dfc..edae051dc 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -999,6 +999,8 @@ private: } case df::item_type::WOOD: return df::unit_labor::WOOD_CRAFT; + case df::item_type::CLOTH: + return df::unit_labor::CLOTHESMAKER; default: debug ("LABORMANAGER: Cannot deduce labor for make crafts job, item type %s\n", ENUM_KEY_STR(item_type, jobitem).c_str()); @@ -1304,7 +1306,7 @@ public: job_to_labor_table[df::job_type::GiveWater2] = jlf_no_labor; job_to_labor_table[df::job_type::GiveFood2] = jlf_no_labor; job_to_labor_table[df::job_type::RecoverPet] = jlf_no_labor; - job_to_labor_table[df::job_type::PitLargeAnimal] = jlf_no_labor; + job_to_labor_table[df::job_type::PitLargeAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::PitSmallAnimal] = jlf_no_labor; job_to_labor_table[df::job_type::SlaughterAnimal] = jlf_const(df::unit_labor::BUTCHER); job_to_labor_table[df::job_type::MakeCharcoal] = jlf_const(df::unit_labor::BURN_WOOD); @@ -1339,7 +1341,7 @@ public: job_to_labor_table[df::job_type::SpinThread] = jlf_const(df::unit_labor::SPINNER); job_to_labor_table[df::job_type::PenLargeAnimal] = jlf_const(df::unit_labor::HAUL_ANIMALS); job_to_labor_table[df::job_type::PenSmallAnimal] = jlf_no_labor; - job_to_labor_table[df::job_type::MakeTool] = jlf_make_furniture; + job_to_labor_table[df::job_type::MakeTool] = jlf_make_object; job_to_labor_table[df::job_type::CollectClay] = jlf_const(df::unit_labor::POTTERY); job_to_labor_table[df::job_type::InstallColonyInHive] = jlf_const(df::unit_labor::BEEKEEPING); job_to_labor_table[df::job_type::CollectHiveProducts] = jlf_const(df::unit_labor::BEEKEEPING); @@ -1551,7 +1553,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector dwarf->status.misc_traits.begin(); p < dwarf->dwarf->status.misc_traits.end(); p++) { - if ((*p)->id == misc_trait_type::Migrant || (*p)->id == misc_trait_type::OnBreak) - is_on_break = true; + if ((*p)->id == misc_trait_type::Migrant) + is_migrant = true; + } + + if (dwarf->dwarf->social_activities.size() > 0) + { + if (print_debug) + out.print ("Dwarf %s is engaged in a social activity. Info only.\n", dwarf->dwarf->name.first_name.c_str()); } if (dwarf->dwarf->profession == profession::BABY || @@ -1985,7 +1993,7 @@ private: else if (dwarf->dwarf->job.current_job == NULL) { - if (is_on_break || dwarf->dwarf->flags1.bits.chained || dwarf->dwarf->flags1.bits.caged) + if (is_migrant || dwarf->dwarf->flags1.bits.chained || dwarf->dwarf->flags1.bits.caged) { state = OTHER; dwarf->clear_all = true; @@ -2351,6 +2359,8 @@ public: } + labor_needed[df::unit_labor::CLEAN] = 1; + if (print_debug) { for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) @@ -2374,7 +2384,10 @@ public: if (i->second > 0) { int priority = labor_infos[l].priority(); - priority += labor_infos[l].time_since_last_assigned()/12; + + if (l < df::unit_labor::HAUL_STONE || l > df::unit_labor::HAUL_ANIMALS) + priority += labor_infos[l].time_since_last_assigned()/12; + for (int n = 0; n < labor_infos[l].busy_dwarfs; n++) priority /= 2; pq.push(make_pair(priority, l)); @@ -2511,7 +2524,8 @@ public: continue; int score = score_labor (*d, l); - score += labor_infos[l].time_since_last_assigned()/12; + if (l < df::unit_labor::HAUL_STONE || l > df::unit_labor::HAUL_ANIMALS) + score += labor_infos[l].time_since_last_assigned()/12; if (l == df::unit_labor::HAUL_FOOD && priority_food > 0) score += 1000000; @@ -2521,11 +2535,6 @@ public: if (t == TOOL_NONE || (*d)->has_tool[t]) { set_labor(*d, l, true); - if (print_debug) - out.print("assign \"%s\" extra labor %s score=%d current %s score=%d\n", - (*d)->dwarf->name.first_name.c_str(), - ENUM_KEY_STR(unit_labor, l).c_str(), score, - ENUM_KEY_STR(unit_labor, (*d)->using_labor).c_str(), current_score); } if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000 && default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) set_labor(*d, (*d)->using_labor, false); @@ -2582,6 +2591,39 @@ public: } } + /* check for dwarfs assigned no labors and assign them the bucket list if there are */ + for (auto d = dwarf_info.begin(); d != dwarf_info.end(); d++) + { + if ((*d)->state == CHILD) + continue; + + bool any = false; + FOR_ENUM_ITEMS (unit_labor, l) + { + if (l == df::unit_labor::NONE) + continue; + if ((*d)->dwarf->status.labors[l]) + { + any = true; + break; + } + } + + set_labor (*d, df::unit_labor::PULL_LEVER, true); + + if (any) continue; + + FOR_ENUM_ITEMS (unit_labor, l) + { + if (l == df::unit_labor::NONE) + continue; + + if (to_assign[l] > 0 || l == df::unit_labor::CLEAN) + set_labor(*d, l, true); + } + } + + /* set reequip on any dwarfs who are carrying tools needed by others */ for (auto d = dwarf_info.begin(); d != dwarf_info.end(); d++) @@ -2606,9 +2648,6 @@ public: if (has_tool != needs_tool) { - if (has_tool && tool_count[t] > tool_in_use[t]) - continue; - df::job_type j = df::job_type::NONE; if ((*d)->dwarf->job.current_job) From a55ce5f1d91486982148b9e62baaedb7c8631d01 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 11 Aug 2016 16:58:35 -0500 Subject: [PATCH 096/413] labormanager: whitespace --- plugins/devel/labormanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index edae051dc..7d41c7814 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -2594,13 +2594,13 @@ public: /* check for dwarfs assigned no labors and assign them the bucket list if there are */ for (auto d = dwarf_info.begin(); d != dwarf_info.end(); d++) { - if ((*d)->state == CHILD) + if ((*d)->state == CHILD) continue; bool any = false; FOR_ENUM_ITEMS (unit_labor, l) { - if (l == df::unit_labor::NONE) + if (l == df::unit_labor::NONE) continue; if ((*d)->dwarf->status.labors[l]) { From 1a79e7456c871ca1eecaf5dada85dca0582040b0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 Aug 2016 18:43:34 -0400 Subject: [PATCH 097/413] Add shell script to build docs Useful for testing docs without changing BUILD_DOCS if it's set to OFF. --- docs/build.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 docs/build.sh diff --git a/docs/build.sh b/docs/build.sh new file mode 100755 index 000000000..d9c0428ad --- /dev/null +++ b/docs/build.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# usage: +# ./build.sh +# ./build.sh sphinx-executable +# JOBS=3 ./build.sh ... + +cd $(dirname "$0") +cd .. + +sphinx=sphinx-build +if [ -n "$1" ]; then + sphinx=$1 +fi + +if [ -z "$JOBS" ]; then + JOBS=2 +fi + +"$sphinx" -a -E -q -b html . ./docs/html -w ./docs/_sphinx-warnings.txt -j "$JOBS" From 99813038e9e33246d2c9a4ac3cdfc526b9d0e4b1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 Aug 2016 23:42:58 -0400 Subject: [PATCH 098/413] Update labormanager for unit.relations removal and fix warnings --- plugins/devel/labormanager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 7d41c7814..e2c188d68 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -687,7 +688,7 @@ static df::unit_labor construction_build_labor (df::item* i) color_ostream* debug_stream; -void debug (char* fmt, ...) +void debug (const char* fmt, ...) { if (debug_stream) { @@ -1924,7 +1925,7 @@ private: for (auto u2 = world->units.active.begin(); u2 != world->units.active.end(); ++u2) { - if ((*u2)->relations.mother_id == dwarf->dwarf->id && + if ((*u2)->relationship_ids[df::unit_relationship_type::Mother] == dwarf->dwarf->id && !(*u2)->flags1.bits.dead && ((*u2)->profession == df::profession::CHILD || (*u2)->profession == df::profession::BABY)) { From a1c25570df856d7304cd0628dad32fe4b67cc56c Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 Aug 2016 23:49:15 -0400 Subject: [PATCH 099/413] Move labormanager to plugins/, per request --- plugins/CMakeLists.txt | 1 + plugins/devel/CMakeLists.txt | 1 - plugins/{devel => }/labormanager.cpp | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename plugins/{devel => }/labormanager.cpp (100%) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index f36b0fa0b..a81d0993a 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -110,6 +110,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(infiniteSky infiniteSky.cpp) DFHACK_PLUGIN(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) DFHACK_PLUGIN(jobutils jobutils.cpp) + DFHACK_PLUGIN(labormanager labormanager.cpp) DFHACK_PLUGIN(lair lair.cpp) DFHACK_PLUGIN(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) DFHACK_PLUGIN(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) diff --git a/plugins/devel/CMakeLists.txt b/plugins/devel/CMakeLists.txt index a1e5b7f14..e5001fff7 100644 --- a/plugins/devel/CMakeLists.txt +++ b/plugins/devel/CMakeLists.txt @@ -9,7 +9,6 @@ DFHACK_PLUGIN(counters counters.cpp) DFHACK_PLUGIN(dumpmats dumpmats.cpp) DFHACK_PLUGIN(eventExample eventExample.cpp) DFHACK_PLUGIN(frozen frozen.cpp) -DFHACK_PLUGIN(labormanager labormanager.cpp) DFHACK_PLUGIN(kittens kittens.cpp) DFHACK_PLUGIN(memview memview.cpp) DFHACK_PLUGIN(nestboxes nestboxes.cpp) diff --git a/plugins/devel/labormanager.cpp b/plugins/labormanager.cpp similarity index 100% rename from plugins/devel/labormanager.cpp rename to plugins/labormanager.cpp From bb66ec6aee7ba07151134c17773c046d21205cd3 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Fri, 12 Aug 2016 19:04:23 +1000 Subject: [PATCH 100/413] Add 'Using Commands' to docs, with pull#767 syntax Plus consequential changes and minor updates to the table of contents. --- docs/Core.rst | 73 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/docs/Core.rst b/docs/Core.rst index a65d16e12..9367338e0 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -4,6 +4,12 @@ DFHack Core ########### +.. contents:: + :depth: 2 + + +Command Implementation +====================== DFHack commands can be implemented in three ways, all of which are used in the same way: @@ -21,7 +27,42 @@ are used in the same way: Most third-party DFHack addons are scripts. -.. contents:: +Using DFHack Commands +===================== +DFHack commands can be executed in a number of ways: + +#. Typing the command into the DFHack console (see below) +#. From the OS terminal (see below) +#. Pressing a key combination set up with `keybinding` +#. From one of several `init-files`, automatically +#. Using `script` to run a batch of commands from a file + +The command line has some nice line editing capabilities, including history +that's preserved between different runs of DF - use :kbd:`↑` and :kbd:`↓` +to go through the history. + +To include whitespace in the argument/s to some command, quote it in +double quotes. To include a double quote character, use ``\"``. + +If the first non-whitespace character is ``:``, the command is parsed in +an alternative mode. The non-whitespace characters following the ``:`` are +the command name, and the remaining part of the line is used verbatim as +the first argument. This is very useful for the `lua` and `rb` commands. +As an example, the following two command lines are exactly equivalent:: + + :foo a b "c d" e f + foo "a b \"c d\" e f" + +There are two ways to run DFHack commands from an OS terminal. + +* If DF and DFHack are already running, calling ``dfhack-run my command`` + in an external terminal is equivalent to calling ``my command`` in the + DFHack console. This executable is provided to support external programs, + and is not intended for direct use. + +* If DF/DFHack is started with arguments beginning with ``+``, the remaining + text is treated as a command in the DFHack console. For example, use + `load-save` to skip the main menu with ``./dfhack +load-save region1``. Built-in Commands @@ -29,6 +70,8 @@ Built-in Commands The following commands are provided by the 'core' components of DFhack, rather than plugins or scripts. +.. contents:: + :local: .. _cls: @@ -245,6 +288,10 @@ The following commands are *not* built-in, but offer similarly useful functions. Init Files ========== + +.. contents:: + :local: + DFHack allows users to automatically run commonly-used DFHack commands when DF is first loaded, when a game is loaded, and when a game is unloaded. @@ -329,34 +376,14 @@ Miscellaneous Notes =================== This section is for odd but important notes that don't fit anywhere else. -* The ``dfhack-run`` executable is there for calling DFHack commands in - an already running DF+DFHack instance from external OS scripts and programs, - and is *not* the way how you use DFHack normally. - * If a DF :kbd:`H` hotkey is named with a DFHack command, pressing the corresponding :kbd:`Fx` button will run that command, instead of zooming to the set location. - -* The command line has some nice line editing capabilities, including history - that's preserved between different runs of DF (use up/down keys to go through - the history). + *This feature will be removed in a future version.* (see :issue:`731`) * The binaries for 0.40.15-r1 to 0.34.11-r4 are on DFFD_. Older versions are available here_. + *These files will eventually be migrated to GitHub.* (see :issue:`473`) .. _DFFD: http://dffd.bay12games.com/search.php?string=DFHack&id=15&limit=1000 .. _here: http://dethware.org/dfhack/download - -* To include whitespace in the argument/s to some command, quote it in - double quotes. To include a double quote character, use ``\"``. - -* If the first non-whitespace character is ``:``, the command is parsed in - an alternative mode which is very useful for the `lua` and `rb` commands. - The following two command lines are exactly equivalent:: - - :foo a b "c d" e f - foo "a b \"c d\" e f" - - * non-whitespace characters following the ``:`` are the command name - * the remaining part of the line is used verbatim as the first argument - From 468cca3f09fbc1c682b0542814f0fff4c36cf657 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Sat, 13 Aug 2016 13:42:12 +1000 Subject: [PATCH 101/413] Improve docs on use of OS terminal for DFHack cmds --- docs/Core.rst | 47 +++++++++++++++++++++++++++++++++++++++-------- docs/Plugins.rst | 2 ++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/docs/Core.rst b/docs/Core.rst index 9367338e0..1c24fd825 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -37,6 +37,8 @@ DFHack commands can be executed in a number of ways: #. From one of several `init-files`, automatically #. Using `script` to run a batch of commands from a file +The DFHack Console +------------------ The command line has some nice line editing capabilities, including history that's preserved between different runs of DF - use :kbd:`↑` and :kbd:`↓` to go through the history. @@ -53,16 +55,45 @@ As an example, the following two command lines are exactly equivalent:: :foo a b "c d" e f foo "a b \"c d\" e f" -There are two ways to run DFHack commands from an OS terminal. +Using an OS terminal +-------------------- +DFHack commands can be run from an OS terminal at startup, using '+ args', +or at any other time using the ``dfhack-run`` executable. -* If DF and DFHack are already running, calling ``dfhack-run my command`` - in an external terminal is equivalent to calling ``my command`` in the - DFHack console. This executable is provided to support external programs, - and is not intended for direct use. +If DF/DFHack is started with arguments beginning with ``+``, the remaining +text is treated as a command in the DFHack console. It is possible to use +multiple such commands, which are split on ``+``. For example:: -* If DF/DFHack is started with arguments beginning with ``+``, the remaining - text is treated as a command in the DFHack console. For example, use - `load-save` to skip the main menu with ``./dfhack +load-save region1``. + ./dfhack +load-save region1 + "Dwarf Fortress.exe" +devel/print-args Hello! +enable workflow + +The first example (\*nix), `load-save`, skips the main menu and loads +``region1`` immediately. The second (Windows) example prints +:guilabel:`Hello!` in the DFHack console, and `enables ` `workflow`. +Note that the ``:foo`` syntax for whitespace in arguments is not compatible \ +with '+ args'. + + +If DF and DFHack are already running, calling ``dfhack-run my command`` +in an external terminal is equivalent to calling ``my command`` in the +DFHack console. Direct use of the DFhack console is generally easier, +but ``dfhack-run`` can be useful in a variety of circumstances: + +- if the console is unavailable + + - with the init setting ``PRINT_MODE:TEXT`` + - while running an interactive command (eg. `liquids` or `tiletypes`) + +- from external programs or scripts +- if DF or DFHack are not responding + +Examples:: + + ./dfhack-run cursecheck + dfhack-run multicmd kill-lua; die + +The first (\*nix) example `checks for vampires `; the +second (Windows) example uses `kill-lua` to cancel a script and exits. Built-in Commands diff --git a/docs/Plugins.rst b/docs/Plugins.rst index efd5da0e6..c1ca5a56d 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -57,6 +57,8 @@ An in-development plugin for realtime fortress visualisation. See :forums:`Armok Vision <146473>`. +.. _cursecheck: + cursecheck ========== Checks a single map tile or the whole map/world for cursed creatures (ghosts, From 570ac8d719014baa46d948079e474c302abfd443 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Sat, 13 Aug 2016 15:46:15 +1000 Subject: [PATCH 102/413] Add link to createitem wiki page --- docs/Plugins.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index c1ca5a56d..7746b8b51 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -2210,7 +2210,8 @@ createitem Allows creating new items of arbitrary types and made of arbitrary materials. 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 * If the item has no subtype, omit the :NONE @@ -2226,7 +2227,10 @@ Examples:: createitem WOOD PLANT_MAT:TOWER_CAP:WOOD Create tower-cap logs. -To change where new items are placed, first run the command with a destination type while an appropriate destination is selected. +For more examples, :wiki:`see this wiki page `. + +To change where new items are placed, first run the command with a +destination type while an appropriate destination is selected. Options: From 18a851224248623878371b530e82b52e624a31de Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 13 Aug 2016 11:40:30 -0400 Subject: [PATCH 103/413] Fix LLONG_MAX/LLONG_MIN in luaconf.h with old glibc versions --- depends/lua/include/luaconf.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/depends/lua/include/luaconf.h b/depends/lua/include/luaconf.h index 1c19bbeb4..ce96b4747 100644 --- a/depends/lua/include/luaconf.h +++ b/depends/lua/include/luaconf.h @@ -14,6 +14,15 @@ #define LUA_COMPAT_APIINTCASTS #define LUA_COMPAT_IPAIRS +// Patch for old glibc versions +#if !defined(LLONG_MAX) && defined(__LONG_LONG_MAX__) +#define LLONG_MAX __LONG_LONG_MAX__ +#endif + +#if !defined(LLONG_MIN) && defined(__LONG_LONG_MAX__) +#define LLONG_MIN (-__LONG_LONG_MAX__ - 1LL) +#endif + /* ** =================================================================== ** Search for "@@" to find all configurable definitions. From 576174ea0babdb06d05baecbff0719e9ba9201d1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 13 Aug 2016 19:52:14 -0400 Subject: [PATCH 104/413] Lua: Add lengths of (some) containers to their string representations --- library/LuaWrapper.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index f7b2bbb1c..6e7f81102 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -996,10 +996,23 @@ static int meta_ptr_tostring(lua_State *state) { uint8_t *ptr = get_object_addr(state, 1, 0, "access"); + bool has_length = false; + uint64_t length = 0; + auto *cid = dynamic_cast(get_object_identity(state, 1, "__tostring()", true, true)); + + if (cid && (cid->type() == IDTYPE_CONTAINER || cid->type() == IDTYPE_STL_PTR_VECTOR)) + { + has_length = true; + length = cid->lua_item_count(state, ptr, container_identity::COUNT_LEN); + } + lua_getfield(state, UPVAL_METATABLE, "__metatable"); const char *cname = lua_tostring(state, -1); - lua_pushstring(state, stl_sprintf("<%s: %p>", cname, (void*)ptr).c_str()); + if (has_length) + lua_pushstring(state, stl_sprintf("<%s[%llu]: %p>", cname, length, (void*)ptr).c_str()); + else + lua_pushstring(state, stl_sprintf("<%s: %p>", cname, (void*)ptr).c_str()); return 1; } From e965f5318fb6876b10431882cfbf7fa5ecd10e43 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 13 Aug 2016 21:44:01 -0400 Subject: [PATCH 105/413] Replace many includes with forward declarations in modules/Maps.h --- library/LuaApi.cpp | 1 + library/include/modules/Buildings.h | 59 ++--------- library/include/modules/Maps.h | 39 ++++--- library/modules/Buildings.cpp | 55 ++++++++++ library/modules/Burrows.cpp | 13 +-- library/modules/Constructions.cpp | 16 +-- library/modules/MapCache.cpp | 38 +++---- library/modules/Maps.cpp | 37 +++---- plugins/changelayer.cpp | 23 ++-- plugins/changevein.cpp | 4 + plugins/cleaners.cpp | 15 ++- plugins/deramp.cpp | 3 + plugins/devel/frozen.cpp | 6 +- plugins/devel/kittens.cpp | 21 ++-- plugins/devel/tilesieve.cpp | 1 + plugins/fixveins.cpp | 5 + plugins/follow.cpp | 18 ++-- plugins/lair.cpp | 3 + plugins/liquids.cpp | 21 ++-- plugins/plants.cpp | 2 + plugins/power-meter.cpp | 42 ++++---- plugins/probe.cpp | 38 ++++--- plugins/remotefortressreader.cpp | 151 +++++++++++++-------------- plugins/rendermax/renderer_light.cpp | 23 ++-- plugins/reveal.cpp | 5 +- plugins/steam-engine.cpp | 50 ++++----- plugins/tiletypes.cpp | 16 ++- plugins/tubefill.cpp | 2 + 28 files changed, 390 insertions(+), 317 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index df077ccc1..997d57a38 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -89,6 +89,7 @@ distribution. #include "df/proj_itemst.h" #include "df/itemdef.h" #include "df/enabler.h" +#include "df/feature_init.h" #include #include diff --git a/library/include/modules/Buildings.h b/library/include/modules/Buildings.h index de78acda6..16df7b212 100644 --- a/library/include/modules/Buildings.h +++ b/library/include/modules/Buildings.h @@ -26,19 +26,20 @@ distribution. #include "Export.h" #include "DataDefs.h" #include "Types.h" +#include "modules/Items.h" +#include "modules/Maps.h" + #include "df/building.h" #include "df/building_stockpilest.h" #include "df/building_type.h" #include "df/civzone_type.h" +#include "df/construction_type.h" #include "df/furnace_type.h" #include "df/item.h" -#include "df/workshop_type.h" -#include "df/construction_type.h" #include "df/shop_type.h" #include "df/siegeengine_type.h" #include "df/trap_type.h" -#include "modules/Items.h" -#include "modules/Maps.h" +#include "df/workshop_type.h" namespace df { @@ -220,55 +221,7 @@ public: item = NULL; } - StockpileIterator& operator++() { - while (stockpile) { - if (block) { - // Check the next item in the current block. - ++current; - } else { - // Start with the top-left block covering the stockpile. - block = Maps::getTileBlock(stockpile->x1, stockpile->y1, stockpile->z); - current = 0; - } - - while (current >= block->items.size()) { - // Out of items in this block; find the next block to search. - if (block->map_pos.x + 16 < stockpile->x2) { - block = Maps::getTileBlock(block->map_pos.x + 16, block->map_pos.y, stockpile->z); - current = 0; - } else if (block->map_pos.y + 16 < stockpile->y2) { - block = Maps::getTileBlock(stockpile->x1, block->map_pos.y + 16, stockpile->z); - current = 0; - } else { - // All items in all blocks have been checked. - block = NULL; - item = NULL; - return *this; - } - } - - // If the current item isn't properly stored, move on to the next. - item = df::item::find(block->items[current]); - if (!item->flags.bits.on_ground) { - continue; - } - - if (!Buildings::containsTile(stockpile, item->pos, false)) { - continue; - } - - // Ignore empty bins, barrels, and wheelbarrows assigned here. - if (item->isAssignedToThisStockpile(stockpile->id)) { - auto ref = Items::getGeneralRef(item, df::general_ref_type::CONTAINS_ITEM); - if (!ref) continue; - } - - // Found a valid item; yield it. - break; - } - - return *this; - } + StockpileIterator& operator++(); void begin(df::building_stockpilest* sp) { stockpile = sp; diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index 7ce594522..af3a9f5d5 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -36,22 +36,33 @@ distribution. #include "BitArray.h" #include "modules/Materials.h" -#include "df/world.h" -#include "df/world_data.h" -#include "df/map_block.h" -#include "df/block_square_event.h" -#include "df/block_square_event_mineralst.h" -#include "df/block_square_event_frozen_liquidst.h" -#include "df/block_square_event_world_constructionst.h" -#include "df/block_square_event_material_spatterst.h" -#include "df/block_square_event_grassst.h" -#include "df/block_square_event_spoorst.h" -#include "df/block_square_event_item_spatterst.h" -#include "df/tile_liquid.h" +#include "df/block_flags.h" +#include "df/feature_type.h" +#include "df/flow_type.h" #include "df/tile_dig_designation.h" +#include "df/tile_liquid.h" #include "df/tile_traffic.h" -#include "df/feature_init.h" -#include "df/flow_type.h" +#include "df/tiletype.h" + +namespace df { + struct block_square_event; + struct block_square_event_frozen_liquidst; + struct block_square_event_grassst; + struct block_square_event_item_spatterst; + struct block_square_event_material_spatterst; + struct block_square_event_mineralst; + struct block_square_event_spoorst; + struct block_square_event_world_constructionst; + struct feature_init; + struct map_block; + struct map_block_column; + struct region_map_entry; + struct world; + struct world_data; + struct world_geo_biome; + union tile_designation; + union tile_occupancy; +} /** * \defgroup grp_maps Maps module and its types diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index d964c8a58..b7933f6ef 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -49,6 +49,7 @@ using namespace std; using namespace DFHack; #include "DataDefs.h" + #include "df/building_axle_horizontalst.h" #include "df/building_bars_floorst.h" #include "df/building_bars_verticalst.h" @@ -74,6 +75,8 @@ using namespace DFHack; #include "df/item.h" #include "df/job.h" #include "df/job_item.h" +#include "df/map_block.h" +#include "df/tile_occupancy.h" #include "df/ui.h" #include "df/ui_look_list.h" #include "df/unit.h" @@ -1290,3 +1293,55 @@ df::building* Buildings::findPenPitAt(df::coord coord) } return NULL; } + +using Buildings::StockpileIterator; +StockpileIterator& StockpileIterator::operator++() { + while (stockpile) { + if (block) { + // Check the next item in the current block. + ++current; + } else { + // Start with the top-left block covering the stockpile. + block = Maps::getTileBlock(stockpile->x1, stockpile->y1, stockpile->z); + current = 0; + } + + while (current >= block->items.size()) { + // Out of items in this block; find the next block to search. + if (block->map_pos.x + 16 < stockpile->x2) { + block = Maps::getTileBlock(block->map_pos.x + 16, block->map_pos.y, stockpile->z); + current = 0; + } else if (block->map_pos.y + 16 < stockpile->y2) { + block = Maps::getTileBlock(stockpile->x1, block->map_pos.y + 16, stockpile->z); + current = 0; + } else { + // All items in all blocks have been checked. + block = NULL; + item = NULL; + return *this; + } + } + + // If the current item isn't properly stored, move on to the next. + item = df::item::find(block->items[current]); + if (!item->flags.bits.on_ground) { + continue; + } + + if (!Buildings::containsTile(stockpile, item->pos, false)) { + continue; + } + + // Ignore empty bins, barrels, and wheelbarrows assigned here. + if (item->isAssignedToThisStockpile(stockpile->id)) { + auto ref = Items::getGeneralRef(item, df::general_ref_type::CONTAINS_ITEM); + if (!ref) continue; + } + + // Found a valid item; yield it. + break; + } + + return *this; +} + diff --git a/library/modules/Burrows.cpp b/library/modules/Burrows.cpp index 48a2ca3a8..f8fbbb23f 100644 --- a/library/modules/Burrows.cpp +++ b/library/modules/Burrows.cpp @@ -29,20 +29,21 @@ distribution. #include using namespace std; -#include "Error.h" #include "Core.h" +#include "DataDefs.h" +#include "Error.h" +#include "MiscUtils.h" #include "modules/Burrows.h" #include "modules/Maps.h" #include "modules/Units.h" -#include "MiscUtils.h" - -#include "DataDefs.h" -#include "df/ui.h" -#include "df/burrow.h" #include "df/block_burrow.h" #include "df/block_burrow_link.h" +#include "df/burrow.h" +#include "df/map_block.h" +#include "df/ui.h" +#include "df/world.h" using namespace DFHack; using namespace df::enums; diff --git a/library/modules/Constructions.cpp b/library/modules/Constructions.cpp index 98410c331..9cec2eab9 100644 --- a/library/modules/Constructions.cpp +++ b/library/modules/Constructions.cpp @@ -31,21 +31,21 @@ distribution. using namespace std; -#include "VersionInfo.h" +#include "Core.h" #include "MemAccess.h" +#include "TileTypes.h" #include "Types.h" -#include "Core.h" +#include "VersionInfo.h" -#include "modules/Constructions.h" #include "modules/Buildings.h" +#include "modules/Constructions.h" #include "modules/Maps.h" -#include "TileTypes.h" - -#include "df/world.h" -#include "df/job_item.h" -#include "df/building_type.h" #include "df/building_constructionst.h" +#include "df/building_type.h" +#include "df/job_item.h" +#include "df/map_block.h" +#include "df/world.h" using namespace DFHack; using namespace df::enums; diff --git a/library/modules/MapCache.cpp b/library/modules/MapCache.cpp index 2ebfd9644..fb4aef935 100644 --- a/library/modules/MapCache.cpp +++ b/library/modules/MapCache.cpp @@ -33,39 +33,41 @@ distribution. #include using namespace std; -#include "modules/Maps.h" -#include "modules/MapCache.h" #include "ColorText.h" +#include "Core.h" +#include "DataDefs.h" #include "Error.h" -#include "VersionInfo.h" #include "MemAccess.h" -#include "ModuleFactory.h" -#include "Core.h" #include "MiscUtils.h" +#include "ModuleFactory.h" +#include "VersionInfo.h" #include "modules/Buildings.h" +#include "modules/MapCache.h" +#include "modules/Maps.h" #include "modules/Materials.h" -#include "DataDefs.h" -#include "df/world_data.h" -#include "df/world_underground_region.h" -#include "df/world_geo_biome.h" -#include "df/world_geo_layer.h" -#include "df/feature_init.h" -#include "df/world_data.h" -#include "df/burrow.h" #include "df/block_burrow.h" #include "df/block_burrow_link.h" -#include "df/world_region_details.h" -#include "df/builtin_mats.h" #include "df/block_square_event_grassst.h" -#include "df/z_level_flags.h" -#include "df/region_map_entry.h" +#include "df/block_square_event_frozen_liquidst.h" +#include "df/building_type.h" +#include "df/builtin_mats.h" +#include "df/burrow.h" +#include "df/feature_init.h" #include "df/flow_info.h" #include "df/plant.h" #include "df/plant_tree_info.h" #include "df/plant_tree_tile.h" -#include "df/building_type.h" +#include "df/region_map_entry.h" +#include "df/world.h" +#include "df/world_data.h" +#include "df/world_data.h" +#include "df/world_geo_biome.h" +#include "df/world_geo_layer.h" +#include "df/world_region_details.h" +#include "df/world_underground_region.h" +#include "df/z_level_flags.h" using namespace DFHack; using namespace MapExtras; diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index 1114107ec..e56ae3109 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -33,36 +33,37 @@ distribution. #include using namespace std; -#include "modules/Maps.h" -#include "modules/MapCache.h" #include "ColorText.h" +#include "Core.h" +#include "DataDefs.h" #include "Error.h" -#include "VersionInfo.h" #include "MemAccess.h" -#include "ModuleFactory.h" -#include "Core.h" #include "MiscUtils.h" +#include "ModuleFactory.h" +#include "VersionInfo.h" #include "modules/Buildings.h" +#include "modules/MapCache.h" +#include "modules/Maps.h" -#include "DataDefs.h" -#include "df/world_data.h" -#include "df/world_underground_region.h" -#include "df/world_geo_biome.h" -#include "df/world_geo_layer.h" -#include "df/feature_init.h" -#include "df/world_data.h" -#include "df/burrow.h" #include "df/block_burrow.h" #include "df/block_burrow_link.h" -#include "df/world_region_details.h" -#include "df/builtin_mats.h" #include "df/block_square_event_grassst.h" -#include "df/z_level_flags.h" -#include "df/region_map_entry.h" -#include "df/flow_info.h" #include "df/building_type.h" +#include "df/builtin_mats.h" +#include "df/burrow.h" +#include "df/feature_init.h" +#include "df/flow_info.h" #include "df/plant.h" +#include "df/region_map_entry.h" +#include "df/world.h" +#include "df/world_data.h" +#include "df/world_data.h" +#include "df/world_geo_biome.h" +#include "df/world_geo_layer.h" +#include "df/world_region_details.h" +#include "df/world_underground_region.h" +#include "df/z_level_flags.h" using namespace DFHack; using namespace df::enums; diff --git a/plugins/changelayer.cpp b/plugins/changelayer.cpp index 64e932609..27e4c12e6 100644 --- a/plugins/changelayer.cpp +++ b/plugins/changelayer.cpp @@ -1,25 +1,24 @@ // changelayer plugin // allows changing the material type of geological layers -// some headers required for a plugin. Nothing special, just the basics. +#include "Console.h" #include "Core.h" -#include -#include -#include - -// DF data structure definition headers #include "DataDefs.h" +#include "Export.h" +#include "PluginManager.h" +#include "TileTypes.h" + +#include "modules/Gui.h" +#include "modules/MapCache.h" #include "modules/Maps.h" #include "modules/Materials.h" -#include "modules/MapCache.h" -#include "modules/Gui.h" - -#include "TileTypes.h" +// DF data structure definition headers +#include "df/region_map_entry.h" +#include "df/world.h" #include "df/world_data.h" #include "df/world_geo_biome.h" #include "df/world_geo_layer.h" -#include "df/region_map_entry.h" using namespace DFHack; using namespace df::enums; @@ -394,4 +393,4 @@ bool conversionAllowed(color_ostream &out, MaterialInfo mat_new, MaterialInfo ma warned = true; } return allowed; -} \ No newline at end of file +} diff --git a/plugins/changevein.cpp b/plugins/changevein.cpp index 9c17af292..8612603fc 100644 --- a/plugins/changevein.cpp +++ b/plugins/changevein.cpp @@ -10,6 +10,10 @@ #include "modules/Materials.h" #include "TileTypes.h" +#include "df/block_square_event.h" +#include "df/block_square_event_mineralst.h" +#include "df/map_block.h" + using std::vector; using std::string; using namespace DFHack; diff --git a/plugins/cleaners.cpp b/plugins/cleaners.cpp index 3bc15e343..24694c6a2 100644 --- a/plugins/cleaners.cpp +++ b/plugins/cleaners.cpp @@ -1,17 +1,22 @@ #include "Core.h" #include "Console.h" +#include "DataDefs.h" #include "Export.h" #include "PluginManager.h" + #include "modules/Maps.h" -#include "DataDefs.h" +#include "df/block_square_event.h" +#include "df/block_square_event_material_spatterst.h" +#include "df/builtin_mats.h" +#include "df/global_objects.h" #include "df/item_actual.h" -#include "df/unit.h" -#include "df/spatter.h" +#include "df/map_block.h" #include "df/matter_state.h" -#include "df/global_objects.h" -#include "df/builtin_mats.h" #include "df/plant.h" +#include "df/spatter.h" +#include "df/unit.h" +#include "df/world.h" using std::vector; using std::string; diff --git a/plugins/deramp.cpp b/plugins/deramp.cpp index f0171dabc..fd7ceb3d7 100644 --- a/plugins/deramp.cpp +++ b/plugins/deramp.cpp @@ -9,6 +9,9 @@ #include "modules/Maps.h" #include "TileTypes.h" +#include "df/map_block.h" +#include "df/world.h" + using std::vector; using std::string; using namespace DFHack; diff --git a/plugins/devel/frozen.cpp b/plugins/devel/frozen.cpp index 338cc37e8..ed5192073 100644 --- a/plugins/devel/frozen.cpp +++ b/plugins/devel/frozen.cpp @@ -1,11 +1,15 @@ #include "Core.h" #include "Console.h" +#include "DataDefs.h" #include "Export.h" #include "PluginManager.h" -#include "DataDefs.h" #include "modules/Maps.h" +#include "df/block_square_event_frozen_liquidst.h" +#include "df/map_block.h" +#include "df/world.h" + using std::vector; using std::string; using namespace DFHack; diff --git a/plugins/devel/kittens.cpp b/plugins/devel/kittens.cpp index 6317a0a39..77da0851e 100644 --- a/plugins/devel/kittens.cpp +++ b/plugins/devel/kittens.cpp @@ -1,16 +1,19 @@ -#include "Core.h" +#include +#include + #include "Console.h" +#include "Core.h" #include "Export.h" -#include "PluginManager.h" #include "MiscUtils.h" -#include -#include -#include "modules/Maps.h" +#include "PluginManager.h" + +#include "modules/Gui.h" #include "modules/Items.h" -#include -#include -#include -#include +#include "modules/Maps.h" + +#include "df/caste_raw.h" +#include "df/creature_raw.h" +#include "df/world.h" using std::vector; using std::string; diff --git a/plugins/devel/tilesieve.cpp b/plugins/devel/tilesieve.cpp index 5c82eabe0..4cef423f6 100644 --- a/plugins/devel/tilesieve.cpp +++ b/plugins/devel/tilesieve.cpp @@ -9,6 +9,7 @@ // DF data structure definition headers #include "DataDefs.h" #include "modules/Maps.h" +#include "df/map_block.h" #include "df/world.h" #include "TileTypes.h" diff --git a/plugins/fixveins.cpp b/plugins/fixveins.cpp index 5f612c9ad..88eeb3b61 100644 --- a/plugins/fixveins.cpp +++ b/plugins/fixveins.cpp @@ -14,6 +14,11 @@ #include "modules/Maps.h" #include "TileTypes.h" +#include "df/block_square_event.h" +#include "df/block_square_event_mineralst.h" +#include "df/map_block.h" +#include "df/world.h" + using std::vector; using std::string; using namespace DFHack; diff --git a/plugins/follow.cpp b/plugins/follow.cpp index 7b8ad3906..7a17f89d0 100644 --- a/plugins/follow.cpp +++ b/plugins/follow.cpp @@ -1,17 +1,19 @@ // Make the camera follow the selected unit +#include "Console.h" #include "Core.h" -#include -#include -#include - -#include "DFHack.h" #include "DataDefs.h" +#include "DFHack.h" +#include "Export.h" +#include "PluginManager.h" + #include "modules/Gui.h" -#include "modules/World.h" #include "modules/Maps.h" -#include -#include +#include "modules/World.h" + +#include "df/creature_raw.h" +#include "df/unit.h" +#include "df/world.h" using namespace DFHack; using namespace df::enums; diff --git a/plugins/lair.cpp b/plugins/lair.cpp index 96a178485..6fb167988 100644 --- a/plugins/lair.cpp +++ b/plugins/lair.cpp @@ -10,6 +10,9 @@ #include "modules/World.h" #include "modules/MapCache.h" #include "modules/Gui.h" + +#include "df/world.h" + using namespace DFHack; using namespace df::enums; diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp index 1953728a4..5b97f9ea2 100644 --- a/plugins/liquids.cpp +++ b/plugins/liquids.cpp @@ -20,29 +20,34 @@ // - grab the code from digcircle to get a circle brush - could be nice when painting with obsidian // - maybe store the last parameters in a file to make them persistent after dfhack is closed? +#include #include -#include -#include #include +#include #include -#include #include -#include +#include +#include using std::vector; using std::string; using std::endl; using std::set; -#include "Core.h" #include "Console.h" +#include "Core.h" #include "Export.h" +#include "LuaTools.h" #include "PluginManager.h" -#include "modules/Maps.h" -#include "modules/Gui.h" #include "TileTypes.h" + +#include "modules/Gui.h" #include "modules/MapCache.h" -#include "LuaTools.h" +#include "modules/Maps.h" + +#include "df/world.h" + #include "Brushes.h" + using namespace MapExtras; using namespace DFHack; using namespace df::enums; diff --git a/plugins/plants.cpp b/plugins/plants.cpp index 5d84ca96e..a15377279 100644 --- a/plugins/plants.cpp +++ b/plugins/plants.cpp @@ -13,7 +13,9 @@ #include "modules/Gui.h" #include "TileTypes.h" #include "modules/MapCache.h" + #include "df/plant.h" +#include "df/world.h" using std::vector; using std::string; diff --git a/plugins/power-meter.cpp b/plugins/power-meter.cpp index 039b133f2..c61c3c8ee 100644 --- a/plugins/power-meter.cpp +++ b/plugins/power-meter.cpp @@ -1,13 +1,3 @@ -#include "Core.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -15,22 +5,34 @@ #include #include -#include -#include "df/graphic.h" +#include "Console.h" +#include "Core.h" +#include "Error.h" +#include "Export.h" +#include "MiscUtils.h" +#include "PluginManager.h" +#include "TileTypes.h" +#include "VTableInterpose.h" + +#include "modules/Gui.h" +#include "modules/Maps.h" +#include "modules/Screen.h" +#include "modules/World.h" + +#include "df/building_drawbuffer.h" #include "df/building_trapst.h" -#include "df/builtin_mats.h" -#include "df/world.h" #include "df/buildings_other_id.h" +#include "df/builtin_mats.h" +#include "df/flow_info.h" +#include "df/graphic.h" #include "df/machine.h" #include "df/machine_info.h" -#include "df/building_drawbuffer.h" +#include "df/report.h" +#include "df/tile_designation.h" #include "df/ui.h" -#include "df/viewscreen_dwarfmodest.h" #include "df/ui_build_selector.h" -#include "df/flow_info.h" -#include "df/report.h" - -#include "MiscUtils.h" +#include "df/viewscreen_dwarfmodest.h" +#include "df/world.h" using std::vector; using std::string; diff --git a/plugins/probe.cpp b/plugins/probe.cpp index b1302868d..94ebc1884 100644 --- a/plugins/probe.cpp +++ b/plugins/probe.cpp @@ -1,33 +1,37 @@ // Just show some position data -#include -#include #include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include using namespace std; -#include "Core.h" #include "Console.h" +#include "Core.h" #include "Export.h" +#include "MiscUtils.h" #include "PluginManager.h" -#include "modules/Units.h" -#include "df/unit_inventory_item.h" -#include "df/building_nest_boxst.h" -#include "modules/Maps.h" + +#include "modules/Buildings.h" #include "modules/Gui.h" -#include "modules/Materials.h" #include "modules/MapCache.h" -#include "modules/Buildings.h" -#include "MiscUtils.h" +#include "modules/Maps.h" +#include "modules/Materials.h" +#include "modules/Units.h" -#include "df/world.h" -#include "df/world_raws.h" +#include "df/block_square_event_grassst.h" +#include "df/block_square_event_world_constructionst.h" #include "df/building_def.h" +#include "df/building_nest_boxst.h" #include "df/region_map_entry.h" +#include "df/unit_inventory_item.h" +#include "df/world.h" +#include "df/world_data.h" +#include "df/world_raws.h" using std::vector; using std::string; @@ -303,7 +307,7 @@ command_result df_probe (color_ostream &out, vector & parameters) out << "salty" << endl; if(des.bits.water_stagnant) out << "stagnant" << endl; - + out.print("%-16s= %s\n", "dig", ENUM_KEY_STR(tile_dig_designation, des.bits.dig).c_str()); out.print("%-16s= %s\n", "traffic", ENUM_KEY_STR(tile_traffic, des.bits.traffic).c_str()); diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index e210b7d50..5edb8e248 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1,101 +1,96 @@ #define DF_VERSION 42004 +#include +#include +#include + // some headers required for a plugin. Nothing special, just the basics. +#include "Console.h" #include "Core.h" -#include -#include -#include +#include "DataDefs.h" +#include "Export.h" +#include "Hooks.h" +#include "MiscUtils.h" +#include "PluginManager.h" +#include "RemoteServer.h" +#include "TileTypes.h" + +#include "SDL_events.h" +#include "SDL_keyboard.h" + +//DFhack specific headers +#include "modules/Buildings.h" +#include "modules/Gui.h" +#include "modules/Items.h" +#include "modules/MapCache.h" +#include "modules/Maps.h" +#include "modules/Materials.h" +#include "modules/Translation.h" +#include "modules/Units.h" +#include "modules/World.h" // DF data structure definition headers -#include "DataDefs.h" -#include "df/world.h" -#include "df/ui.h" -#include "df/item.h" -#include "df/creature_raw.h" -#include "df/caste_raw.h" +#include "df/army.h" +#include "df/army_flags.h" +#include "df/body_appearance_modifier.h" +#include "df/body_part_layer_raw.h" #include "df/body_part_raw.h" +#include "df/bp_appearance_modifier.h" +#include "df/building_axle_horizontalst.h" +#include "df/building_bridgest.h" +#include "df/building_def_furnacest.h" +#include "df/building_def_workshopst.h" +#include "df/building_rollersst.h" +#include "df/building_screw_pumpst.h" +#include "df/building_siegeenginest.h" +#include "df/building_water_wheelst.h" +#include "df/building_wellst.h" +#include "df/building_windmillst.h" +#include "df/builtin_mats.h" +#include "df/caste_raw.h" +#include "df/caste_raw.h" +#include "df/color_modifier_raw.h" +#include "df/creature_raw.h" +#include "df/creature_raw.h" +#include "df/descriptor_color.h" +#include "df/descriptor_color.h" +#include "df/descriptor_pattern.h" +#include "df/descriptor_pattern.h" +#include "df/descriptor_shape.h" +#include "df/dfhack_material_category.h" +#include "df/enabler.h" +#include "df/graphic.h" #include "df/historical_figure.h" - +#include "df/item.h" +#include "df/itemdef.h" #include "df/job_item.h" #include "df/job_material_category.h" -#include "df/dfhack_material_category.h" -#include "df/matter_state.h" -#include "df/material_vec_ref.h" -#include "df/builtin_mats.h" #include "df/map_block_column.h" +#include "df/material_vec_ref.h" +#include "df/matter_state.h" +#include "df/mental_attribute_type.h" +#include "df/physical_attribute_type.h" #include "df/plant.h" #include "df/plant_raw_flags.h" +#include "df/region_map_entry.h" +#include "df/tissue.h" +#include "df/ui.h" +#include "df/unit.h" +#include "df/viewscreen_choose_start_sitest.h" +#include "df/world.h" +#include "df/world_data.h" +#include "df/world_region.h" +#include "df/world_region_details.h" + #if DF_VERSION > 40001 #include "df/plant_tree_info.h" #include "df/plant_tree_tile.h" #include "df/plant_growth.h" #include "df/plant_growth_print.h" #endif -#include "df/itemdef.h" -#include "df/building_def_workshopst.h" -#include "df/building_def_furnacest.h" -#include "df/building_wellst.h" -#include "df/building_water_wheelst.h" -#include "df/building_screw_pumpst.h" -#include "df/building_axle_horizontalst.h" -#include "df/building_windmillst.h" -#include "df/building_siegeenginest.h" -#include "df/building_rollersst.h" -#include "df/building_bridgest.h" - -#include "df/descriptor_color.h" -#include "df/descriptor_pattern.h" -#include "df/descriptor_shape.h" - -#include "df/physical_attribute_type.h" -#include "df/mental_attribute_type.h" -#include "df/color_modifier_raw.h" -#include "df/descriptor_color.h" -#include "df/descriptor_pattern.h" - -#include "df/region_map_entry.h" -#include "df/world_region_details.h" -#include "df/world_region.h" -#include "df/army.h" -#include "df/army_flags.h" - -#include "df/unit.h" -#include "df/creature_raw.h" -#include "df/caste_raw.h" -#include "df/tissue.h" - -#include "df/enabler.h" -#include "df/graphic.h" - -#include "df/viewscreen_choose_start_sitest.h" - -#include "df/bp_appearance_modifier.h" -#include "df/body_part_layer_raw.h" -#include "df/body_appearance_modifier.h" - -//DFhack specific headers -#include "modules/Maps.h" -#include "modules/MapCache.h" -#include "modules/Materials.h" -#include "modules/Gui.h" -#include "modules/Translation.h" -#include "modules/Items.h" -#include "modules/Buildings.h" -#include "modules/Units.h" -#include "modules/World.h" -#include "TileTypes.h" -#include "MiscUtils.h" -#include "Hooks.h" -#include "SDL_events.h" -#include "SDL_keyboard.h" - -#include -#include -#include #include "RemoteFortressReader.pb.h" -#include "RemoteServer.h" using namespace DFHack; using namespace df::enums; @@ -2301,7 +2296,7 @@ static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage if (!orig_part) continue; auto send_part = send_caste->add_body_parts(); - + send_part->set_token(orig_part->token); send_part->set_category(orig_part->category); send_part->set_parent(orig_part->con_part_id); @@ -2410,7 +2405,7 @@ static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage send_caste->set_description(orig_caste->description); send_caste->set_adult_size(orig_caste->misc.adult_size); } - + for (int j = 0; j < orig_creature->tissue.size(); j++) { auto orig_tissue = orig_creature->tissue[j]; diff --git a/plugins/rendermax/renderer_light.cpp b/plugins/rendermax/renderer_light.cpp index 716f3d0b6..48dcb8223 100644 --- a/plugins/rendermax/renderer_light.cpp +++ b/plugins/rendermax/renderer_light.cpp @@ -1,34 +1,33 @@ #include "renderer_light.hpp" #include -#include #include +#include +#include #include "tinythread.h" #include "LuaTools.h" #include "modules/Gui.h" -#include "modules/Screen.h" #include "modules/Maps.h" - +#include "modules/Screen.h" #include "modules/Units.h" -#include "df/graphic.h" -#include "df/viewscreen_dwarfmodest.h" -#include "df/viewscreen_dungeonmodest.h" -#include "df/flow_info.h" -#include "df/world.h" +#include "df/block_square_event_material_spatterst.h" #include "df/building.h" #include "df/building_doorst.h" #include "df/building_floodgatest.h" -#include "df/plant.h" -#include "df/plant_raw.h" +#include "df/flow_info.h" +#include "df/graphic.h" #include "df/item.h" #include "df/items_other_id.h" +#include "df/plant.h" +#include "df/plant_raw.h" #include "df/unit.h" - -#include +#include "df/viewscreen_dungeonmodest.h" +#include "df/viewscreen_dwarfmodest.h" +#include "df/world.h" using df::global::gps; using namespace DFHack; diff --git a/plugins/reveal.cpp b/plugins/reveal.cpp index 01c007d05..20b36467e 100644 --- a/plugins/reveal.cpp +++ b/plugins/reveal.cpp @@ -10,8 +10,11 @@ #include "modules/World.h" #include "modules/MapCache.h" #include "modules/Gui.h" -#include "df/construction.h" + #include "df/block_square_event_frozen_liquidst.h" +#include "df/construction.h" +#include "df/world.h" + using MapExtras::MapCache; using std::string; diff --git a/plugins/steam-engine.cpp b/plugins/steam-engine.cpp index cc9455914..fbc575e36 100644 --- a/plugins/steam-engine.cpp +++ b/plugins/steam-engine.cpp @@ -1,12 +1,3 @@ -#include "Core.h" -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -14,26 +5,37 @@ #include #include -#include -#include "df/graphic.h" -#include "df/building_workshopst.h" +#include "Console.h" +#include "Core.h" +#include "Export.h" +#include "MiscUtils.h" +#include "PluginManager.h" +#include "TileTypes.h" +#include "VTableInterpose.h" + +#include "modules/Gui.h" +#include "modules/Maps.h" +#include "modules/Screen.h" +#include "modules/World.h" + #include "df/building_def_workshopst.h" -#include "df/item_liquid_miscst.h" -#include "df/power_info.h" -#include "df/workshop_type.h" -#include "df/builtin_mats.h" -#include "df/world.h" +#include "df/building_drawbuffer.h" +#include "df/building_workshopst.h" #include "df/buildings_other_id.h" -#include "df/machine.h" +#include "df/builtin_mats.h" +#include "df/flow_info.h" +#include "df/graphic.h" +#include "df/item_liquid_miscst.h" #include "df/job.h" -#include "df/building_drawbuffer.h" +#include "df/machine.h" +#include "df/power_info.h" +#include "df/report.h" +#include "df/tile_designation.h" #include "df/ui.h" -#include "df/viewscreen_dwarfmodest.h" #include "df/ui_build_selector.h" -#include "df/flow_info.h" -#include "df/report.h" - -#include "MiscUtils.h" +#include "df/viewscreen_dwarfmodest.h" +#include "df/workshop_type.h" +#include "df/world.h" /* * This plugin implements a steam engine workshop. It activates diff --git a/plugins/tiletypes.cpp b/plugins/tiletypes.cpp index ae5362e15..76da1df3e 100644 --- a/plugins/tiletypes.cpp +++ b/plugins/tiletypes.cpp @@ -19,27 +19,33 @@ // Options (tiletypes-command): // (anything) - run the given command +#include #include -#include #include #include -#include #include +#include + using std::vector; using std::string; using std::endl; using std::set; -#include "Core.h" #include "Console.h" +#include "Core.h" #include "Export.h" #include "PluginManager.h" -#include "modules/Maps.h" -#include "modules/Gui.h" #include "TileTypes.h" + +#include "modules/Gui.h" #include "modules/MapCache.h" +#include "modules/Maps.h" + #include "df/tile_dig_designation.h" +#include "df/world.h" + #include "Brushes.h" + using namespace MapExtras; using namespace DFHack; using namespace df::enums; diff --git a/plugins/tubefill.cpp b/plugins/tubefill.cpp index 73c615c9b..1b77d466c 100644 --- a/plugins/tubefill.cpp +++ b/plugins/tubefill.cpp @@ -14,6 +14,8 @@ #include "TileTypes.h" #include "df/deep_vein_hollow.h" +#include "df/map_block.h" +#include "df/world.h" using namespace DFHack; using namespace df::enums; From de731b02994765e9fad7e236d44839c7d2dca0b7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 14 Aug 2016 12:41:09 -0400 Subject: [PATCH 106/413] Move save_dir back into cur_savegame and update submodules --- library/Core.cpp | 8 ++++---- library/RemoteTools.cpp | 2 +- library/modules/World.cpp | 2 +- library/xml | 2 +- plugins/isoworldremote.cpp | 4 ++-- plugins/remotefortressreader.cpp | 2 +- plugins/rendermax/renderer_light.cpp | 4 ++-- scripts | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 975290e52..fb1dd80bb 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2107,7 +2107,7 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve if (!df::global::world) return; - std::string rawFolder = "data/save/" + (df::global::world->save_dir) + "/raw/"; + std::string rawFolder = "data/save/" + (df::global::world->cur_savegame.save_dir) + "/raw/"; auto i = table.find(event); if ( i != table.end() ) { @@ -2167,9 +2167,9 @@ void Core::onStateChange(color_ostream &out, state_change_event event) case SC_WORLD_UNLOADED: case SC_MAP_LOADED: case SC_MAP_UNLOADED: - if (world && world->save_dir.size()) + if (world && world->cur_savegame.save_dir.size()) { - std::string save_dir = "data/save/" + world->save_dir; + std::string save_dir = "data/save/" + world->cur_savegame.save_dir; std::string evtlogpath = save_dir + "/events-dfhack.log"; std::ofstream evtlog; evtlog.open(evtlogpath, std::ios_base::app); // append @@ -2187,7 +2187,7 @@ void Core::onStateChange(color_ostream &out, state_change_event event) evtlog << timebuf; evtlog << "DFHack " << Version::git_description() << " on " << ostype << "; "; evtlog << "cwd md5: " << md5w.getHashFromString(getHackPath()).substr(0, 10) << "; "; - evtlog << "save: " << world->save_dir << "; "; + evtlog << "save: " << world->cur_savegame.save_dir << "; "; evtlog << sc_event_name(event) << "; "; if (gametype) evtlog << "game type " << ENUM_KEY_STR(game_type, *gametype) << " (" << *gametype << ")"; diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp index 909ad9133..77374ea0c 100644 --- a/library/RemoteTools.cpp +++ b/library/RemoteTools.cpp @@ -386,7 +386,7 @@ static command_result GetWorldInfo(color_ostream &stream, if (df::global::gametype) gt = *df::global::gametype; - out->set_save_dir(world->save_dir); + out->set_save_dir(world->cur_savegame.save_dir); if (world->world_data->name.has_name) describeName(out->mutable_world_name(), &world->world_data->name); diff --git a/library/modules/World.cpp b/library/modules/World.cpp index fcf516f4e..3be400515 100644 --- a/library/modules/World.cpp +++ b/library/modules/World.cpp @@ -151,7 +151,7 @@ void World::SetCurrentWeather(uint8_t weather) string World::ReadWorldFolder() { - return world->save_dir; + return world->cur_savegame.save_dir; } bool World::isFortressMode(df::game_type t) diff --git a/library/xml b/library/xml index d5036d833..a8b3349ee 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit d5036d8336d266bcb13e27e702a0acada01227a4 +Subproject commit a8b3349ee1e03cc979497eeb95e59f7f59552691 diff --git a/plugins/isoworldremote.cpp b/plugins/isoworldremote.cpp index bd3433b27..017fb45f6 100644 --- a/plugins/isoworldremote.cpp +++ b/plugins/isoworldremote.cpp @@ -198,7 +198,7 @@ static command_result GetEmbarkInfo(color_ostream &stream, const MapRequest *in, return CR_OK; } if (in->has_save_folder()) { //If no save folder is given, it means we don't care. - if (!(in->save_folder() == world->save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them. + if (!(in->save_folder() == world->cur_savegame.save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them. out->set_available(false); return CR_OK; } @@ -345,7 +345,7 @@ static command_result GetRawNames(color_ostream &stream, const MapRequest *in, R return CR_OK; } if (in->has_save_folder()) { //If no save folder is given, it means we don't care. - if (!(in->save_folder() == world->save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them. + if (!(in->save_folder() == world->cur_savegame.save_dir || in->save_folder() == "ANY")) { //isoworld has a different map loaded, don't bother trying to load tiles for it, we don't have them. out->set_available(false); return CR_OK; } diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 5edb8e248..8a2428adb 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1571,7 +1571,7 @@ static command_result GetMapInfo(color_ostream &stream, const EmptyMessage *in, out->set_block_pos_z(pos_z); out->set_world_name(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, false))); out->set_world_name_english(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, true))); - out->set_save_name(df::global::world->save_dir); + out->set_save_name(df::global::world->cur_savegame.save_dir); return CR_OK; } diff --git a/plugins/rendermax/renderer_light.cpp b/plugins/rendermax/renderer_light.cpp index 48dcb8223..f0f3c92cf 100644 --- a/plugins/rendermax/renderer_light.cpp +++ b/plugins/rendermax/renderer_light.cpp @@ -1171,9 +1171,9 @@ void lightingEngineViewscreen::defaultSettings() void lightingEngineViewscreen::loadSettings() { std::string rawFolder; - if(df::global::world->save_dir!="") + if(df::global::world->cur_savegame.save_dir!="") { - rawFolder= "data/save/" + (df::global::world->save_dir) + "/raw/"; + rawFolder= "data/save/" + (df::global::world->cur_savegame.save_dir) + "/raw/"; } else { diff --git a/scripts b/scripts index 274e7c372..955db4654 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 274e7c372c83611d8fad53345a0cb9ad2a1f10df +Subproject commit 955db46549779a411da563252dc98c4c242de489 From c2997b9c79bdff4c7a0dcc2f9c10da2c0f92a1c3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Aug 2016 15:47:40 -0400 Subject: [PATCH 107/413] Fix save_dir --- library/lua/dfhack.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index f535d25ad..900607c08 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -606,7 +606,7 @@ end function dfhack.getSavePath() if dfhack.isWorldLoaded() then - return dfhack.getDFPath() .. '/data/save/' .. df.global.world.save_dir + return dfhack.getDFPath() .. '/data/save/' .. df.global.world.cur_savegame.save_dir end end From 0b6597ddb21c8b75fdbef476cd26dc94706afe9a Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Aug 2016 15:59:46 -0400 Subject: [PATCH 108/413] Stop field_offset from crashing due to missing vtables Now, a pointer to NULL is cast to the type in question, avoiding the need to call new() or delete() with potentially-misaligned types. Also, virtual_identity::find has been tweaked to prevent it from crashing on NULL vtable pointers. This was suggested by Angavrilov. --- library/DataDefs.cpp | 3 +++ library/lua/memscan.lua | 14 ++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index be381d860..06f1ac6c9 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -255,6 +255,9 @@ virtual_identity *virtual_identity::get(virtual_ptr instance_ptr) virtual_identity *virtual_identity::find(void *vtable) { + if (!vtable) + return NULL; + // Actually, a reader/writer lock would be sufficient, // since the table is only written once per class. tthread::lock_guard lock(*known_mutex); diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua index 534830724..e24d8a8c9 100644 --- a/library/lua/memscan.lua +++ b/library/lua/memscan.lua @@ -307,14 +307,12 @@ function field_ref(handle,...) end function field_offset(type,...) - local handle = df.new(type) - local _,haddr = df.sizeof(handle) - local _,addr = df.sizeof(field_ref(handle,...)) - -- to aid in diagnosis of bad virtual dtors - io.stderr:write('memscan: deleting instance of '..tostring(type) .. '\n'):flush() - df.delete(handle) - io.stderr:write('successfully deleted\n'):flush() - return addr-haddr + local tmp = df.new('intptr_t') -- pointer to nullptr + local _, haddr = df.sizeof(tmp) + local handle = df.reinterpret_cast(type, tmp) + local _, addr = df.sizeof(field_ref(handle,...)) + df.delete(tmp) + return addr - haddr end function MemoryArea:object_by_field(addr,type,...) From 9e4a6d75911334996eaf6b412cde60a13e8f1fd6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Aug 2016 17:28:18 -0400 Subject: [PATCH 109/413] Update default base address on 64-bit Linux --- library/include/Memory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/include/Memory.h b/library/include/Memory.h index 33d40c3cc..0f465c834 100644 --- a/library/include/Memory.h +++ b/library/include/Memory.h @@ -13,7 +13,7 @@ #endif #elif defined(_LINUX) #ifdef DFHACK64 - #define DEFAULT_BASE_ADDR 0x8048000 + #define DEFAULT_BASE_ADDR 0x400000 #else #define DEFAULT_BASE_ADDR 0x8048000 #endif From 98a187ca43133a21ea05bc91526356424ed6c3d4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Aug 2016 17:28:44 -0400 Subject: [PATCH 110/413] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index a8b3349ee..87aa5e2ea 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit a8b3349ee1e03cc979497eeb95e59f7f59552691 +Subproject commit 87aa5e2ea8c1153b2b12b3189fe5a593f52de792 From 9171149afbb79e50b5721a19024f4bad7b03a96b Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Aug 2016 23:42:17 -0400 Subject: [PATCH 111/413] Update submodule refs --- plugins/stonesense | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/stonesense b/plugins/stonesense index 9270ceb54..5db5f9151 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 9270ceb5463657a6d039bdc3389fe69c78a0784b +Subproject commit 5db5f9151d4140b53169fcb7bed3383991b33326 diff --git a/scripts b/scripts index 955db4654..8b532b757 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 955db46549779a411da563252dc98c4c242de489 +Subproject commit 8b532b757600d63855f9babee4c1c32af5e2d496 From 70ac99cbfa7cd9e8c65db10d82a1e007d7e39892 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 21 Aug 2016 20:58:40 -0400 Subject: [PATCH 112/413] Fix Buildings::setOwner() persistence Needed to set bld->owner_id for changes to persist across save/load Fixes #983, thanks to Quietust --- NEWS.rst | 4 ++++ library/modules/Buildings.cpp | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 97daeee32..0715ccae4 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -41,6 +41,10 @@ New Scripts ----------- - `load-save`: loads a save non-interactively +Fixes +----- +- Buildings::setOwner() changes now persist properly when saved + DFHack 0.43.03-r1 ================= diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index b7933f6ef..9d672cd58 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -239,6 +239,7 @@ bool Buildings::setOwner(df::building *bld, df::unit *unit) if (unit) { + bld->owner_id = unit->id; unit->owned_buildings.push_back(bld); if (auto spouse = df::unit::find(unit->relationship_ids[df::unit_relationship_type::Spouse])) @@ -248,6 +249,10 @@ bool Buildings::setOwner(df::building *bld, df::unit *unit) blist.push_back(bld); } } + else + { + bld->owner_id = -1; + } return true; } From e983e66a1ae2061e26b0cf59793a9f7907237224 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 21 Aug 2016 20:59:24 -0400 Subject: [PATCH 113/413] Update xml and scripts --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 87aa5e2ea..bb582c8b5 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 87aa5e2ea8c1153b2b12b3189fe5a593f52de792 +Subproject commit bb582c8b51fddfa9d8c83a3e8d27c205b587180c diff --git a/scripts b/scripts index 8b532b757..042fcffd0 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 8b532b757600d63855f9babee4c1c32af5e2d496 +Subproject commit 042fcffd051c1f1ceab268e54bed1ed197b1f91e From 93ac937cb9b53f7c89587bb6e06f29beba212f33 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 21 Aug 2016 22:24:41 -0400 Subject: [PATCH 114/413] Add new job types to autohauler --- plugins/autohauler.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/autohauler.cpp b/plugins/autohauler.cpp index d7b233195..7a3f8a3d8 100644 --- a/plugins/autohauler.cpp +++ b/plugins/autohauler.cpp @@ -397,7 +397,15 @@ static const dwarf_state dwarf_states[] = { BUSY /* PushTrackVehicle */, BUSY /* PlaceTrackVehicle */, BUSY /* StoreItemInVehicle */, - BUSY /* GeldAnimal */ + BUSY /* GeldAnimal */, + BUSY /* MakeFigurine */, + BUSY /* MakeAmulet */, + BUSY /* MakeScepter */, + BUSY /* MakeCrown */, + BUSY /* MakeRing */, + BUSY /* MakeEarring */, + BUSY /* MakeBracelet */, + BUSY /* MakeGem */ }; // Mode assigned to labors. Either it's a hauling job, or it's not. From 3d2f7d426d00628b684a975b0ba5fc7e63591241 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Mon, 1 Aug 2016 15:48:21 +1000 Subject: [PATCH 115/413] Update the example init file After updating the extra init file in my pack, I realised that many of the changes could be merged into the standard init. This enables a few more UI improvements, adds neglected keybindings, and removes the roses-init and binpatches sections (third-party only and obsolete respectively). --- dfhack.init-example | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/dfhack.init-example b/dfhack.init-example index 4d2a1b2f3..f8cadb215 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -48,6 +48,10 @@ keybinding add Ctrl-F@dwarfmode/Default "dwarfmonitor stats" # export a Dwarf's preferences screen in BBCode to post to a forum keybinding add Ctrl-Shift-F@dwarfmode forum-dwarves +# an in-game init file editor +keybinding add Alt-S@title gui/settings-manager +keybinding add Alt-S@dwarfmode/Default gui/settings-manager + ############################## # Generic adv mode bindings # ############################## @@ -177,6 +181,7 @@ tweak import-priority-category # Misc. UI tweaks tweak block-labors # Prevents labors that can't be used from being toggled tweak civ-view-agreement +tweak eggs-fertile tweak fps-min tweak hide-priority tweak kitchen-keys @@ -223,7 +228,7 @@ enable \ # You can comment out the extension of a line. # enable mouse controls and sand indicator in embark screen -embark-tools enable sand mouse +embark-tools enable sticky sand mouse ########### # Scripts # @@ -232,14 +237,11 @@ embark-tools enable sand mouse # write extra information to the gamelog modtools/extra-gamelog enable +# extended status screen (bedrooms page) +enable gui/extended-status + # add information to item viewscreens view-item-info enable +# a replacement for the "load game" screen gui/load-screen enable - -#roses-init must be called on world load if you are using his persist-delay, class system, etc -#base/roses-init -all - -####################################################### -# Apply binary patches at runtime # -####################################################### From 1dab45ffeda58fe7a47b387caabbc7d53a5daa27 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 22 Aug 2016 23:18:08 -0400 Subject: [PATCH 116/413] Replace lua_pushnumber with lua_pushinteger in LuaApi.cpp --- library/LuaApi.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 997d57a38..18b4ab270 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2347,7 +2347,7 @@ static int internal_getAddress(lua_State *L) const char *name = luaL_checkstring(L, 1); uintptr_t addr = Core::getInstance().vinfo->getAddress(name); if (addr) - lua_pushnumber(L, addr); + lua_pushinteger(L, addr); else lua_pushnil(L); return 1; @@ -2413,9 +2413,9 @@ static int internal_getMemRanges(lua_State *L) for(size_t i = 0; i < ranges.size(); i++) { lua_newtable(L); - lua_pushnumber(L, (uintptr_t)ranges[i].start); + lua_pushinteger(L, (uintptr_t)ranges[i].start); lua_setfield(L, -2, "start_addr"); - lua_pushnumber(L, (uintptr_t)ranges[i].end); + lua_pushinteger(L, (uintptr_t)ranges[i].end); lua_setfield(L, -2, "end_addr"); lua_pushstring(L, ranges[i].name); lua_setfield(L, -2, "name"); From 2dccd1d0ffb7f87a92a326e6a0a34768d7697864 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 22 Aug 2016 23:18:30 -0400 Subject: [PATCH 117/413] Add CheckedArray:__tostring() method --- library/lua/memscan.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua index e24d8a8c9..78a9e7b8c 100644 --- a/library/lua/memscan.lua +++ b/library/lua/memscan.lua @@ -39,6 +39,9 @@ function CheckedArray:__newindex(idx, val) end self.data[idx] = val end +function CheckedArray:__tostring() + return (''):format(self.type, self.count) +end function CheckedArray:addr2idx(addr, round) local off = addr - self.start if off >= 0 and off < self.size and (round or (off % self.esize) == 0) then From f4b0c2fcfc0570569569c57f0f83e7c69df23ce1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 22 Aug 2016 23:18:58 -0400 Subject: [PATCH 118/413] color-dfhack-text: Fix potential overflow issue --- plugins/devel/color-dfhack-text.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/devel/color-dfhack-text.cpp b/plugins/devel/color-dfhack-text.cpp index eb5e9c659..d0db8e710 100644 --- a/plugins/devel/color-dfhack-text.cpp +++ b/plugins/devel/color-dfhack-text.cpp @@ -16,7 +16,7 @@ REQUIRE_GLOBAL(gps); struct { bool flicker; uint8_t color; - short tick; + uint8_t tick; } config; void color_text_tile(const Screen::Pen &pen, int x, int y, bool map); From 7097b1f8177061ae666eec201b38471cb6860a77 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 23 Aug 2016 14:34:33 -0400 Subject: [PATCH 119/413] Add TC01, Qartar, milochristiansen to Authors.rst --- docs/Authors.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index accaaa630..8592dac0e 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -19,7 +19,9 @@ Anuradha Dissanayake falconne AtomicChicken AtomicChicken belal jimhester Ben Lubar BenLubar +Ben Rosser TC01 Caldfir caldfir +Carter Bray Qartar Chris Dombroski cdombroski Clayton Hughes David Corbett dscorbett @@ -62,6 +64,7 @@ Michon van Dooren MaienM miffedmap miffedmap Mike Stewart thewonderidiot Mikko Juola Noeda Adeon +Milo Christiansen milochristiansen MithrilTuxedo MithrilTuxedo mizipzor mizipzor moversti moversti From 30601dc3fd6535a58abe33b2bf2643cf981f4079 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 23 Aug 2016 15:43:32 -0400 Subject: [PATCH 120/413] Update Compile.rst for GCC 4.8 and x64 changes, and general cleanup Closes #980 --- docs/Compile.rst | 162 ++++++++++++++++++++++++++++------------------- 1 file changed, 97 insertions(+), 65 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 650abbfca..b693f4cc3 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -90,31 +90,15 @@ Dependencies DFHack is meant to be installed into an existing DF folder, so get one ready. We assume that any Linux platform will have ``git`` available (though it may -require installing from your package manager.) +need to be installed with your package manager.) -To build DFHack you need GCC version 4.5 or later, capable of compiling for 32-bit -(i386) targets. GCC 4.5 is easiest to work with due to avoiding libstdc++ issues -(see below), but any version from 4.5 onwards (including 5.x) will work. +To build DFHack you need GCC version 4.8 or later. GCC 4.8 is easiest to work +with due to avoiding libstdc++ issues (see below), but any version from 4.8 +onwards (including 5.x) will work. -On 64-bit distributions, you'll need the multilib development tools and libraries: - -* ``gcc-multilib`` and ``g++-multilib`` -* If you have installed a non-default version of GCC - for example, GCC 4.5 on a - distribution that defaults to 5.x - you may need to add the version number to - the multilib packages. - - * For example, ``gcc-4.5-multilib`` and ``g++-4.5-multilib`` if installing for GCC 4.5 - on a system that uses a later GCC version. - * This is definitely required on Ubuntu/Debian, check if using a different distribution. - -Note that installing a 32-bit GCC on 64-bit systems (e.g. ``gcc:i386`` on Debian) will -typically *not* work, as it depends on several other 32-bit libraries that -conflict with system libraries. Alternatively, you might be able to use ``lxc`` -to -:forums:`create a virtual 32-bit environment <139553.msg5435310#msg5435310>`. - -Before you can build anything, you'll also need ``cmake``. It is advisable to also get -``ccmake`` on distributions that split the cmake package into multiple parts. +Before you can build anything, you'll also need ``cmake``. It is advisable to +also get ``ccmake`` on distributions that split the cmake package into multiple +parts. You also need perl and the XML::LibXML and XML::LibXSLT perl packages (for the code generation parts). You should be able to find them in your distro repositories. @@ -127,16 +111,34 @@ Here are some package install commands for various platforms: * For the required Perl modules: ``perl-xml-libxml`` and ``perl-xml-libxslt`` (or through ``cpan``) -* On 64-bit Ubuntu:: +* On Ubuntu:: - apt-get install gcc cmake git gcc-multilib g++-multilib zlib1g-dev:i386 libxml-libxml-perl libxml-libxslt-perl + apt-get install gcc cmake git zlib1g-dev libxml-libxml-perl libxml-libxslt-perl -* On 32-bit Ubuntu:: +* Debian and derived distros should have similar requirements to Ubuntu. - apt-get install gcc cmake git gcc-multilib g++-multilib zlib1g-dev libxml-libxml-perl libxml-libxslt-perl -* Debian and derived distros should have similar requirements to Ubuntu. +Multilib dependencies +--------------------- +If you want to compile 32-bit DFHack on 64-bit distributions, you'll need the +multilib development tools and libraries: + +* ``gcc-multilib`` and ``g++-multilib`` +* If you have installed a non-default version of GCC - for example, GCC 4.8 on a + distribution that defaults to 5.x - you may need to add the version number to + the multilib packages. + + * For example, ``gcc-4.8-multilib`` and ``g++-4.8-multilib`` if installing for GCC 4.8 + on a system that uses a later GCC version. + * This is definitely required on Ubuntu/Debian, check if using a different distribution. +* ``zlib1g-dev:i386`` (or a similar i386 zlib-dev package) + +Note that installing a 32-bit GCC on 64-bit systems (e.g. ``gcc:i386`` on +Debian) will typically *not* work, as it depends on several other 32-bit +libraries that conflict with system libraries. Alternatively, you might be able +to use ``lxc`` to +:forums:`create a virtual 32-bit environment <139553.msg5435310#msg5435310>`. Build ----- @@ -163,15 +165,16 @@ or the cmake-gui program. Incompatible libstdc++ ~~~~~~~~~~~~~~~~~~~~~~ -When compiling dfhack yourself, it builds against your system libstdc++. -When Dwarf Fortress runs, it uses a libstdc++ shipped with the binary, which -comes from GCC 4.5 and is incompatible with code compiled with newer GCC versions. -This manifests itself with an error message such as:: +When compiling dfhack yourself, it builds against your system libstdc++. When +Dwarf Fortress runs, it uses a libstdc++ shipped with the binary, which comes +from GCC 4.8 and is incompatible with code compiled with newer GCC versions. If +you compile DFHack with a GCC version newer than 4.8, you will see an error +message such as:: ./libs/Dwarf_Fortress: /pathToDF/libs/libstdc++.so.6: version - `GLIBCXX_3.4.15' not found (required by ./hack/libdfhack.so) + `GLIBCXX_3.4.18' not found (required by ./hack/libdfhack.so) -To fix this you can compile with GCC 4.5 or remove the libstdc++ shipped with +To fix this you can compile with GCC 4.8 or remove the libstdc++ shipped with DF, which causes DF to use your system libstdc++ instead:: cd /path/to/DF/ @@ -180,9 +183,9 @@ DF, which causes DF to use your system libstdc++ instead:: Note that distributing binaries compiled with newer GCC versions requires end- users to delete libstdc++ themselves and have a libstdc++ on their system from the same GCC version or newer. For this reason, distributing anything compiled -with GCC versions newer than 4.5 is discouraged. In the future we may start +with GCC versions newer than 4.8 is discouraged. In the future we may start bundling a later libstdc++ as part of the DFHack package, so as to enable -compilation-for-distribution with a GCC newer than 4.5. +compilation-for-distribution with a GCC newer than 4.8. Mac OS X ======== @@ -190,38 +193,67 @@ DFHack functions similarly on OS X and Linux, and the majority of the information above regarding the build process (cmake and make) applies here as well. +DFHack can officially be built on OS X with anything from GCC 4.5 to 4.8, so 4.8 +is recommended, as 4.5 has issues on newer systems, but 4.5-4.7 should also +work. Anything newer than 4.8 will require you to perform extra steps to get +DFHack to run (see `osx-new-gcc-notes`), and your build will likely not be +redistributable. + +.. _osx-new-gcc-notes: + +Notes for GCC 4.9+, OS X 10.10+, or XCode 7 users +------------------------------------------------- + +If none of these situations apply to you, skip to `osx-setup`. + If you have issues building on OS X 10.10 (Yosemite) or above, try definining the following environment variable:: export MACOSX_DEPLOYMENT_TARGET=10.9 -Note for El Capitan (OSX 10.11) and XCode 7.x users ---------------------------------------------------- -* You will probably find when following the instructions below that GCC 4.5 will - fail to install on OSX 10.11, or any older OSX that is using XCode 7. -* There are two workarounds: +If you try to build with GCC 4.5, you will probably find that GCC 4.5 will fail +to install on OS X 10.11 and newer, or any older OS X that is using XCode 7 or +newer. There are two workarounds: + +* Install a newer version of GCC instead (e.g. ``brew install gcc48`` or ``brew + install gcc5``) and follow the instructions for linking libstdc++ below. - * Install GCC 5.x instead (``brew install gcc5``), and then after compile - replace ``hack/libstdc++.6.dylib`` with a symlink to GCC 5's i386 - version of this file:: +* Install XCode 6, which is available as a free download from the Apple + Developer Center. - cd /hack && mv libstdc++.6.dylib libstdc++.6.dylib.orig && - ln -s /usr/local/Cellar/gcc5/5.2.0/lib/gcc/5/i386/libstdc++.6.dylib . + * Either install this as your only XCode, or install it additionally + to XCode 7 and then switch between them using ``xcode-select`` + * Ensure XCode 6 is active before attempting to install GCC 4.5 and + whenever you are compiling DFHack with GCC 4.5. - * Install XCode 6, which is available as a free download from the Apple - Developer Center. - * Either install this as your only XCode, or install it additionally - to XCode 7 and then switch between them using ``xcode-select`` - * Ensure XCode 6 is active before attempting to install GCC 4.5 and - whenever you are compiling DFHack with GCC 4.5. +If you build with a GCC version newer than 4.8, DFHack will probably crash +immediately on startup, or soon after. To fix this, you will need to replace +``hack/libstdc++.6.dylib`` with a symlink to the ``libstdc++.6.dylib`` included +in your version of GCC:: + + cd /hack && mv libstdc++.6.dylib libstdc++.6.dylib.orig && + ln -s [PATH_TO_LIBSTDC++] . + +For example, with GCC 5.2.0, ``PATH_TO_LIBSTDC++`` would be:: + + /usr/local/Cellar/gcc5/5.2.0/lib/gcc/5/libstdc++.6.dylib # for 64-bit DFHack + /usr/local/Cellar/gcc5/5.2.0/lib/gcc/5/i386/libstdc++.6.dylib # for 32-bit DFHack + +**Note:** If you build with a version of GCC that requires this, your DFHack +build will *not* be redistributable. (Even if you copy the ``libstdc++.6.dylib`` +from your GCC version and distribute that too, it will fail on older OS X +versions.) For this reason, if you plan on distributing DFHack, it is highly +recommended to use GCC 4.5-4.8. + +.. _osx-setup: Dependencies and system set-up ------------------------------ #. Download and unpack a copy of the latest DF -#. Install Xcode from Mac App Store +#. Install Xcode from the Mac App Store #. Install the XCode Command Line Tools by running the following command:: @@ -229,26 +261,26 @@ Dependencies and system set-up #. Install dependencies + It is recommended to use Homebrew instead of MacPorts, as it is generally + cleaner, quicker, and smarter. For example, installing MacPort's GCC will + install more than twice as many dependencies as Homebrew's will, and all in + both 32-bit and 64-bit variants. Homebrew also doesn't require constant use + of sudo. + Using `Homebrew `_ (recommended):: brew tap homebrew/versions brew install git brew install cmake - brew install gcc45 + brew install gcc48 Using `MacPorts `_:: - sudo port install gcc45 +universal cmake +universal git-core +universal + sudo port install gcc48 +universal cmake +universal git-core +universal Macports will take some time - maybe hours. At some point it may ask you to install a Java environment; let it do so. - It is recommended to use Homebrew instead of MacPorts, as it is generally - cleaner, quicker, and smarter. For example, installing - MacPort's GCC 4.5 will install more than twice as many dependencies - as Homebrew's will, and all in both 32bit and 64bit variants. - Homebrew also doesn't require constant use of sudo. - #. Install Perl dependencies * Using system Perl @@ -286,13 +318,13 @@ Building Homebrew (if installed elsewhere, replace /usr/local with ``$(brew --prefix)``):: - export CC=/usr/local/bin/gcc-4.5 - export CXX=/usr/local/bin/g++-4.5 + export CC=/usr/local/bin/gcc-4.8 + export CXX=/usr/local/bin/g++-4.8 Macports:: - export CC=/opt/local/bin/gcc-mp-4.5 - export CXX=/opt/local/bin/g++-mp-4.5 + export CC=/opt/local/bin/gcc-mp-4.8 + export CXX=/opt/local/bin/g++-mp-4.8 Change the version numbers appropriately if you installed a different version of GCC. From 64e3b12f4fcaa789c447ee1150151e81dd3c648b Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 23 Aug 2016 15:54:11 -0400 Subject: [PATCH 121/413] Make docs/build.sh a bit more configurable --- docs/build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/build.sh b/docs/build.sh index d9c0428ad..6745db4d5 100755 --- a/docs/build.sh +++ b/docs/build.sh @@ -9,12 +9,12 @@ cd $(dirname "$0") cd .. sphinx=sphinx-build -if [ -n "$1" ]; then - sphinx=$1 +if [ -n "$SPHINX" ]; then + sphinx=$SPHINX fi if [ -z "$JOBS" ]; then JOBS=2 fi -"$sphinx" -a -E -q -b html . ./docs/html -w ./docs/_sphinx-warnings.txt -j "$JOBS" +"$sphinx" -a -E -q -b html . ./docs/html -w ./docs/_sphinx-warnings.txt -j "$JOBS" "$@" From 7487f44fc8cb801cbf6d283833e7eed7f115dfdf Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 23 Aug 2016 21:47:41 -0400 Subject: [PATCH 122/413] Implement a helper to create lua environments with shortcuts (e.g. scr, unit) Used in gui/gm-editor and lua Closes #977 --- library/lua/utils.lua | 42 ++++++++++++++++++++++++++++++++++++------ scripts | 2 +- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/library/lua/utils.lua b/library/lua/utils.lua index a677af3bf..24c24c074 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -611,15 +611,45 @@ function processArgs(args, validArgs) end function fillTable(table1,table2) - for k,v in pairs(table2) do - table1[k] = v - end + for k,v in pairs(table2) do + table1[k] = v + end end function unfillTable(table1,table2) - for k,v in pairs(table2) do - table1[k] = nil - end + for k,v in pairs(table2) do + table1[k] = nil + end +end + +function df_shortcut_var(k) + if k == 'scr' or k == 'screen' then + return dfhack.gui.getCurViewscreen() + elseif k == 'bld' or k == 'building' then + return dfhack.gui.getSelectedBuilding() + elseif k == 'item' then + return dfhack.gui.getSelectedItem() + elseif k == 'job' then + return dfhack.gui.getSelectedJob() + elseif k == 'wsjob' or k == 'workshop_job' then + return dfhack.gui.getSelectedWorkshopJob() + elseif k == 'unit' then + return dfhack.gui.getSelectedUnit() + else + for g in pairs(df.global) do + if g == k then + return df.global[k] + end + end + + return _G[k] + end +end + +function df_shortcut_env() + local env = {} + setmetatable(env, {__index = function(self, k) return df_shortcut_var(k) end}) + return env end return _ENV diff --git a/scripts b/scripts index 042fcffd0..3e3fb7bff 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 042fcffd051c1f1ceab268e54bed1ed197b1f91e +Subproject commit 3e3fb7bff6dce41e7ea85ee3addf44291b53f800 From 6ce470ad57fe198fca15644d17e6749ea07fa592 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 24 Aug 2016 16:20:30 -0400 Subject: [PATCH 123/413] Add basic lua expression support to memview Currently just supports basic field accesses (world.x, screen.y.z). No support for world.x - 4, etc. Closes #976 --- library/lua/utils.lua | 21 +++++++++++ plugins/devel/CMakeLists.txt | 2 +- plugins/devel/memutils.cpp | 71 ++++++++++++++++++++++++++++++++++++ plugins/devel/memutils.h | 3 ++ plugins/devel/memview.cpp | 16 +++++++- 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 plugins/devel/memutils.cpp create mode 100644 plugins/devel/memutils.h diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 24c24c074..408ceaba8 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -652,4 +652,25 @@ function df_shortcut_env() return env end +df_env = df_shortcut_env() + +function df_expr_to_ref(expr) + expr = expr:gsub('%["(.-)"%]', function(field) return '.' .. field end) + :gsub('%[\'(.-)\'%]', function(field) return '.' .. field end) + local parts = split_string(expr, '%.') + local obj = df_env[parts[1]] + for i = 2, #parts do + if i == #parts and type(obj[parts[i]]) ~= 'userdata' then + obj = obj:_field(parts[i]) + else + obj = obj[parts[i]] + end + end + return obj +end + +function addressof(obj) + return select(2, obj:sizeof()) +end + return _ENV diff --git a/plugins/devel/CMakeLists.txt b/plugins/devel/CMakeLists.txt index e5001fff7..4fb4b5cf5 100644 --- a/plugins/devel/CMakeLists.txt +++ b/plugins/devel/CMakeLists.txt @@ -10,7 +10,7 @@ DFHACK_PLUGIN(dumpmats dumpmats.cpp) DFHACK_PLUGIN(eventExample eventExample.cpp) DFHACK_PLUGIN(frozen frozen.cpp) DFHACK_PLUGIN(kittens kittens.cpp) -DFHACK_PLUGIN(memview memview.cpp) +DFHACK_PLUGIN(memview memview.cpp memutils.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(nestboxes nestboxes.cpp) DFHACK_PLUGIN(notes notes.cpp) DFHACK_PLUGIN(onceExample onceExample.cpp) diff --git a/plugins/devel/memutils.cpp b/plugins/devel/memutils.cpp new file mode 100644 index 000000000..5674f2c9c --- /dev/null +++ b/plugins/devel/memutils.cpp @@ -0,0 +1,71 @@ +#include + +#include "Core.h" +#include "LuaTools.h" +#include "LuaWrapper.h" + +using namespace DFHack; +using namespace DFHack::LuaWrapper; +using namespace std; + +namespace memutils { + static lua_State *state; + static color_ostream_proxy *out; + + struct initializer { + Lua::StackUnwinder *unwinder; + initializer() + { + if (!out) + out = new color_ostream_proxy(Core::getInstance().getConsole()); + if (!state) + state = Lua::Open(*out); + unwinder = new Lua::StackUnwinder(state); + } + ~initializer() + { + delete unwinder; + } + }; + + struct cleaner { + ~cleaner() + { + if (state) + { + lua_close(state); + state = NULL; + } + if (out) + { + delete out; + out = NULL; + } + } + }; + + static cleaner g_cleaner; + + void *lua_expr_to_addr(const char *expr) + { + initializer init; + Lua::PushModulePublic(*out, state, "utils", "df_expr_to_ref"); + lua_pushstring(state, expr); + if (!Lua::SafeCall(*out, state, 1, 1)) + { + out->printerr("Failed to evaluate %s\n", expr); + return NULL; + } + + Lua::PushModulePublic(*out, state, "utils", "addressof"); + lua_swap(state); + if (!Lua::SafeCall(*out, state, 1, 1) || !lua_isinteger(state, -1)) + { + out->printerr("Failed to get address: %s\n", expr); + return NULL; + } + + auto addr = uintptr_t(lua_tointeger(state, -1)); + return (void*)addr; + } +} diff --git a/plugins/devel/memutils.h b/plugins/devel/memutils.h new file mode 100644 index 000000000..b94d02a9a --- /dev/null +++ b/plugins/devel/memutils.h @@ -0,0 +1,3 @@ +namespace memutils { + void *lua_expr_to_addr(const char *expr); +} diff --git a/plugins/devel/memview.cpp b/plugins/devel/memview.cpp index 53ee86755..27dc72861 100644 --- a/plugins/devel/memview.cpp +++ b/plugins/devel/memview.cpp @@ -8,6 +8,8 @@ #include #include +#include "memutils.h" + using std::vector; using std::string; using namespace DFHack; @@ -138,7 +140,19 @@ command_result memview (color_ostream &out, vector & parameters) { mymutex->lock(); Core::getInstance().p->getMemRanges(memdata.ranges); - memdata.addr=(void *)convert(parameters[0],true); + if (parameters.empty()) + { + memdata.addr = 0; + } + else if (toLower(parameters[0].substr(0, 2)) == "0x") + { + memdata.addr = (void *)convert(parameters[0],true); + } + else + { + memdata.addr = memutils::lua_expr_to_addr(parameters[0].c_str()); + } + if(memdata.addr==0) { Deinit(); From 85ebbf0e9c1e23cd289cc4828a93932c1db08a34 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 24 Aug 2016 17:18:55 -0400 Subject: [PATCH 124/413] Fix df_expr_to_ref for raw userdata --- library/lua/utils.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 408ceaba8..4800042f0 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -660,7 +660,9 @@ function df_expr_to_ref(expr) local parts = split_string(expr, '%.') local obj = df_env[parts[1]] for i = 2, #parts do - if i == #parts and type(obj[parts[i]]) ~= 'userdata' then + local cur = obj[parts[i]] + if i == #parts and ((type(cur) ~= 'userdata') or + type(cur) == 'userdata' and getmetatable(cur) == nil) then obj = obj:_field(parts[i]) else obj = obj[parts[i]] From a3ab757642c37fcc8a4394547e4e184cf8882182 Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 25 Aug 2016 21:14:23 +0530 Subject: [PATCH 125/413] Add spatters to remotefortressreader.cpp --- plugins/proto/RemoteFortressReader.proto | 24 ++++++++ plugins/remotefortressreader.cpp | 78 ++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 996e01a30..36c2442ce 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -176,6 +176,29 @@ message RiverTile optional RiverEdge west = 4; } +enum MatterState +{ + Solid = 0; + Liquid = 1; + Gas = 2; + Powder = 3; + Paste = 4; + Pressed = 5; +} + +message Spatter +{ + optional MatPair material = 1; + optional int32 amount = 2; + optional MatterState state = 3; + optional MatPair item = 4; +} + +message SpatterPile +{ + repeated Spatter spatters = 1; +} + message MapBlock { required int32 map_x = 1; @@ -202,6 +225,7 @@ message MapBlock repeated int32 tree_y = 22; repeated int32 tree_z = 23; repeated TileDigDesignation tile_dig_designation = 24; + repeated SpatterPile spatterPile = 25; } message MatPair { diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 6933826c7..dbe8a5f12 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -913,11 +913,42 @@ bool IsBuildingChanged(DFCoord pos) return changed; } +map spatterHashes; + +//check if map spatters have changed +bool IsspatterChanged(DFCoord pos) +{ + df::map_block * block = Maps::getBlock(pos); + bool changed = false; + std::vector materials; + std::vector items; + if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL, NULL, &items)) + return false; + + uint16_t hash = 0; + + for each (auto mat in materials) + { + hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_material_spatterst)); + } + for each (auto mat in items) + { + hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_item_spatterst)); + } + if (spatterHashes[pos] != hash) + { + spatterHashes[pos] = hash; + return true; + } + return false; +} + static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage *in) { hashes.clear(); waterHashes.clear(); buildingHashes.clear(); + spatterHashes.clear(); return CR_OK; } @@ -1310,6 +1341,43 @@ void CopyBuildings(df::map_block * DfBlock, RemoteFortressReader::MapBlock * Net } } +void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) +{ + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + std::vector materials; + std::vector items; + if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, NULL, NULL, NULL, &items)) + return; + + for (int yy = 0; yy < 16; yy++) + for (int xx = 0; xx < 16; xx++) + { + auto send_pile = NetBlock->add_spatterpile(); + for each (auto mat in materials) + { + auto send_spat = send_pile->add_spatters(); + send_spat->set_state((MatterState)mat->mat_state); + auto send_mat = send_spat->mutable_material(); + send_mat->set_mat_index(mat->mat_index); + send_mat->set_mat_type(mat->mat_type); + send_spat->set_amount(mat->amount[xx][yy]); + } + for each (auto item in items) + { + auto send_spat = send_pile->add_spatters(); + auto send_mat = send_spat->mutable_material(); + send_mat->set_mat_index(item->matindex); + send_mat->set_mat_type(item->mattype); + send_spat->set_amount(item->amount[xx][yy]); + auto send_item = send_spat->mutable_item(); + send_item->set_mat_type(item->item_type); + send_item->set_mat_index(item->item_subtype); + } + } +} + static command_result GetBlockList(color_ostream &stream, const BlockRequest *in, BlockList *out) { int x, y, z; @@ -1367,9 +1435,11 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in { bool tileChanged = IsTiletypeChanged(pos); bool desChanged = IsDesignationChanged(pos); + bool spatterChanged = IsspatterChanged(pos); + bool buildingChanged = IsBuildingChanged(pos); //bool bldChanged = IsBuildingChanged(pos); RemoteFortressReader::MapBlock *net_block; - if (tileChanged || desChanged) + if (tileChanged || desChanged || spatterChanged || buildingChanged) net_block = out->add_map_blocks(); if (tileChanged) { @@ -1378,10 +1448,10 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in } if (desChanged) CopyDesignation(block, net_block, &MC, pos); - if (tileChanged) - { + if (buildingChanged) CopyBuildings(block, net_block, &MC, pos); - } + if (spatterChanged) + Copyspatters(block, net_block, &MC, pos); } } } From 012e5e2a3b6acae039fa8e3c8135639ad7c09ffd Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 25 Aug 2016 12:14:44 -0400 Subject: [PATCH 126/413] Add gui/manager-quantity keybinding --- dfhack.init-example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dfhack.init-example b/dfhack.init-example index f8cadb215..169d40046 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -52,6 +52,9 @@ keybinding add Ctrl-Shift-F@dwarfmode forum-dwarves keybinding add Alt-S@title gui/settings-manager keybinding add Alt-S@dwarfmode/Default gui/settings-manager +# change quantity of manager orders +keybinding add Alt-Q@jobmanagement gui/manager-quantity + ############################## # Generic adv mode bindings # ############################## From db7be082ef3bf4dd117dd1595295ad222d67e769 Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 25 Aug 2016 23:56:30 +0530 Subject: [PATCH 127/413] Only copy spatters if they actually have any amount. --- plugins/remotefortressreader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index dbe8a5f12..ee78a2a77 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1357,6 +1357,8 @@ void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetB auto send_pile = NetBlock->add_spatterpile(); for each (auto mat in materials) { + if (mat->amount == 0) + continue; auto send_spat = send_pile->add_spatters(); send_spat->set_state((MatterState)mat->mat_state); auto send_mat = send_spat->mutable_material(); @@ -1366,6 +1368,8 @@ void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetB } for each (auto item in items) { + if (item->amount == 0) + continue; auto send_spat = send_pile->add_spatters(); auto send_mat = send_spat->mutable_material(); send_mat->set_mat_index(item->matindex); From 5c3260c382aba267458ce1001230f65b32639357 Mon Sep 17 00:00:00 2001 From: Japa Date: Fri, 26 Aug 2016 08:49:54 +0530 Subject: [PATCH 128/413] Actually check spatter amounts properly --- plugins/remotefortressreader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index ee78a2a77..a093f2dfc 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1357,7 +1357,7 @@ void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetB auto send_pile = NetBlock->add_spatterpile(); for each (auto mat in materials) { - if (mat->amount == 0) + if (mat->amount[xx][yy] == 0) continue; auto send_spat = send_pile->add_spatters(); send_spat->set_state((MatterState)mat->mat_state); @@ -1368,7 +1368,7 @@ void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetB } for each (auto item in items) { - if (item->amount == 0) + if (item->amount[xx][yy] == 0) continue; auto send_spat = send_pile->add_spatters(); auto send_mat = send_spat->mutable_material(); From 91cb734a25f65a40c7aa85692db3c7fdcc9ba28c Mon Sep 17 00:00:00 2001 From: Japa Date: Fri, 26 Aug 2016 12:23:50 +0530 Subject: [PATCH 129/413] Send histfig materials over remotefortressreader.cpp, using unique ids. --- plugins/remotefortressreader.cpp | 141 ++++++++++++++++++------------- 1 file changed, 84 insertions(+), 57 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index a093f2dfc..b9683aa83 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -15,6 +15,7 @@ #include "df/caste_raw.h" #include "df/body_part_raw.h" #include "df/historical_figure.h" +#include "df/world_history.h" #include "df/job_item.h" #include "df/job_material_category.h" @@ -945,78 +946,79 @@ bool IsspatterChanged(DFCoord pos) static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage *in) { - hashes.clear(); - waterHashes.clear(); - buildingHashes.clear(); + hashes.clear(); + waterHashes.clear(); + buildingHashes.clear(); spatterHashes.clear(); - return CR_OK; + return CR_OK; } df::matter_state GetState(df::material * mat, uint16_t temp = 10015) { - df::matter_state state = matter_state::Solid; - if (temp >= mat->heat.melting_point) - state = df::matter_state::Liquid; - if (temp >= mat->heat.boiling_point) - state = matter_state::Gas; - return state; + df::matter_state state = matter_state::Solid; + if (temp >= mat->heat.melting_point) + state = df::matter_state::Liquid; + if (temp >= mat->heat.boiling_point) + state = matter_state::Gas; + return state; } static command_result GetMaterialList(color_ostream &stream, const EmptyMessage *in, MaterialList *out) { - if (!Core::getInstance().isWorldLoaded()) { - //out->set_available(false); - return CR_OK; - } + if (!Core::getInstance().isWorldLoaded()) { + //out->set_available(false); + return CR_OK; + } - df::world_raws *raws = &world->raws; - MaterialInfo mat; - for (int i = 0; i < raws->inorganics.size(); i++) - { - mat.decode(0, i); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(0); - mat_def->mutable_mat_pair()->set_mat_index(i); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)] < raws->language.colors.size()) - { - df::descriptor_color *color = raws->language.colors[raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)]]; - mat_def->mutable_state_color()->set_red(color->red * 255); - mat_def->mutable_state_color()->set_green(color->green * 255); - mat_def->mutable_state_color()->set_blue(color->blue * 255); - } - } - for (int i = 0; i < 19; i++) - { - int k = -1; - if (i == 7) - k = 1;// for coal. - for (int j = -1; j <= k; j++) - { - mat.decode(i, j); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(i); - mat_def->mutable_mat_pair()->set_mat_index(j); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])] < raws->language.colors.size()) - { - df::descriptor_color *color = raws->language.colors[raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])]]; - mat_def->mutable_state_color()->set_red(color->red * 255); - mat_def->mutable_state_color()->set_green(color->green * 255); - mat_def->mutable_state_color()->set_blue(color->blue * 255); - } - } - } - for (int i = 0; i < raws->creatures.all.size(); i++) - { + df::world_raws *raws = &world->raws; + df::world_history *history = &world->history; + MaterialInfo mat; + for (int i = 0; i < raws->inorganics.size(); i++) + { + mat.decode(0, i); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(0); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)] < raws->language.colors.size()) + { + df::descriptor_color *color = raws->language.colors[raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)]]; + mat_def->mutable_state_color()->set_red(color->red * 255); + mat_def->mutable_state_color()->set_green(color->green * 255); + mat_def->mutable_state_color()->set_blue(color->blue * 255); + } + } + for (int i = 0; i < 19; i++) + { + int k = -1; + if (i == 7) + k = 1;// for coal. + for (int j = -1; j <= k; j++) + { + mat.decode(i, j); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(i); + mat_def->mutable_mat_pair()->set_mat_index(j); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])] < raws->language.colors.size()) + { + df::descriptor_color *color = raws->language.colors[raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])]]; + mat_def->mutable_state_color()->set_red(color->red * 255); + mat_def->mutable_state_color()->set_green(color->green * 255); + mat_def->mutable_state_color()->set_blue(color->blue * 255); + } + } + } + for (int i = 0; i < raws->creatures.all.size(); i++) + { df::creature_raw * creature = raws->creatures.all[i]; for (int j = 0; j < creature->material.size(); j++) { - mat.decode(j + 19, i); + mat.decode(j + MaterialInfo::CREATURE_BASE, i); MaterialDefinition *mat_def = out->add_material_list(); mat_def->mutable_mat_pair()->set_mat_type(j + 19); mat_def->mutable_mat_pair()->set_mat_index(i); @@ -1031,6 +1033,31 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage } } } + for (int i = 0; i < history->figures.size(); i++) + { + df::historical_figure * figure = history->figures[i]; + if (figure->race < 0) + continue; + df::creature_raw * creature = raws->creatures.all[figure->race]; + for (int j = 0; j < creature->material.size(); j++) + { + mat.decode(j + MaterialInfo::FIGURE_BASE, i); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(j + MaterialInfo::FIGURE_BASE); + mat_def->mutable_mat_pair()->set_mat_index(i); + stringstream id; + id << "HF" << i << mat.getToken(); + mat_def->set_id(id.str()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) + { + df::descriptor_color *color = raws->language.colors[creature->material[j]->state_color[GetState(creature->material[j])]]; + mat_def->mutable_state_color()->set_red(color->red * 255); + mat_def->mutable_state_color()->set_green(color->green * 255); + mat_def->mutable_state_color()->set_blue(color->blue * 255); + } + } + } for (int i = 0; i < raws->plants.all.size(); i++) { df::plant_raw * plant = raws->plants.all[i]; From 7d145de4a7490cbf8328d0ac9e71446374dd1dc0 Mon Sep 17 00:00:00 2001 From: Japa Date: Fri, 26 Aug 2016 23:48:32 +0530 Subject: [PATCH 130/413] Translate histfig mats into creature mats, rather than sending the entire histfig population. --- plugins/remotefortressreader.cpp | 737 +++++++++++++++---------------- 1 file changed, 365 insertions(+), 372 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index b9683aa83..81dc690a1 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -240,9 +240,9 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("ResetMapHashes", ResetMapHashes); svc->addFunction("GetItemList", GetItemList); svc->addFunction("GetBuildingDefList", GetBuildingDefList); - svc->addFunction("GetWorldMap", GetWorldMap); - svc->addFunction("GetWorldMapNew", GetWorldMapNew); - svc->addFunction("GetRegionMaps", GetRegionMaps); + svc->addFunction("GetWorldMap", GetWorldMap); + svc->addFunction("GetWorldMapNew", GetWorldMapNew); + svc->addFunction("GetRegionMaps", GetRegionMaps); svc->addFunction("GetRegionMapsNew", GetRegionMapsNew); svc->addFunction("GetCreatureRaws", GetCreatureRaws); svc->addFunction("GetWorldMapCenter", GetWorldMapCenter); @@ -855,6 +855,22 @@ static command_result CheckHashes(color_ostream &stream, const EmptyMessage *in) return CR_OK; } +void CopyMat(RemoteFortressReader::MatPair * mat, int type, int index) +{ + if (type >= MaterialInfo::FIGURE_BASE && type < MaterialInfo::PLANT_BASE) + { + df::historical_figure * figure = df::historical_figure::find(index); + if (figure) + { + type -= MaterialInfo::GROUP_SIZE; + index = figure->race; + } + } + mat->set_mat_type(type); + mat->set_mat_index(index); + +} + map hashes; //check if the tiletypes have changed @@ -919,102 +935,102 @@ map spatterHashes; //check if map spatters have changed bool IsspatterChanged(DFCoord pos) { - df::map_block * block = Maps::getBlock(pos); - bool changed = false; - std::vector materials; - std::vector items; - if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL, NULL, &items)) - return false; - - uint16_t hash = 0; - - for each (auto mat in materials) - { - hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_material_spatterst)); - } - for each (auto mat in items) - { - hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_item_spatterst)); - } - if (spatterHashes[pos] != hash) - { - spatterHashes[pos] = hash; - return true; - } - return false; + df::map_block * block = Maps::getBlock(pos); + bool changed = false; + std::vector materials; + std::vector items; + if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL, NULL, &items)) + return false; + + uint16_t hash = 0; + + for each (auto mat in materials) + { + hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_material_spatterst)); + } + for each (auto mat in items) + { + hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_item_spatterst)); + } + if (spatterHashes[pos] != hash) + { + spatterHashes[pos] = hash; + return true; + } + return false; } static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage *in) { - hashes.clear(); - waterHashes.clear(); - buildingHashes.clear(); - spatterHashes.clear(); - return CR_OK; + hashes.clear(); + waterHashes.clear(); + buildingHashes.clear(); + spatterHashes.clear(); + return CR_OK; } df::matter_state GetState(df::material * mat, uint16_t temp = 10015) { - df::matter_state state = matter_state::Solid; - if (temp >= mat->heat.melting_point) - state = df::matter_state::Liquid; - if (temp >= mat->heat.boiling_point) - state = matter_state::Gas; - return state; + df::matter_state state = matter_state::Solid; + if (temp >= mat->heat.melting_point) + state = df::matter_state::Liquid; + if (temp >= mat->heat.boiling_point) + state = matter_state::Gas; + return state; } static command_result GetMaterialList(color_ostream &stream, const EmptyMessage *in, MaterialList *out) { - if (!Core::getInstance().isWorldLoaded()) { - //out->set_available(false); - return CR_OK; - } - - - - df::world_raws *raws = &world->raws; - df::world_history *history = &world->history; - MaterialInfo mat; - for (int i = 0; i < raws->inorganics.size(); i++) - { - mat.decode(0, i); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(0); - mat_def->mutable_mat_pair()->set_mat_index(i); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)] < raws->language.colors.size()) - { - df::descriptor_color *color = raws->language.colors[raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)]]; - mat_def->mutable_state_color()->set_red(color->red * 255); - mat_def->mutable_state_color()->set_green(color->green * 255); - mat_def->mutable_state_color()->set_blue(color->blue * 255); - } - } - for (int i = 0; i < 19; i++) - { - int k = -1; - if (i == 7) - k = 1;// for coal. - for (int j = -1; j <= k; j++) - { - mat.decode(i, j); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(i); - mat_def->mutable_mat_pair()->set_mat_index(j); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])] < raws->language.colors.size()) - { - df::descriptor_color *color = raws->language.colors[raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])]]; - mat_def->mutable_state_color()->set_red(color->red * 255); - mat_def->mutable_state_color()->set_green(color->green * 255); - mat_def->mutable_state_color()->set_blue(color->blue * 255); - } - } - } - for (int i = 0; i < raws->creatures.all.size(); i++) - { + if (!Core::getInstance().isWorldLoaded()) { + //out->set_available(false); + return CR_OK; + } + + + + df::world_raws *raws = &world->raws; + df::world_history *history = &world->history; + MaterialInfo mat; + for (int i = 0; i < raws->inorganics.size(); i++) + { + mat.decode(0, i); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(0); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)] < raws->language.colors.size()) + { + df::descriptor_color *color = raws->language.colors[raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)]]; + mat_def->mutable_state_color()->set_red(color->red * 255); + mat_def->mutable_state_color()->set_green(color->green * 255); + mat_def->mutable_state_color()->set_blue(color->blue * 255); + } + } + for (int i = 0; i < 19; i++) + { + int k = -1; + if (i == 7) + k = 1;// for coal. + for (int j = -1; j <= k; j++) + { + mat.decode(i, j); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(i); + mat_def->mutable_mat_pair()->set_mat_index(j); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])] < raws->language.colors.size()) + { + df::descriptor_color *color = raws->language.colors[raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])]]; + mat_def->mutable_state_color()->set_red(color->red * 255); + mat_def->mutable_state_color()->set_green(color->green * 255); + mat_def->mutable_state_color()->set_blue(color->blue * 255); + } + } + } + for (int i = 0; i < raws->creatures.all.size(); i++) + { df::creature_raw * creature = raws->creatures.all[i]; for (int j = 0; j < creature->material.size(); j++) { @@ -1033,31 +1049,31 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage } } } - for (int i = 0; i < history->figures.size(); i++) - { - df::historical_figure * figure = history->figures[i]; - if (figure->race < 0) - continue; - df::creature_raw * creature = raws->creatures.all[figure->race]; - for (int j = 0; j < creature->material.size(); j++) - { - mat.decode(j + MaterialInfo::FIGURE_BASE, i); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(j + MaterialInfo::FIGURE_BASE); - mat_def->mutable_mat_pair()->set_mat_index(i); - stringstream id; - id << "HF" << i << mat.getToken(); - mat_def->set_id(id.str()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) - { - df::descriptor_color *color = raws->language.colors[creature->material[j]->state_color[GetState(creature->material[j])]]; - mat_def->mutable_state_color()->set_red(color->red * 255); - mat_def->mutable_state_color()->set_green(color->green * 255); - mat_def->mutable_state_color()->set_blue(color->blue * 255); - } - } - } + //for (int i = 0; i < history->figures.size(); i++) + //{ + // df::historical_figure * figure = history->figures[i]; + // if (figure->race < 0) + // continue; + // df::creature_raw * creature = raws->creatures.all[figure->race]; + // for (int j = 0; j < creature->material.size(); j++) + // { + // mat.decode(j + MaterialInfo::FIGURE_BASE, i); + // MaterialDefinition *mat_def = out->add_material_list(); + // mat_def->mutable_mat_pair()->set_mat_type(j + MaterialInfo::FIGURE_BASE); + // mat_def->mutable_mat_pair()->set_mat_index(i); + // stringstream id; + // id << "HF" << i << mat.getToken(); + // mat_def->set_id(id.str()); + // mat_def->set_name(mat.toString()); //find the name at cave temperature; + // if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) + // { + // df::descriptor_color *color = raws->language.colors[creature->material[j]->state_color[GetState(creature->material[j])]]; + // mat_def->mutable_state_color()->set_red(color->red * 255); + // mat_def->mutable_state_color()->set_green(color->green * 255); + // mat_def->mutable_state_color()->set_blue(color->blue * 255); + // } + // } + //} for (int i = 0; i < raws->plants.all.size(); i++) { df::plant_raw * plant = raws->plants.all[i]; @@ -1241,28 +1257,18 @@ void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBloc default: break; } - RemoteFortressReader::MatPair * material = NetBlock->add_materials(); - material->set_mat_type(staticMat.mat_type); - material->set_mat_index(staticMat.mat_index); - RemoteFortressReader::MatPair * layerMaterial = NetBlock->add_layer_materials(); - layerMaterial->set_mat_type(0); - layerMaterial->set_mat_index(block->layerMaterialAt(p)); - RemoteFortressReader::MatPair * veinMaterial = NetBlock->add_vein_materials(); - veinMaterial->set_mat_type(0); - veinMaterial->set_mat_index(block->veinMaterialAt(p)); - RemoteFortressReader::MatPair * baseMaterial = NetBlock->add_base_materials(); - baseMaterial->set_mat_type(baseMat.mat_type); - baseMaterial->set_mat_index(baseMat.mat_index); + CopyMat(NetBlock->add_materials(), staticMat.mat_type, staticMat.mat_index); + CopyMat(NetBlock->add_layer_materials(), 0, block->layerMaterialAt(p)); + CopyMat(NetBlock->add_vein_materials(), 0, block->veinMaterialAt(p)); + CopyMat(NetBlock->add_base_materials(), baseMat.mat_type, baseMat.mat_index); RemoteFortressReader::MatPair * constructionItem = NetBlock->add_construction_items(); - constructionItem->set_mat_type(-1); - constructionItem->set_mat_index(-1); + CopyMat(constructionItem, -1, -1); if (tileMaterial(tile) == tiletype_material::CONSTRUCTION) { df::construction *con = df::construction::find(DfBlock->map_pos + df::coord(xx, yy, 0)); if (con) { - constructionItem->set_mat_type(con->item_type); - constructionItem->set_mat_index(con->item_subtype); + CopyMat(constructionItem, con->item_type, con->item_subtype); } } NetBlock->add_tree_percent(trunk_percent[xx][yy]); @@ -1370,43 +1376,39 @@ void CopyBuildings(df::map_block * DfBlock, RemoteFortressReader::MapBlock * Net void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) { - NetBlock->set_map_x(DfBlock->map_pos.x); - NetBlock->set_map_y(DfBlock->map_pos.y); - NetBlock->set_map_z(DfBlock->map_pos.z); - std::vector materials; - std::vector items; - if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, NULL, NULL, NULL, &items)) - return; - - for (int yy = 0; yy < 16; yy++) - for (int xx = 0; xx < 16; xx++) - { - auto send_pile = NetBlock->add_spatterpile(); - for each (auto mat in materials) - { - if (mat->amount[xx][yy] == 0) - continue; - auto send_spat = send_pile->add_spatters(); - send_spat->set_state((MatterState)mat->mat_state); - auto send_mat = send_spat->mutable_material(); - send_mat->set_mat_index(mat->mat_index); - send_mat->set_mat_type(mat->mat_type); - send_spat->set_amount(mat->amount[xx][yy]); - } - for each (auto item in items) - { - if (item->amount[xx][yy] == 0) - continue; - auto send_spat = send_pile->add_spatters(); - auto send_mat = send_spat->mutable_material(); - send_mat->set_mat_index(item->matindex); - send_mat->set_mat_type(item->mattype); - send_spat->set_amount(item->amount[xx][yy]); - auto send_item = send_spat->mutable_item(); - send_item->set_mat_type(item->item_type); - send_item->set_mat_index(item->item_subtype); - } - } + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + std::vector materials; + std::vector items; + if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, NULL, NULL, NULL, &items)) + return; + + for (int yy = 0; yy < 16; yy++) + for (int xx = 0; xx < 16; xx++) + { + auto send_pile = NetBlock->add_spatterpile(); + for each (auto mat in materials) + { + if (mat->amount[xx][yy] == 0) + continue; + auto send_spat = send_pile->add_spatters(); + send_spat->set_state((MatterState)mat->mat_state); + CopyMat(send_spat->mutable_material(), mat->mat_type, mat->mat_index); + send_spat->set_amount(mat->amount[xx][yy]); + } + for each (auto item in items) + { + if (item->amount[xx][yy] == 0) + continue; + auto send_spat = send_pile->add_spatters(); + CopyMat(send_spat->mutable_material(), item->mattype, item->matindex); + send_spat->set_amount(item->amount[xx][yy]); + auto send_item = send_spat->mutable_item(); + send_item->set_mat_type(item->item_type); + send_item->set_mat_index(item->item_subtype); + } + } } static command_result GetBlockList(color_ostream &stream, const BlockRequest *in, BlockList *out) @@ -1466,8 +1468,8 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in { bool tileChanged = IsTiletypeChanged(pos); bool desChanged = IsDesignationChanged(pos); - bool spatterChanged = IsspatterChanged(pos); - bool buildingChanged = IsBuildingChanged(pos); + bool spatterChanged = IsspatterChanged(pos); + bool buildingChanged = IsBuildingChanged(pos); //bool bldChanged = IsBuildingChanged(pos); RemoteFortressReader::MapBlock *net_block; if (tileChanged || desChanged || spatterChanged || buildingChanged) @@ -1481,8 +1483,8 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in CopyDesignation(block, net_block, &MC, pos); if (buildingChanged) CopyBuildings(block, net_block, &MC, pos); - if (spatterChanged) - Copyspatters(block, net_block, &MC, pos); + if (spatterChanged) + Copyspatters(block, net_block, &MC, pos); } } } @@ -2045,126 +2047,126 @@ static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, static void SetRegionTile(RegionTile * out, df::region_map_entry * e1) { - df::world_region * region = df::world_region::find(e1->region_id); - df::world_geo_biome * geoBiome = df::world_geo_biome::find(e1->geo_index); - out->set_rainfall(e1->rainfall); - out->set_vegetation(e1->vegetation); - out->set_temperature(e1->temperature); - out->set_evilness(e1->evilness); - out->set_drainage(e1->drainage); - out->set_volcanism(e1->volcanism); - out->set_savagery(e1->savagery); - out->set_salinity(e1->salinity); - if (region->type == world_region_type::Lake) - out->set_water_elevation(region->lake_surface); - else - out->set_water_elevation(99); - - int topLayer = 0; - for (int i = 0; i < geoBiome->layers.size(); i++) - { - auto layer = geoBiome->layers[i]; - if (layer->top_height == 0) - { - topLayer = layer->mat_index; - } - if (layer->type != geo_layer_type::SOIL - && layer->type != geo_layer_type::SOIL_OCEAN - && layer->type != geo_layer_type::SOIL_SAND) - { - auto mat = out->add_stone_materials(); - mat->set_mat_index(layer->mat_index); - mat->set_mat_type(0); - } - } - auto surfaceMat = out->mutable_surface_material(); - surfaceMat->set_mat_index(topLayer); - surfaceMat->set_mat_type(0); - - for (int i = 0; i < region->population.size(); i++) - { - auto pop = region->population[i]; - if (pop->type == world_population_type::Grass) - { - auto plantMat = out->add_plant_materials(); - - plantMat->set_mat_index(pop->plant); - plantMat->set_mat_type(419); - } - else if (pop->type == world_population_type::Tree) - { - auto plantMat = out->add_tree_materials(); - - plantMat->set_mat_index(pop->plant); - plantMat->set_mat_type(419); - } - } + df::world_region * region = df::world_region::find(e1->region_id); + df::world_geo_biome * geoBiome = df::world_geo_biome::find(e1->geo_index); + out->set_rainfall(e1->rainfall); + out->set_vegetation(e1->vegetation); + out->set_temperature(e1->temperature); + out->set_evilness(e1->evilness); + out->set_drainage(e1->drainage); + out->set_volcanism(e1->volcanism); + out->set_savagery(e1->savagery); + out->set_salinity(e1->salinity); + if (region->type == world_region_type::Lake) + out->set_water_elevation(region->lake_surface); + else + out->set_water_elevation(99); + + int topLayer = 0; + for (int i = 0; i < geoBiome->layers.size(); i++) + { + auto layer = geoBiome->layers[i]; + if (layer->top_height == 0) + { + topLayer = layer->mat_index; + } + if (layer->type != geo_layer_type::SOIL + && layer->type != geo_layer_type::SOIL_OCEAN + && layer->type != geo_layer_type::SOIL_SAND) + { + auto mat = out->add_stone_materials(); + mat->set_mat_index(layer->mat_index); + mat->set_mat_type(0); + } + } + auto surfaceMat = out->mutable_surface_material(); + surfaceMat->set_mat_index(topLayer); + surfaceMat->set_mat_type(0); + + for (int i = 0; i < region->population.size(); i++) + { + auto pop = region->population[i]; + if (pop->type == world_population_type::Grass) + { + auto plantMat = out->add_plant_materials(); + + plantMat->set_mat_index(pop->plant); + plantMat->set_mat_type(419); + } + else if (pop->type == world_population_type::Tree) + { + auto plantMat = out->add_tree_materials(); + + plantMat->set_mat_index(pop->plant); + plantMat->set_mat_type(419); + } + } } static command_result GetWorldMapNew(color_ostream &stream, const EmptyMessage *in, WorldMap *out) { - if (!df::global::world->world_data) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - if (!data->region_map) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - int width = data->world_width; - int height = data->world_height; - out->set_world_width(width); - out->set_world_height(height); - out->set_name(Translation::TranslateName(&(data->name), false)); - out->set_name_english(Translation::TranslateName(&(data->name), true)); - auto poles = data->flip_latitude; - switch (poles) - { - case df::world_data::None: - out->set_world_poles(WorldPoles::NO_POLES); - break; - case df::world_data::North: - out->set_world_poles(WorldPoles::NORTH_POLE); - break; - case df::world_data::South: - out->set_world_poles(WorldPoles::SOUTH_POLE); - break; - case df::world_data::Both: - out->set_world_poles(WorldPoles::BOTH_POLES); - break; - default: - break; - } - for (int yy = 0; yy < height; yy++) - for (int xx = 0; xx < width; xx++) - { - df::region_map_entry * map_entry = &data->region_map[xx][yy]; - df::world_region * region = data->regions[map_entry->region_id]; - - auto regionTile = out->add_region_tiles(); - regionTile->set_elevation(map_entry->elevation); - SetRegionTile(regionTile, map_entry); - auto clouds = out->add_clouds(); - clouds->set_cirrus(map_entry->clouds.bits.cirrus); - clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); - clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); - clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); - clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); - } - DFCoord pos = GetMapCenter(); - out->set_center_x(pos.x); - out->set_center_y(pos.y); - out->set_center_z(pos.z); - - - out->set_cur_year(World::ReadCurrentYear()); - out->set_cur_year_tick(World::ReadCurrentTick()); - return CR_OK; + if (!df::global::world->world_data) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + if (!data->region_map) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + int width = data->world_width; + int height = data->world_height; + out->set_world_width(width); + out->set_world_height(height); + out->set_name(Translation::TranslateName(&(data->name), false)); + out->set_name_english(Translation::TranslateName(&(data->name), true)); + auto poles = data->flip_latitude; + switch (poles) + { + case df::world_data::None: + out->set_world_poles(WorldPoles::NO_POLES); + break; + case df::world_data::North: + out->set_world_poles(WorldPoles::NORTH_POLE); + break; + case df::world_data::South: + out->set_world_poles(WorldPoles::SOUTH_POLE); + break; + case df::world_data::Both: + out->set_world_poles(WorldPoles::BOTH_POLES); + break; + default: + break; + } + for (int yy = 0; yy < height; yy++) + for (int xx = 0; xx < width; xx++) + { + df::region_map_entry * map_entry = &data->region_map[xx][yy]; + df::world_region * region = data->regions[map_entry->region_id]; + + auto regionTile = out->add_region_tiles(); + regionTile->set_elevation(map_entry->elevation); + SetRegionTile(regionTile, map_entry); + auto clouds = out->add_clouds(); + clouds->set_cirrus(map_entry->clouds.bits.cirrus); + clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); + clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); + clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); + clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); + } + DFCoord pos = GetMapCenter(); + out->set_center_x(pos.x); + out->set_center_y(pos.y); + out->set_center_z(pos.z); + + + out->set_cur_year(World::ReadCurrentYear()); + out->set_cur_year_tick(World::ReadCurrentTick()); + return CR_OK; } static void AddRegionTiles(WorldMap * out, df::region_map_entry * e1, df::world_data * worldData) @@ -2208,7 +2210,7 @@ static void AddRegionTiles(RegionTile * out, df::coord2d pos, df::world_data * w pos.x = worldData->world_width - 1; if (pos.y >= worldData->world_height) pos.y = worldData->world_height - 1; - SetRegionTile(out, &worldData->region_map[pos.x][pos.y]); + SetRegionTile(out, &worldData->region_map[pos.x][pos.y]); } static df::coord2d ShiftCoords(df::coord2d source, int direction) @@ -2371,13 +2373,13 @@ static void CopyLocalMap(df::world_data * worldData, df::world_region_details* w south = region; } - RegionTile* outputTiles[17][17]; + RegionTile* outputTiles[17][17]; for (int yy = 0; yy < 17; yy++) for (int xx = 0; xx < 17; xx++) { auto tile = out->add_tiles(); - outputTiles[xx][yy] = tile; + outputTiles[xx][yy] = tile; //This is because the bottom row doesn't line up. if (xx == 16 && yy == 16 && southEast != NULL) { @@ -2427,82 +2429,78 @@ static void CopyLocalMap(df::world_data * worldData, df::world_region_details* w east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); } - auto regionMap = worldData->region_map[pos_x][pos_y]; - - for (int i = 0; i < worldData->sites.size(); i++) - { - df::world_site* site = worldData->sites[i]; - if (!site) - continue; - - int region_min_x = pos_x * 16; - int region_min_y = pos_y * 16; - - if ((site->global_min_x > (region_min_x + 16)) || - (site->global_min_y > (region_min_y + 16)) || - (site->global_max_x < (region_min_x)) || - (site->global_max_y < (region_min_y))) - continue; - - if (site->realization == NULL) - continue; - - auto realization = site->realization; - for (int site_x = 0; site_x < 17; site_x++) - for (int site_y = 0; site_y < 17; site_y++) - { - int region_x = site->global_min_x - region_min_x + site_x; - int region_y = site->global_min_y - region_min_y + site_y; - - if (region_x < 0 || region_y < 0 || region_x >= 16 || region_y >= 16) - continue; - - for (int j = 0; j < realization->building_map[site_x][site_y].buildings.size(); j++) - { - auto in_building = realization->building_map[site_x][site_y].buildings[j]; - auto out_building = outputTiles[region_x][region_y]->add_buildings(); - - out_building->set_id(in_building->id); - out_building->set_type((SiteRealizationBuildingType)in_building->type); - out_building->set_min_x(in_building->min_x - (site_x * 48)); - out_building->set_min_y(in_building->min_y - (site_y * 48)); - out_building->set_max_x(in_building->max_x - (site_x * 48)); - out_building->set_max_y(in_building->max_y - (site_y * 48)); - - auto mat = out_building->mutable_material(); - mat->set_mat_type(in_building->item.mat_type); - mat->set_mat_index(in_building->item.mat_index); - - STRICT_VIRTUAL_CAST_VAR(tower_info, df::site_realization_building_info_castle_towerst, in_building->building_info); - if (tower_info) - { - mat->set_mat_index(tower_info->wall_item.mat_index); - mat->set_mat_type(tower_info->wall_item.mat_type); - - auto out_tower = out_building->mutable_tower_info(); - out_tower->set_roof_z(tower_info->roof_z); - out_tower->set_round(tower_info->shape.bits.round); - out_tower->set_goblin(tower_info->shape.bits.goblin); - } - STRICT_VIRTUAL_CAST_VAR(wall_info, df::site_realization_building_info_castle_wallst, in_building->building_info); - if (wall_info) - { - mat->set_mat_index(wall_info->wall_item.mat_index); - mat->set_mat_type(wall_info->wall_item.mat_type); - - auto out_wall = out_building->mutable_wall_info(); - - out_wall->set_start_x(wall_info->start_x - (site_x * 48)); - out_wall->set_start_y(wall_info->start_y - (site_y * 48)); - out_wall->set_start_z(wall_info->start_z); - out_wall->set_end_x(wall_info->end_x - (site_x * 48)); - out_wall->set_end_y(wall_info->end_y - (site_y * 48)); - out_wall->set_end_z(wall_info->end_z); - } - } - - } - } + auto regionMap = worldData->region_map[pos_x][pos_y]; + + for (int i = 0; i < worldData->sites.size(); i++) + { + df::world_site* site = worldData->sites[i]; + if (!site) + continue; + + int region_min_x = pos_x * 16; + int region_min_y = pos_y * 16; + + if ((site->global_min_x > (region_min_x + 16)) || + (site->global_min_y > (region_min_y + 16)) || + (site->global_max_x < (region_min_x)) || + (site->global_max_y < (region_min_y))) + continue; + + if (site->realization == NULL) + continue; + + auto realization = site->realization; + for (int site_x = 0; site_x < 17; site_x++) + for (int site_y = 0; site_y < 17; site_y++) + { + int region_x = site->global_min_x - region_min_x + site_x; + int region_y = site->global_min_y - region_min_y + site_y; + + if (region_x < 0 || region_y < 0 || region_x >= 16 || region_y >= 16) + continue; + + for (int j = 0; j < realization->building_map[site_x][site_y].buildings.size(); j++) + { + auto in_building = realization->building_map[site_x][site_y].buildings[j]; + auto out_building = outputTiles[region_x][region_y]->add_buildings(); + + out_building->set_id(in_building->id); + out_building->set_type((SiteRealizationBuildingType)in_building->type); + out_building->set_min_x(in_building->min_x - (site_x * 48)); + out_building->set_min_y(in_building->min_y - (site_y * 48)); + out_building->set_max_x(in_building->max_x - (site_x * 48)); + out_building->set_max_y(in_building->max_y - (site_y * 48)); + + CopyMat(out_building->mutable_material(), in_building->item.mat_type, in_building->item.mat_index); + + STRICT_VIRTUAL_CAST_VAR(tower_info, df::site_realization_building_info_castle_towerst, in_building->building_info); + if (tower_info) + { + CopyMat(out_building->mutable_material(), tower_info->wall_item.mat_type, tower_info->wall_item.mat_index); + + auto out_tower = out_building->mutable_tower_info(); + out_tower->set_roof_z(tower_info->roof_z); + out_tower->set_round(tower_info->shape.bits.round); + out_tower->set_goblin(tower_info->shape.bits.goblin); + } + STRICT_VIRTUAL_CAST_VAR(wall_info, df::site_realization_building_info_castle_wallst, in_building->building_info); + if (wall_info) + { + CopyMat(out_building->mutable_material(), wall_info->wall_item.mat_type, wall_info->wall_item.mat_index); + + auto out_wall = out_building->mutable_wall_info(); + + out_wall->set_start_x(wall_info->start_x - (site_x * 48)); + out_wall->set_start_y(wall_info->start_y - (site_y * 48)); + out_wall->set_start_z(wall_info->start_z); + out_wall->set_end_x(wall_info->end_x - (site_x * 48)); + out_wall->set_end_y(wall_info->end_y - (site_y * 48)); + out_wall->set_end_z(wall_info->end_z); + } + } + + } + } } static command_result GetRegionMaps(color_ostream &stream, const EmptyMessage *in, RegionMaps *out) @@ -2535,7 +2533,7 @@ static command_result GetRegionMapsNew(color_ostream &stream, const EmptyMessage df::world_region_details * region = data->region_details[i]; if (!region) continue; - RegionMap * regionMap = out->add_region_maps(); + RegionMap * regionMap = out->add_region_maps(); CopyLocalMap(data, region, regionMap); } return CR_OK; @@ -2720,10 +2718,7 @@ static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage send_tissue->set_name(orig_tissue->tissue_name_singular); send_tissue->set_subordinate_to_tissue(orig_tissue->subordinate_to_tissue); - auto send_mat = send_tissue->mutable_material(); - - send_mat->set_mat_index(orig_tissue->mat_index); - send_mat->set_mat_type(orig_tissue->mat_type); + CopyMat(send_tissue->mutable_material(), orig_tissue->mat_type, orig_tissue->mat_index); } } @@ -2779,9 +2774,7 @@ static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in growth_remote->set_timing_end(growth_local->timing_2); growth_remote->set_trunk_height_start(growth_local->trunk_height_perc_1); growth_remote->set_trunk_height_end(growth_local->trunk_height_perc_2); - auto growthMat = growth_remote->mutable_mat(); - growthMat->set_mat_index(growth_local->mat_index); - growthMat->set_mat_type(growth_local->mat_type); + CopyMat(growth_remote->mutable_mat(), growth_local->mat_type, growth_local->mat_index); } } return CR_OK; From bbaf129adfae4f081468c8bb4e48e2c1bdb9009f Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 27 Aug 2016 15:24:53 -0400 Subject: [PATCH 131/413] Fix ruby codegen for bitfields/enums with long base-type --- plugins/ruby/codegen.pl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/plugins/ruby/codegen.pl b/plugins/ruby/codegen.pl index 3e41f93c9..eb9828490 100755 --- a/plugins/ruby/codegen.pl +++ b/plugins/ruby/codegen.pl @@ -657,6 +657,9 @@ sub get_compound_align { if ($st eq 'bitfield' or $st eq 'enum') { my $base = $field->getAttribute('base-type') || 'uint32_t'; + if ($base eq 'long') { + return $SIZEOF_LONG; + } print "$st type $base\n" if $base !~ /int(\d+)_t/; return $1/8; } @@ -793,9 +796,15 @@ sub sizeof_compound { if ($st eq 'bitfield' or $st eq 'enum') { my $base = $field->getAttribute('base-type') || 'uint32_t'; - print "$st type $base\n" if $base !~ /int(\d+)_t/; - $sizeof_cache{$typename} = $1/8 if $typename; - return $1/8; + if ($base eq 'long') { + $sizeof_cache{$typename} = $SIZEOF_LONG if $typename; + return $SIZEOF_LONG; + } + else { + print "$st type $base\n" if $base !~ /int(\d+)_t/; + $sizeof_cache{$typename} = $1/8 if $typename; + return $1/8; + } } if ($field->getAttribute('is-union')) From 41e298bdfce4c56c5c1a82d45f93dcd0bce66fd0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 27 Aug 2016 15:27:57 -0400 Subject: [PATCH 132/413] Update submodules --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index bb582c8b5..761f2ca80 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit bb582c8b51fddfa9d8c83a3e8d27c205b587180c +Subproject commit 761f2ca80e9eb13aad7f104b8ab218739ea44212 diff --git a/scripts b/scripts index 3e3fb7bff..0a022e862 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 3e3fb7bff6dce41e7ea85ee3addf44291b53f800 +Subproject commit 0a022e862e009b37d06cd0f4e1d4097ae3395ecf From af5d4ec5a838630f80d9879f03a8de5a923fbb1e Mon Sep 17 00:00:00 2001 From: Japa Date: Mon, 29 Aug 2016 21:43:20 +0530 Subject: [PATCH 133/413] removed foreach. --- plugins/remotefortressreader.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 81dc690a1..1ff5cd0e5 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1388,8 +1388,9 @@ void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetB for (int xx = 0; xx < 16; xx++) { auto send_pile = NetBlock->add_spatterpile(); - for each (auto mat in materials) + for (int i = 0; i < materials.size(); i++) { + auto mat = materials[i]; if (mat->amount[xx][yy] == 0) continue; auto send_spat = send_pile->add_spatters(); @@ -1397,8 +1398,9 @@ void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetB CopyMat(send_spat->mutable_material(), mat->mat_type, mat->mat_index); send_spat->set_amount(mat->amount[xx][yy]); } - for each (auto item in items) + for (int i = 0; i < items.size(); i++) { + auto item = items[i]; if (item->amount[xx][yy] == 0) continue; auto send_spat = send_pile->add_spatters(); From 1862106fd10ff44260013ef48448586d7831cc1d Mon Sep 17 00:00:00 2001 From: Japa Date: Mon, 29 Aug 2016 22:29:40 +0530 Subject: [PATCH 134/413] Removed the other foreach. --- plugins/remotefortressreader.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 1ff5cd0e5..6bc7c8173 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -944,13 +944,15 @@ bool IsspatterChanged(DFCoord pos) uint16_t hash = 0; - for each (auto mat in materials) + for (int i = 0; i < materials.size(); i++) { + auto mat = materials[i]; hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_material_spatterst)); } - for each (auto mat in items) + for (int i = 0; i < items.size(); i++) { - hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_item_spatterst)); + auto item = items[i]; + hash ^= fletcher16((uint8_t*)item, sizeof(df::block_square_event_item_spatterst)); } if (spatterHashes[pos] != hash) { From 8f2cc5bc4df1a68c1ea291b8132e95dfff5fa7f3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 4 Sep 2016 16:06:26 -0400 Subject: [PATCH 135/413] Fix and reorganize remotefortressreader includes --- plugins/remotefortressreader.cpp | 176 +++++++++++++++---------------- 1 file changed, 84 insertions(+), 92 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 6bc7c8173..6ad2f3eda 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1,111 +1,102 @@ #define DF_VERSION 42004 -// some headers required for a plugin. Nothing special, just the basics. -#include "Core.h" -#include -#include -#include +#include +#include +#include -// DF data structure definition headers +#include "Console.h" +#include "Core.h" #include "DataDefs.h" -#include "df/world.h" -#include "df/ui.h" -#include "df/item.h" -#include "df/creature_raw.h" -#include "df/caste_raw.h" -#include "df/body_part_raw.h" -#include "df/historical_figure.h" -#include "df/world_history.h" +#include "Export.h" +#include "Hooks.h" +#include "MiscUtils.h" +#include "PluginManager.h" +#include "RemoteFortressReader.pb.h" +#include "RemoteServer.h" +#include "SDL_events.h" +#include "SDL_keyboard.h" +#include "TileTypes.h" -#include "df/job_item.h" -#include "df/job_material_category.h" -#include "df/dfhack_material_category.h" -#include "df/matter_state.h" -#include "df/material_vec_ref.h" -#include "df/builtin_mats.h" -#include "df/map_block_column.h" -#include "df/plant.h" -#include "df/plant_raw_flags.h" -#if DF_VERSION > 40001 -#include "df/plant_tree_info.h" -#include "df/plant_tree_tile.h" -#include "df/plant_growth.h" -#include "df/plant_growth_print.h" -#endif -#include "df/itemdef.h" -#include "df/building_def_workshopst.h" +#include "modules/Buildings.h" +#include "modules/Gui.h" +#include "modules/Items.h" +#include "modules/MapCache.h" +#include "modules/Maps.h" +#include "modules/Materials.h" +#include "modules/Translation.h" +#include "modules/Units.h" +#include "modules/World.h" + +#include "df/army.h" +#include "df/army_flags.h" +#include "df/block_square_event_item_spatterst.h" +#include "df/block_square_event_material_spatterst.h" +#include "df/body_appearance_modifier.h" +#include "df/body_part_layer_raw.h" +#include "df/body_part_raw.h" +#include "df/bp_appearance_modifier.h" +#include "df/building_axle_horizontalst.h" +#include "df/building_bridgest.h" #include "df/building_def_furnacest.h" -#include "df/building_wellst.h" -#include "df/building_water_wheelst.h" +#include "df/building_def_workshopst.h" +#include "df/building_rollersst.h" #include "df/building_screw_pumpst.h" -#include "df/building_axle_horizontalst.h" -#include "df/building_windmillst.h" #include "df/building_siegeenginest.h" -#include "df/building_rollersst.h" -#include "df/building_bridgest.h" - +#include "df/building_water_wheelst.h" +#include "df/building_wellst.h" +#include "df/building_windmillst.h" +#include "df/builtin_mats.h" +#include "df/caste_raw.h" +#include "df/caste_raw.h" +#include "df/color_modifier_raw.h" +#include "df/creature_raw.h" +#include "df/creature_raw.h" #include "df/descriptor_color.h" +#include "df/descriptor_color.h" +#include "df/descriptor_pattern.h" #include "df/descriptor_pattern.h" #include "df/descriptor_shape.h" - -#include "df/physical_attribute_type.h" +#include "df/dfhack_material_category.h" +#include "df/enabler.h" +#include "df/graphic.h" +#include "df/historical_figure.h" +#include "df/item.h" +#include "df/itemdef.h" +#include "df/job_item.h" +#include "df/job_material_category.h" +#include "df/map_block_column.h" +#include "df/material_vec_ref.h" +#include "df/matter_state.h" #include "df/mental_attribute_type.h" -#include "df/color_modifier_raw.h" -#include "df/descriptor_color.h" -#include "df/descriptor_pattern.h" - +#include "df/physical_attribute_type.h" +#include "df/plant.h" +#include "df/plant_raw_flags.h" #include "df/region_map_entry.h" -#include "df/world_region_details.h" -#include "df/world_region.h" -#include "df/army.h" -#include "df/army_flags.h" -#include "df/world_geo_biome.h" -#include "df/world_geo_layer.h" -#include "df/world_population.h" -#include "df/world_site.h" -#include "df/world_site_realization.h" #include "df/site_realization_building.h" #include "df/site_realization_building_info_castle_towerst.h" #include "df/site_realization_building_info_castle_wallst.h" #include "df/site_realization_building_info_trenchesst.h" - -#include "df/unit.h" -#include "df/creature_raw.h" -#include "df/caste_raw.h" #include "df/tissue.h" - -#include "df/enabler.h" -#include "df/graphic.h" - +#include "df/ui.h" +#include "df/unit.h" #include "df/viewscreen_choose_start_sitest.h" +#include "df/world.h" +#include "df/world_data.h" +#include "df/world_geo_biome.h" +#include "df/world_geo_layer.h" +#include "df/world_history.h" +#include "df/world_population.h" +#include "df/world_region.h" +#include "df/world_region_details.h" +#include "df/world_site.h" +#include "df/world_site_realization.h" -#include "df/bp_appearance_modifier.h" -#include "df/body_part_layer_raw.h" -#include "df/body_appearance_modifier.h" - -//DFhack specific headers -#include "modules/Maps.h" -#include "modules/MapCache.h" -#include "modules/Materials.h" -#include "modules/Gui.h" -#include "modules/Translation.h" -#include "modules/Items.h" -#include "modules/Buildings.h" -#include "modules/Units.h" -#include "modules/World.h" -#include "TileTypes.h" -#include "MiscUtils.h" -#include "Hooks.h" -#include "SDL_events.h" -#include "SDL_keyboard.h" - -#include -#include -#include - -#include "RemoteFortressReader.pb.h" - -#include "RemoteServer.h" +#if DF_VERSION > 40001 +#include "df/plant_growth.h" +#include "df/plant_growth_print.h" +#include "df/plant_tree_info.h" +#include "df/plant_tree_tile.h" +#endif using namespace DFHack; using namespace df::enums; @@ -113,7 +104,8 @@ using namespace RemoteFortressReader; using namespace std; DFHACK_PLUGIN("RemoteFortressReader"); -#if DF_VERSION < 40024 + +#ifndef REQUIRE_GLOBAL using namespace df::global; #else REQUIRE_GLOBAL(world); @@ -2502,7 +2494,7 @@ static void CopyLocalMap(df::world_data * worldData, df::world_region_details* w out_wall->set_end_z(wall_info->end_z); } } - + } } } @@ -2603,7 +2595,7 @@ static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage if (!orig_part) continue; auto send_part = send_caste->add_body_parts(); - + send_part->set_token(orig_part->token); send_part->set_category(orig_part->category); send_part->set_parent(orig_part->con_part_id); @@ -2712,7 +2704,7 @@ static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage send_caste->set_description(orig_caste->description); send_caste->set_adult_size(orig_caste->misc.adult_size); } - + for (int j = 0; j < orig_creature->tissue.size(); j++) { auto orig_tissue = orig_creature->tissue[j]; From 36b9ee5cf4f03d09f167a26e787319b59de7c746 Mon Sep 17 00:00:00 2001 From: David Seguin Date: Wed, 7 Sep 2016 23:28:50 -0400 Subject: [PATCH 136/413] Added check to rescan zlib and pthread on linux unset ZLIB_LIBRARY and CMAKE_HAVE_PTHREAD_H to rescan those libs when arch changes from 32 to 64 (and vis-versa). There may be a better way to do this. --- CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a55940eff..3eb6a1927 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,6 +274,16 @@ endif() #### expose depends #### +# check for change in arch (32<->64) +if(UNIX) + GET_PROPERTY(DFHACK_CACHED_ARCH CACHE STRING PROPERTY DFHACK_BUILD_ARCH) + if("${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_CACHED_ARCH}") + # no change + else() + unset(ZLIB_LIBRARY CACHE) + unset(CMAKE_HAVE_PTHREAD_H CACHE) + endif() +endif() # find and make available libz if(NOT UNIX) # Windows From 860e5840060491a73bbf1dcea4201c34b723cef1 Mon Sep 17 00:00:00 2001 From: David Seguin Date: Thu, 8 Sep 2016 11:28:15 -0400 Subject: [PATCH 137/413] Added @lethosor 's change --- CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3eb6a1927..abb188577 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -277,9 +277,7 @@ endif() # check for change in arch (32<->64) if(UNIX) GET_PROPERTY(DFHACK_CACHED_ARCH CACHE STRING PROPERTY DFHACK_BUILD_ARCH) - if("${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_CACHED_ARCH}") - # no change - else() + if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_CACHED_ARCH}") unset(ZLIB_LIBRARY CACHE) unset(CMAKE_HAVE_PTHREAD_H CACHE) endif() From 01a97f6487ea72aaeab94234d28ca627a7ba5f39 Mon Sep 17 00:00:00 2001 From: David Seguin Date: Thu, 8 Sep 2016 17:12:42 -0400 Subject: [PATCH 138/413] Made pthread required for building protobuf --- depends/protobuf/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index 5b54c8335..9846fd4e5 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -68,7 +68,7 @@ IF (HAVE_HASH_MAP EQUAL 0) ENDIF() IF(UNIX) - FIND_PACKAGE(Threads) + FIND_PACKAGE(Threads REQUIRED) ENDIF() CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h") @@ -247,4 +247,4 @@ IF(NOT CMAKE_CROSSCOMPILING) TARGET_LINK_LIBRARIES(protoc-bin protoc) EXPORT(TARGETS protoc-bin FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake ) -ENDIF() \ No newline at end of file +ENDIF() From 1029e0f02a53ab1254298189fd5181c96c9a30cc Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 15 Sep 2016 01:37:07 -0400 Subject: [PATCH 139/413] Fix a few whitespace issues From #992 --- CMakeLists.txt | 2 +- depends/protobuf/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index abb188577..1b77161d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -277,7 +277,7 @@ endif() # check for change in arch (32<->64) if(UNIX) GET_PROPERTY(DFHACK_CACHED_ARCH CACHE STRING PROPERTY DFHACK_BUILD_ARCH) - if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_CACHED_ARCH}") + if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_CACHED_ARCH}") unset(ZLIB_LIBRARY CACHE) unset(CMAKE_HAVE_PTHREAD_H CACHE) endif() diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index 9846fd4e5..59fe3f0d8 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -68,7 +68,7 @@ IF (HAVE_HASH_MAP EQUAL 0) ENDIF() IF(UNIX) - FIND_PACKAGE(Threads REQUIRED) + FIND_PACKAGE(Threads REQUIRED) ENDIF() CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h") From 38cd830abfbed1469d22c8a9cc70bf730871823c Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 15 Sep 2016 01:52:54 -0400 Subject: [PATCH 140/413] Revert "Added check to rescan zlib and pthread on linux" This reverts commit 36b9ee5cf4f03d09f167a26e787319b59de7c746. Ref #992, #982 --- CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b77161d2..a55940eff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,14 +274,6 @@ endif() #### expose depends #### -# check for change in arch (32<->64) -if(UNIX) - GET_PROPERTY(DFHACK_CACHED_ARCH CACHE STRING PROPERTY DFHACK_BUILD_ARCH) - if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_CACHED_ARCH}") - unset(ZLIB_LIBRARY CACHE) - unset(CMAKE_HAVE_PTHREAD_H CACHE) - endif() -endif() # find and make available libz if(NOT UNIX) # Windows From 869e705549ffbe062a885a96586ab774fc86bfdd Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 15 Sep 2016 10:24:57 -0400 Subject: [PATCH 141/413] Re-run zlib and pthread scans on Linux/OS X when the build architecture changes Fixes #982, ref #992 --- CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a55940eff..d25404e27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,6 +274,13 @@ endif() #### expose depends #### +if(UNIX) + # Rescan for pthread and zlib if the build arch changed + if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_BUILD_ARCH_PREV}") + unset(ZLIB_LIBRARY CACHE) + unset(CMAKE_HAVE_PTHREAD_H CACHE) + endif() +endif() # find and make available libz if(NOT UNIX) # Windows @@ -407,3 +414,6 @@ set(CPACK_PACKAGE_FILE_NAME "dfhack-${DFHACK_VERSION}-${DFHACK_PACKAGE_PLATFORM_ INCLUDE(CPack) #INCLUDE(FindSphinx.cmake) + +# Store old build arch +SET(DFHACK_BUILD_ARCH_PREV "${DFHACK_BUILD_ARCH}" CACHE STRING "Previous build architecture" FORCE) From 27d222966504223578684db02eb466abddc85679 Mon Sep 17 00:00:00 2001 From: Quietust Date: Sun, 25 Sep 2016 18:29:57 -0500 Subject: [PATCH 142/413] Fix follow_jmp for 64-bit code - skip REX prefix if found --- library/VTableInterpose.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/library/VTableInterpose.cpp b/library/VTableInterpose.cpp index c547800c2..520d91061 100644 --- a/library/VTableInterpose.cpp +++ b/library/VTableInterpose.cpp @@ -96,12 +96,13 @@ static uint32_t *follow_jmp(void *ptr) { switch (*p) { - case 0xE9: // jmp near rel32 #ifdef DFHACK64 - p += 5 + *(int32_t*)(p+1) + 1; -#else - p += 5 + *(int32_t*)(p+1); + case 0x48: // REX prefix + p++; + break; #endif + case 0xE9: // jmp near rel32 + p += 5 + *(int32_t*)(p+1); break; case 0xEB: // jmp short rel8 p += 2 + *(int8_t*)(p+1); From 888a09bed5c63fb9b5023ac7e3122727b4a4f035 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 26 Sep 2016 17:23:55 -0400 Subject: [PATCH 143/413] Switch to downloading OS X libruby --- plugins/ruby/CMakeLists.txt | 23 +++++++++++++++++------ plugins/ruby/libruby187.osx.tar.gz | Bin 340284 -> 0 bytes plugins/ruby/linux32/.gitignore | 1 + plugins/ruby/linux64/.gitignore | 1 + plugins/ruby/osx32/.gitignore | 1 + plugins/ruby/osx64/.gitignore | 1 + plugins/ruby/win32/.gitignore | 1 + plugins/ruby/win64/.gitignore | 1 + 8 files changed, 23 insertions(+), 6 deletions(-) delete mode 100644 plugins/ruby/libruby187.osx.tar.gz create mode 100644 plugins/ruby/linux32/.gitignore create mode 100644 plugins/ruby/linux64/.gitignore create mode 100644 plugins/ruby/osx32/.gitignore create mode 100644 plugins/ruby/osx64/.gitignore create mode 100644 plugins/ruby/win32/.gitignore create mode 100644 plugins/ruby/win64/.gitignore diff --git a/plugins/ruby/CMakeLists.txt b/plugins/ruby/CMakeLists.txt index dfb0dc3c4..ac5b4a959 100644 --- a/plugins/ruby/CMakeLists.txt +++ b/plugins/ruby/CMakeLists.txt @@ -1,17 +1,28 @@ IF (APPLE) - EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/libruby187.osx.tar.gz - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - SET(RUBYLIB ${CMAKE_CURRENT_BINARY_DIR}/libruby.dylib) + SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/osx${DFHACK_BUILD_ARCH}/libruby.dylib) + SET(RUBYLIB_INSTALL_NAME "libruby.dylib") + IF(${DFHACK_BUILD_ARCH} STREQUAL 64) + MESSAGE("No ruby lib for 64-bit OS X yet") + ELSE() + DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/osx32-libruby187.dylib.gz" + "gz" + ${RUBYLIB}.gz + "e9bc4263557e652121b055a46abb4f97" + ${RUBYLIB} + "3ee5356759f764a440be5b5b44649826") + ENDIF() ELSEIF(UNIX) + SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/linux${DFHACK_BUILD_ARCH}/libruby.so) + SET(RUBYLIB_INSTALL_NAME "libruby.so") EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/libruby187.linux.tar.gz WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) FILE(RENAME ${CMAKE_CURRENT_BINARY_DIR}/libruby1.8.so.1.8.7 ${CMAKE_CURRENT_BINARY_DIR}/libruby.so) - SET(RUBYLIB ${CMAKE_CURRENT_BINARY_DIR}/libruby.so) ELSE() + SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/win${DFHACK_BUILD_ARCH}/libruby.dll) + SET(RUBYLIB_INSTALL_NAME "libruby.dll") EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/msvcrtruby187.tar.gz WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) FILE(RENAME ${CMAKE_CURRENT_BINARY_DIR}/msvcrt-ruby18.dll ${CMAKE_CURRENT_BINARY_DIR}/libruby.dll) - SET(RUBYLIB ${CMAKE_CURRENT_BINARY_DIR}/libruby.dll) ENDIF() IF (APPLE OR UNIX) @@ -35,7 +46,7 @@ INCLUDE_DIRECTORIES("${dfhack_SOURCE_DIR}/depends/tthread") DFHACK_PLUGIN(ruby ruby.cpp LINK_LIBRARIES dfhack-tinythread) ADD_DEPENDENCIES(ruby ruby-autogen-rb) -INSTALL(FILES ${RUBYLIB} DESTINATION ${DFHACK_LIBRARY_DESTINATION}) +INSTALL(FILES ${RUBYLIB} DESTINATION ${DFHACK_LIBRARY_DESTINATION} RENAME ${RUBYLIB_INSTALL_NAME}) INSTALL(DIRECTORY . DESTINATION hack/ruby diff --git a/plugins/ruby/libruby187.osx.tar.gz b/plugins/ruby/libruby187.osx.tar.gz deleted file mode 100644 index 42153395778ff0256aaa65bd297e1724c1236146..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 340284 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

    {LRJPyTp? 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ⅆ(5?^(~B59*x{qOBMnrcv+N2oq)x>;Mhc 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%0A7S~{SD_XNeQDJ{2DIBf4CX1dqoTef$q>>E#$F= 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 diff --git a/plugins/ruby/linux32/.gitignore b/plugins/ruby/linux32/.gitignore new file mode 100644 index 000000000..ef44e3942 --- /dev/null +++ b/plugins/ruby/linux32/.gitignore @@ -0,0 +1 @@ +libruby* diff --git a/plugins/ruby/linux64/.gitignore b/plugins/ruby/linux64/.gitignore new file mode 100644 index 000000000..ef44e3942 --- /dev/null +++ b/plugins/ruby/linux64/.gitignore @@ -0,0 +1 @@ +libruby* diff --git a/plugins/ruby/osx32/.gitignore b/plugins/ruby/osx32/.gitignore new file mode 100644 index 000000000..ef44e3942 --- /dev/null +++ b/plugins/ruby/osx32/.gitignore @@ -0,0 +1 @@ +libruby* diff --git a/plugins/ruby/osx64/.gitignore b/plugins/ruby/osx64/.gitignore new file mode 100644 index 000000000..ef44e3942 --- /dev/null +++ b/plugins/ruby/osx64/.gitignore @@ -0,0 +1 @@ +libruby* diff --git a/plugins/ruby/win32/.gitignore b/plugins/ruby/win32/.gitignore new file mode 100644 index 000000000..ef44e3942 --- /dev/null +++ b/plugins/ruby/win32/.gitignore @@ -0,0 +1 @@ +libruby* diff --git a/plugins/ruby/win64/.gitignore b/plugins/ruby/win64/.gitignore new file mode 100644 index 000000000..ef44e3942 --- /dev/null +++ b/plugins/ruby/win64/.gitignore @@ -0,0 +1 @@ +libruby* From 7abb82b6d10ff7b5698e1dfa313e03ddf0d5fbf6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 26 Sep 2016 17:36:57 -0400 Subject: [PATCH 144/413] Switch to downloading 32-bit libruby on Linux and Windows --- plugins/ruby/CMakeLists.txt | 26 ++++++++++++++++++++------ plugins/ruby/libruby187.linux.tar.gz | Bin 382504 -> 0 bytes plugins/ruby/msvcrtruby187.tar.gz | Bin 387577 -> 0 bytes 3 files changed, 20 insertions(+), 6 deletions(-) delete mode 100644 plugins/ruby/libruby187.linux.tar.gz delete mode 100644 plugins/ruby/msvcrtruby187.tar.gz diff --git a/plugins/ruby/CMakeLists.txt b/plugins/ruby/CMakeLists.txt index ac5b4a959..1377155ec 100644 --- a/plugins/ruby/CMakeLists.txt +++ b/plugins/ruby/CMakeLists.txt @@ -14,15 +14,29 @@ IF (APPLE) ELSEIF(UNIX) SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/linux${DFHACK_BUILD_ARCH}/libruby.so) SET(RUBYLIB_INSTALL_NAME "libruby.so") - EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/libruby187.linux.tar.gz - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - FILE(RENAME ${CMAKE_CURRENT_BINARY_DIR}/libruby1.8.so.1.8.7 ${CMAKE_CURRENT_BINARY_DIR}/libruby.so) + IF(${DFHACK_BUILD_ARCH} STREQUAL 64) + MESSAGE("No ruby lib for 64-bit Linux yet") + ELSE() + DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/linux32-libruby187.so.gz" + "gz" + ${RUBYLIB}.gz + "2d06f5069ff07ea934ecd40db55a4ac5" + ${RUBYLIB} + "b00d8d7086cb39f6fde793f9d89cb2d7") + ENDIF() ELSE() SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/win${DFHACK_BUILD_ARCH}/libruby.dll) SET(RUBYLIB_INSTALL_NAME "libruby.dll") - EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/msvcrtruby187.tar.gz - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - FILE(RENAME ${CMAKE_CURRENT_BINARY_DIR}/msvcrt-ruby18.dll ${CMAKE_CURRENT_BINARY_DIR}/libruby.dll) + IF(${DFHACK_BUILD_ARCH} STREQUAL 64) + MESSAGE("No ruby lib for 64-bit Windows yet") + ELSE() + DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-libruby187.dll.gz" + "gz" + ${RUBYLIB}.gz + "ffc0f1b5b33748e2a36128e90c97f6b2" + ${RUBYLIB} + "482c1c418f4ee1a5f04203eee1cda0ef") + ENDIF() ENDIF() IF (APPLE OR UNIX) diff --git a/plugins/ruby/libruby187.linux.tar.gz b/plugins/ruby/libruby187.linux.tar.gz deleted file mode 100644 index e6e9e86ab39cb8a94305358e29c47983bb536ec9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 382504 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�`(Kx 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%0DUEM4cqv^F`u@qa@fX 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

    @J9yy8A4MslEr`00u~? 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∋}3swm# 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

    ;)cPPOVbV0FyYf-G!cueoO0>F9hXyr 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%0A0vdMFtAxnb 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

    >6%_`~Ui?nS+1)mYvpgH)EXO8sHpnJ%)<-%M zTx~Ps>|&dw0a#H*&1gn!Fp zS$cJAX0r6!(CnO+Uc_k%A2P7x*RjLrg69}JUV##|AGz&c@F#anKz4*-;#gk4`KJuFc%iMp4bFJmyB7b2o7kv3{Z1+ zDinM_d>MgX;`D!>LiICyAZ{*0JD;+XQJhFT#?eGE0sC@pG~;ZOpzrCL`@j+*Pu zZj3S4^L%Df=oZ8&bZ;y-DRgI(LN~k)oXS;jSWMT&f012w2suE;*EdFF{!dqpk^eKP z2ErcSn6^H{v~_OhUj$_I*0gpkLP`AsJF-&ZO{~NW>6_l&r%2CfRQUA@GK5_o)P)F8U(b<+t^`^~`5ioJ2iw~F1gWrnv2d7wvexad1+871U}hs9{a`*9T~ zuQa-320hfuBKx^-BExl1m8@C_j8ELPQ;Pe0vc(b*1AhBaEpLNT#xDx|Jx8|#Yfv5Aoq>*;VCXFOeIwI~TH z2_DFnk!ugH-Tk-CtUJ!lxVMEvyN#hsq2tgcd>Wr5YO=-Jp;RPfxx@qi$F6hAE=C*s z=hALYG$sXr_Rjz|ivs#+`t~2pk}9POLSpdg^*X)X|E>OX@k#wD^OXLi)#H3t&NnwZ zDc4C1>v_M7%>dpXLgwhVf*%|`v&POe-MOFg{4>QTMrq) z;`9fg+~bR>p<@+_{TP1yCkDx7kRr_f!rT~;rQa~f2nP8Yv%u!m2FPc-qtW0RVHjne zgdJZ4!QodLqXVgyr*3yuxb|y+vu{B3ri(H+v_OAzZ3?kCY_C1U?pBwTVHKxUBfWE$ z4IAOlx}Iq(DgBIDT1Y`Zh?dNRqiN&uWQysn%M*Celx ziQhDie#KkQPdGC`r?K!}xjF(Fx|*(?F7UOG0$&qd;Irrg-*G9t{2mov5}kqXZKSRY ztWS)p>*jtW-sxG_Q%t?!!s5?);*SuW_gBM)?~u(B{s>PU@pShA*<1a{<(9pD0J{3q z2L;I9ebK|p6GP$-E4PD9b>UmiGu*18Yp0Fee(S!9==rD>N>im>JR~CZd$g9R5Omt` zU}J=Tg_}uE)`~RgxejN*p>etr5OAj|(SuVzgCGhFc0XHZ_bH&$@x#=9#)8rZI{Hif z7Jd9MU!y>9e`GNuxbQ#sGbImWO729IJS>Ki9g@eyt3htQ0V;y<6EL)x>aaKiWqA6+ z8s7GsLDm9nfH;w}MQX(#tlQiFrMbSdQ9t=>uK(;yV=oxhC6m$xIRloH=DgUI;isz1 zjU33-8@cjNZe&ul5o1FMd?xm`nl)yNX$0j&f@P-egS+(2?$N*Wr-C~D>B?hBB(#7q z6?nvI66$_5eh3`yw3=kPml91f-Hiz*nJ)Yywmj30MznvW*f_&K*6|iR@MHtF;DlY6 zqi{#Ds@P5N>tp)UkALY;zkjVi%{;0roCKE@tw#d;y)DByazS5o7a13tM=Pv0NYpVk~b$I7sm z=@Aki6N0dBGD6KZN#IorpXV*n49gJ)!C31EHA z)WY6sF1*d$Y>6yfXzuxkq7Z*Own?^_uQXCNC&a{qEi*U&lz2(7pZYMPqC4&?^lT`1 zbKe%D^E3AI7blx9Gx`Yto&nbpe&2y=O;%q}-Dt$Bz%I+#$?Spco;#EsnqwPjGB1H9 z^Fm}AfhIE@n#`7cn|qvcCr$JW@SRNZ^do!Vw&%WA`S?e=S0T;)a8FCAIrApb{R+kI z)b&IZLg%43#F#$b*JzGEqij{aQF5vk$_3^-A=pRA;aqv_cgNr zV4&=cP2|VnJ1HcH?g?Z$cX=u94rL%r!5)Bs%em@2RBh(ik1#kB2Rd!iPYpUN5yv~S z<5cf*94`eA;XIr^@^DI!w~bVgzy(S@_IW(1H`zjzU))?-retIYOT4hQ5nV1IrSbpip5{26Vp0<- zh>p1Jy{Tt6`(1URXdBW0#9L3}t#t82k4^uDOgJvDU9mT_FL#T*vw6`hei^#(dJ7JkFy}nD^M2E_PRXxS^X)asp-gYp)Q;*+F4eJuND-_S1nD_VmT`l{J}V$A z>E3(4Gq8wAszOZw4I))mmZx)IzvpIM|Nj1Nv2glkD4SGwh3Y~>-A-e(_O!<&-ewnd zYdBkzcHU{-hV^IBRh`DspO1sKRkTj??1=+htfQ{#T1)qB-^I88g&>@o4Y0L+8Sl=k zu?^-{>rK-D2IX36ij~wt?17=4`+L?=%s5~q+%{tPJx@R4BDZJUd?-PfGHXXR!(t1T z$ffRDw%4Y-a$b!D|DP!5E~>Sw+OwzDU@(Wesi}2ToG8v^R_Wg<*sD_wqO?!;y-xqH z34HeMOe!!GLr%I#oa`7#ecYuE?p>GVN^k~xp$*FO6GA?cp2eBBk8~CmBNG|fBf5_T z*TblK&G{BsaOLYq*nJ3hef# zlxB4zEdl3lR@}u1GJDpf&1AuP&ZNzkoMMZI4f++{lU8|pTF%6!E7Gc^7kth!7TVPu zO-ap?cQE_tZNcCXOBa0foc6LO(>gv*Gs4H%e~~(X(40WV3!_BA#g_3F z%O=f{S?dfAY2>~1o~5SEeRn1CC7vFu4$hhF^0dsde6f-={z;bbf>eo^v^R?(J=W?O zivQM)dM`Bz8971-GR4Ytlb6jleUU*Q#PnljyIiZZ;Y`1VY z7qC_eYMSHZ+RZhdEHyz;LV=kQ2JUS%=WPbd5qK&b zgw+Y0R!eK(WhQH2!M>KUH85E)2wv9Vp{Q+erRLlWyM%LF2Y&*tJ%BHv2e9H~09gl1 zMkp3itaUK^z_`mxlkmWr!fJK0UF=*#Db{1GweAZ`qSm^CTJ64K8`Q!a z+wAgj`(Mdy4;&Z?nUrk%1(gj^*8~4G$u{La!}K?u@Q4ezk`>-d?LHa z&YvO#>mb^FpFx&a-HX`jn2TM~{u#neuLFT1DIj7#$giOof))_2 z)JNCRMv`VzBFx9j)t=%*cJbi*KG8GK7@C?>0j|=HHvJ0i>Dora@;aPE@5;N30S(4o z&vkNd5KW!(tP+2xH?edQT>0IQ{;COcVwYYoR%XqM|HbRC=h0+~5krQ?Le}mIB@kCA zNjSK5GA_KSjCe2|?1H(P@8mxwJtYJQ6N#>qBw8#6kKL+wwVB>DB}g|oP_F=NlyP`D3)Jxu%(h{Dnt%> zx(2<2w3O(Gxy!N{t~`>!oFoT^}6Wl$VACY)-dFYY3XtEy!}D&Hy|mkBnr zF)@am`#$LO7bGG#R{h{Og z#*0WhJSZB-|M7}M3tewtm!PB7xuL(Ipt(tqv`QW-gtrDL=I&@k^i{s7Nud}Ro}M!PMQ3#| zJY>%2G+{=}i??fRME$r&-~;3~RH@XU+MhHA8=LV8LDt3a4vJH!4~-r0naK&rBpY}3 zO#xKY7M*?d6w5r^-{CH1g)oCWbrSQu8uL7f+AP|S=STQ?56wS6@5b|Re*O~AgHN47 z7m<@}k=hMkZh|jgcna;;0=_lB`#qkUo-%UCkh6zBK)ldIio8#gTkFqcl<%n$%Omc7 zNPhO%1!N_$(Zr?tc9Bt{H{o-yo-~i2N&lr!uun02V+44C3q4<*U=RYTs1y~WPezPz zrDk%XBi<7iuq{ZzX}VO%Bu^_+>Rf)>SVK=oDfd=~&OW|u!ZX@YtbuSn1zoA8{i`Y8 zv#P=I@)*+1MiO$MJ%59e;j|(h&UWC}XgPd?`02~9OcqkdX;PMvR&8fWGBL}*Dt^C^ z-Y1ohLTU9#=QH(`sgJCdYIZ8RF*sOhRBzl_{B}}Tx>ujn^+x+n5}OfR0eFvLH7VFO z&N~q?>5JM!U-XTVQzd5ia(NK)UZp;TtX>^@)=@m1oGK_$y=(^TI$=jy3qEm2QiSLBi0RADEv9e7IHRV0y z`ec*hWg$6{x6jbtEo-FfoB)!01oK16R^L{K^o*C=?6ROc#AgTIUaQo?3|fJ`NkWw8 z&q{T`L#$k3$-hD!Fk;E*=ozC-9gt0uB#Z3sa&j29@Keto}s?RWN+tWaC8-~q*?d~-dzys5@Ppu4dE0o}b2~8)%uRzx)e00jypt#`rFDaT zlGaH({-anDS{e+u`MBNheJMjxaHzL~9b|lraOF}VT14X|j5T@TRy<*{OrROd3T1laY zWKJeZ*9=doDat0__ctOF@V}2!07h?%V!((@ z(l5w+Ous%aR+3sR>s&D_ol3ej&K3?MH4wZ zK)>Dg*#hU``=C}eNLqBX6f^PF0Dlvem=X>#8g}$dvY2BFR?3XgQ{731lf<0CNftf2n?VOn{?btpt|zT= zC#ikydm_ouP|knLq?dYcYoj?Y>=ePsgYF6enjXxr6yHkYJZ&z{gi3hd_m+{O9RoWt ztWozNo%#^vz(|2FRTZ#s0le^#&`F-@uONyiCH6&D$^EnnqZ%EmAqnk231pOr_R|X)w4~M9C18dVLG0wsT9&Rr@X&HPr;n! zO3qTL-k*?0d$F3o^yr(SQ8|#0Y;q`N$B9SrwXrJdsT2C(*r&#`$7%`xEcN*<@msRB`$r6FAsF&EoaCESKQ4HMCsJGLKEiwa5e{p?gV4hvFZ#b30AT~eSbhkH9Z$BJcZ~NzHLpndFL~M@ zI+V;*Kz!vxLCc?!Ch|?}Zf=J<-X#u*Vg`^*LHlMNWm9zMzUNW^LHtJe7RIBcmWF6X zgV>{qwzN(A8zbSjlDXg?zO+}1E0C@7Tr6VvtlUviC+iLo6*0ZjbJ zmTt>wJ!cf<$)PL#(xl$ejR-7Ed;C3%WeGMknSkf>Uv2TeW_*vmnR{~QQQh`T=JZ1Q z(~tORMk-BoSSG`PaL}dyjmH8ESmgFbg=9Ilc?9F zwki?FEAG}aa5ocp&y{zJ)Ktav67=h?C_m}~9w!-Yh`YGk^|2@yqV5$V*Y(6lUaVM z+mh(HTOFCE$6PlKld>tW)}bEU=y&*aJkZO#ZIT*W1y<&9FCM6#Gn(oyd>RK$eVb{oU05n zlU!FbapogBXD*QksS0rM5_#oY>fXtJ%1w(wTe+ekqA!eOS{NA1s9|J1DcN6zY>w$s z=9m(P6}u1$jThBC$M$gNVKFi2X_Ir1-2?AEYQIiR5ZBM?FTug1*Z6FX#J(E8Qny_| zL5Kp&;2f2oCivECC?}CXDa@63508+?I)0TVjh8D)=d*fBWh0xiUCD{drmPDo)rOF= zP6@)oi5V#iDeI|V4vnj2J&9vO~OG_cNP)6=_AqNbsbEk`a z+f74Aw|TA>{~}9betNR!(t`YSu|apmpmNgH7JNc?2GUV*t2h9q2lLj|*h1o8u{jW% z%3FXfkU7pu$#Is;`#eMVD&n1Ew7zrjrlvjvZc$g_a{BLwa8UibLM5dEF-c^>&#!VvG#C=20s%scD)J+3EIB2pe{%{~w~m&SyIqV#t^TT}ru`pTyMl5>IRI zR5y(idqchp#`3VE;eB9C8qQ!3WB<)h+w`;D_jPl@(8Wi0{pkC`3R}D2Akuq@?+Ubv zC6umGiC9x$j-aTxM8DcI>^?5OUQ zGK6M@npeg`9n%>RPcWA#1!NGY^9~pnnqG3mqTfF;W&syojQezfh)zy_Gb@mVbt-AWIn5rnb(^F8E?e8-aGLdtNu#MEla1>4%hH=5ypQhm`?g3W~!={erJz_gj( z1AO0$M9j1ri9>}SI!#29<+*TrzP-SLV{x7M{Mt|EiYAZZX#g4z!((( zA5C@7BTjmRm(MX~yYmgPvF{$1w}kZUxm3lz{r9rg>2H&Dzrvh(nL|c+zfcDZGv3?2 zB~AcA)O67W?T^0Li3}*+#+T$D+?UxB_#Ij@6xvg4U+eltA~CS0#-o7BX6=Q(y1c}2 z%MgX79#L3|J(oaNcp-F!?fW+Oq#NN5np1pXPe)Fin?QMbV`9DEK#lg;O+NB9-Oe8z;CWwIwrE64)yYrp@?9P(!+!O2PHEdoNL2QEL`8YH&-ZOLReIY%1 zt+%=677Zxr!3XLgS!=()YqMxqnTtZD1;t`b{xW+}W@$l*c)Ih3u7gVpaGC%TN((S7 z420psO}asU6LtGMaakl%GuOzsYg0QAM$Y$KUFy?c)p~#57^zGudUw;f1Fzz1gth2L zM%}eN{E=uUG?H^pLMCSnk~|_&+_UF?UlHw9&cZFxerZo!hL}sh-+YwOodL_=!2Jja zS$=u4@3g8h63vYX5_;uQv264R)Ja-5(UzW(*F=wfjS#|Zq7xpX3E%Auya+txRW(NT zx$OtWR2)cJBnG-K$5H975I<`k8W++w?h+{P;X7q<`rCtp&%O%pTqxeDe5_(`{$U{x z9bV~x(s%D;)%)|R_C9tP5f$9_+I%^&>c&uAUX_xEFn}}nSm@S$=GMO@ zx?$y#=z?zSZ?3=L!z9OLKR^kU`o&YFjoZ;`%LG;S&;u-YH4xZQY!sl%-QLH~pvrq7 z$9tqKPy=h)e+sEYd$UZ(OyDr>5xUqveRI|Tr;u43*~qb;PP$s{2?6cvEkuK2w)CF$ zHheVJLSJK|$p^X!ntTB|$&CkjR`e-3xJi)C|VoY!~?HlYnyrAN7U$$Gvz3tVYtw8+0sfsM<1|t8I3At}Gp!UMowB%b6c6WQP zTTI9;_Fkdq8ahk(>hnyafACViV@)MwZ}%i=C*Bf>?)$ZA)thMhQFV;q=nmbOK}e=; zwV4M5+7b_pDUygAYO8b?iJ#HXo=`JF?AlH47?5DyxE3aB;Fa+x_;MGcpj6FUDbVFo zy=m+b;i4ErUI&MXqGQdMz{*x>{Y7uj<+rt`zY=)qtrMLo%;-L-q$FhpaLUti1*p_%@Tf$Xjc-D)BiaHHJy3*KLsHh z8<{QI(&DQ_#Pus>p6srQt2R5?XH2 zNj!ni9+xTZ721;hG|Bo5AKaw6SMYM6uKH%un$XfOhF=H8g|zB+=fM@xzU8BDV_c$D zS8zqNU-{@)P8!0023JJ;l#f2GSm&UvQb9BTZOKjuJY>%PJSvXwQ(V5UBH^LZK2&EZ zX9+=&+!zyr;4!hIhW~^J%crw2MYZ7bLI&hqZyGk}wheUGd>_-TT){0)B6@=K_mFC| z@YQImfDT6Z`6T3ULO{4F-yIbc*=5}es4Fd4X_LQcXwXB8MyEH#_3c#e%Rps*?2Kz8E+Su8+SZB^jQuer&)#`We^Pw1=1^1@j){kw03T4?$K);g5vfYnWFj4$$OQ?c8t&G! zY>?WC1HJvL&7$W5uZKdP9vAOJwibH)WgJ_&wMv3+z#hG(l~?>#QR7~D^Il2apgZiv zlf^%zpav8AQQ%SA(WNo6Bnn`cW>;6&SS@tE(4xN86idw^V@#TF=?sT%T@T*sA*lzK z=a!vP$rE&MGi!uaNK%&?p(3d{E_E;BKgCqZ8le(hBeX#3>ZRg9YMvOV3D^e@(z~Q^Mgf+;}b&v%0 z)aj_vEo4L(*{Z3yxX7e4mD3MT2yw#Gvojo1NXA#C_K3{0&#+EDzYkj{w?v;0&5W8q z2>RFUlNn9q!||xD-REnt6;d~lx07`Ph{@54PJ($b{Aq`a3{M)IRB>)YK1P_h&*ppx zWV52WkFb?Rs|?~`&bcR94hS67O(4j;snQB-Ml40v=NtJy|CHH&*@h%(tki^r@8EMg zXQc7}B!h1}zBM^&fBpBklHsPyIox!)He*YpIoz}}Z~)eN@8a$~3GcGW3yD^6S2Ed7 z*rki^%;#+uHaJmxL6=SjB6Q@#``Jq*2kRnuSB9FJ&9-WR&6cxefh3@n^cQEa z$wOcjU7={opW6O?qK9wM{u9i>b)VKDETo4irwk+Q17sKJt|F7lhd9Ir+enb71Y+u6 z!&yuG!y3*^ksGgV`Sbn+3oJT1(Koek7KpEn<$W#6U)y#Ny~+}$Ye@lCp`|~>T0Yx7 z=DU02e*D+F(Jj07+-hB)-CJIo@)as^tdg0=y{Tlct*>YlJJfM^EwO{bVy>e5h>OI| zOq-T|A2I#Na*N4IMrvZ+c2nHWqZWgmSNv?S^8@9?!*$CmxyH9iOEJ5Ww^O$iD;I2$ z9o&{l{<&Q0eTt>tr^ry4N`_g&Y~>*{TgfWn`xwtux-Ntr6JL65W3!?W*kAH?M)^pY zbSfy9mtyZ`$%*bU;}5_%*}JT23=L$4^ z3pYIhP503C$ZV68CiqaDU{GK3SwYC!^T8u~?hZ$QFLU3=a^nH=2h(Yc>$+~%Wvef~ zrks4SHfT0pAK6hNUpk5O3JNGX$>eOdVgT3yDRt=R0N3OAJ+1+{*1p;x`sYg%b&_#A_)~#?`)Bdv$2aBE5Yygo!Zokj{ zA=R_6lA~aI(+2uZC3t^R>dn4Li#z$)2a@8|erqKgbObY9eB_yE#T=^e4h=-SYsYQ0 zT548m7kz-p>vXnG$lUC05`KtyhHA+ybNa!HSfiTY`Bm%DDq;pb7)CZD(0%A_&Yym& zI?1xk>T&L>$Eg2!PDl&6l61R#B)%3_YPI)p|5F;iA)=oHB`pq=5uxru%t>9(E@hyp zsWLEv)?d_ywErBUou{SRsz(z#COenlL2M4mT!dBsT14Ir%ln&Fj}oj$o>7zVliGY- zP}`Dgkjg&kUV-c^dIBZz6XvHkuJpcKmuyijOCE)GgXNBm`Qr5nQw5S)UZ~ZqGtY6F znfrQFPCxtM|0e61>K)RV2h2rX^xfh3Fe*+iQqR(?*E>P@Hr?HD2XOZI}e<8YfcX*0(gdi!lt42>^e1t+W0 zE*}<&+ON2@e}lo%W|A3NBwo)yPo4nd@WB^gN>h!9J7fr} zO%M8_aHNFKklYkApr#*(OR?aOr}e54twJ^p##L7LOBiTT>wK z3_2nBm6!r81L+uGFgsNiOgWXfaeJij^1fFB7stfQv^)+Yk(?(=BT# z8piy|Yv`70aeeD6l0_wl z>Z;q?$?GWis*~bk?}Hx{Z>`wgW{N|tZ>t@X{=jOn;Kn*=!3myGt7Z-Jm2{GKEAr&} z{`a_Droz%07z~+BTo%#o6NMyWqYyI=?4yOS=u(2@=^@y{bQ-r|3o7HiVC;396TSB1 zn@L=_TsyWZmJ{q;B|7#+GwN73in)Pr@O`FwUcq6TXD61(HuJrxeSTv^4@%QkanIz8 zV_MRXBRO zBJ7#^(B=Wtb|~eo~sfTOQ##lW_r0!anp%| zg2?)h6r&}SHCZY4eriuHKX_)?lwELdP+KSiY#ckMnfL?nAKnufAQu3fE9Y2PCpg0r z)qr`XsN|bAeHN{2WHML}c)Qd8I>yk74CU%E4?A2$?L4SyDp1}gu9%vTP&6YH89r-1q*0%;tCr)!OUdpBet<{&Y zP{lHE98X%LN94MM;$N;!(Z{2`whs5JvWR5|K37`x8Nv z*EJ!Ud=QI+D(Ns6f;x}7X9R!gKP=pu&vQ)l{0%V+E*^(6#HO@R>}m+SMR~4_xCACx zp=l2PoBgCYuF)VVIjg+9(lR22SZ%T;@u|n?Jm}&|Z7@>CwE{UwTz>yXBkK+I`x_zG zk8!YE5^-Tp$YUEJV^nT6ig}qLh6_<4f1DX>hpll#~Phhi#6F zZ!`59f#d8ELjJi*Er1A2@}CO^gow#6$X8NMwz-*(^T-z^t}~CHlIQjAX4s=IG)C>H zgKQx6-UM)Auz^-ICb@z4IAyjYiZ|V$)#uF&#V#Ev0vg&4z#WZn-*=WT5AH6{A_&CaS& zJ+O&ZTxPY}Aq!i|oXe z3hm!zI0))aOAh{!GXP-&HrQ9F&&sZjg*Sd5vIB^ARui37YNNix(x!Tcnpjt2^B`E{ zJEFJRnwJ}iZb|$JMqkhS(EK{=Kw7>hO6Zd{b1_)Id9Y2NGx__tq^UcP_nvRWc*TI^ zkX^8Vaz^)WfgA1geTkA!rDs-n28Bv}#$Mwy_L|#9!np?wX5st#eeFQnYBINYlGXDw zw|GmJ5ZAFNS++R)BdPBgA#eEjV=NXSZUTZavTHc^`ICF}Kr6oWD7LZQua01>&cGpy z9-ji+7h+E_T!Pb|m8kzncKWYQL`n<%XwEUX^`I8y3e?OQI4@D(pR?@JYEs%ThC(tZ z$nS`Wfsow^tS~#2AOm{r(Nk7@DN|N_o?rwA5lw$e@r23iUe4*8Z^2CX zP)xmG?0I&jG>p(+9M3=h8D@!}S| z1RF0SJs`gFt)}@tZZXaGFBa2$AF!M`-`g!5M=Co0Wpm`D zAif9Y`3;UR>3_v4=lMCSoM)J{V4e%C=6RlAji2W=FR&FQgufUim>#o8Y{k><7K&Na zXo_WYPqci5t|R6+5oglK1{u5kubtp#RdF+ah)S!aHu3R8f^%$vU6c4R7C%g3dyAHt zJUF(@CY~8fdj_hXXwcWAK*l3*57tpVrojkcVxaow1{r6bLnVnN)h`HABxFC(!1>Vd zB9NVjrh)8X4Kg>$K=A-%_d(MZ*{FXw!drA{;IW_hf<_rP_8+OVN)Fe1kjGAlc<5m4 z*sIKAFICU2pOzNr8Sfi?+E_=&fN)?C0Kt(j5kq}j+%){jgch~MA+AlYcf!C zCu&AY&YgBY-*QG+RcW7nfKG(A>t7Xp(}7-haZb8M2~@juEdhNo#{~3DYAnzK3DoT! z6HuP(>_9!uKs{WIF*mO^KLcHB25KgOq=U1)@1NZ9K4zf9&e)bZNg#+T2GFKBp!ORW zD9hZ^f;gZ-H!+ag4D>`C&DN5i`(+=CLhh`57qR4D@n*OLAJCGXqU&77OHB&Mg(1f$oR{vYc)1t~v+M z0y9wRIe=m&SZf*!RQU%3y=87`%Q=9Sn}J?C2hgWxpeN&i*8Rmm>&-wT;(+Eq$v|Jt zG67vFf%L_hD_h!PZmDTpOQU5=+sr^eHHii4E`h!_0~I%k{ao=vp5RZ+$b2=fCC8Iz zp{GerV(H0#HhQ`>uB9GNG0?YWpzd)km91x>gJz(VxR&Z=pENVj5B6A~DH7 z-nPdQ$~xI?_zW2;#0e>92O?DJKsgL#7}u1%CQxb1aH02aHl;xQ&{%5U{zu-d=-Hb9 z5JJY?EqJY5@K7|@{DD}To$t9Qbom88T z>wC%ismau3C~CFN|6w2637f2zC8JqHrfok{0>8f{NooR`%@aGaadx5eIUisI?kQ5$ zw8m%*^@;pU(W)NgXU_Z3XxxkFcZTZi2^QQ5L!CiqJJTTpF-@x0jMJR^8x6mtF7mzG z#Cy6ES1ry&?qhMs?zYdfZIb!U;s52iXEFETzy1Bcc}M>%<8*CN_9$N~!!jI3Ec->0 z7;6PFBCD+)6o2u2UH%aju|7_a!I<>ORa(G&79dw?aUM^Oy3Q28Ym)GOny%Y(!Ba`+Is=aUm;@kVWIH#GY^qfpO%exn9ct8FMm#gt7bq3lTR2i|#ll!8 z4X2!+4o>z}WlI>&3M;F2wC6oKX|o zX0p*{dvlu>>)*6#J6oIj{NrSil@=)WrbwzLi;<3BHbi3PWDdhoWrCdolw=! zI~$@p6`MA)K_dQ+Kh220^DZ4%JgA-xG^h%#<7=6$Ef&HHGu!+E?D{GgFTGe)-(~3=o@yN@vf$t@V0uZvn ziKHFK5P%fm>I>lGRI+CXzQ20C)%gBD8*CO|#PP(~fj0&AdtX3HwX&rf<66G*gkg|L zx+~Zrg{;O+hel>rl%}x%tH~D5SWMrjtEX>FS^%)$WNY7xLYYYZVwp(30|mfoBLm=g znp5NwLVc6uaUm!M`Ut-!92e`b}e0U5-TQ)?Y6w4(p1-! z>zY#Cow0SlouE29)%A<5+kJxhB-LFQTeq6uvr%1=tYd!T#bpL?cKxST!%gMS6=a*# zTzY3pKBLrXk0IRV`1WEI+%KN`jBoF0?OcfE9<&7@d>ODstV)mWg`}u;WFGa5!UuNw z8cDD5`RXW9cKDQT)^6pU%?YGlFhAK+I*?6srn&+VPZuZ_AQWh0MbRYJnkLv1OOL*( z40I_6qgv#U`3Gj|n0a?BeJUo#7xEAwo@SXkz#b@`+CP|I-Lnq&uLE7GZ3T=G`igb& znN1I_we<5wBs9_5e~Cp`CUs$vyz;^7KznBGv{Id9P2U(sfvE`5f33CY9_*t&=Tuv} zciJpLZ;7sa`T1CqCCk&tgosuz8Hms^aQJ?U#XNjDSHtMbFb-tH_)iLA#!50tV7I4_ z-puRfW*~3+Z|AHP_?Au&=iQH{b^U(N;+j27TjXlJz2*($E=h`PQ#Ut8klM&mXpK^XP|S z{>RhZ{@xW*(U~lh@Xd24TjWK4DCj)~nCWY5`ZfRIEsXQKzaR}6$0-&PL)0FC_q9P{ zUBGg%Ld&K-VRBnz#dAX+4Z=%<#4e`}BvfZl)BTmB?>f$Sm%8tbf7ik9`i^9a_r&aJ z-!#&Tt)ef|ZFb*5U^DW5@6{bP!qwMP^*IJ^vm~7biwrvZQy?xlrd-*FmY?L7TPph& zFTjc5dkS`zg~8*s!Lre(rW(1t>l`Dkz1zpJ^G^PQi%_nl3wgne(ZltJ`&A`NG} z)8oIr^TnC(xX%6#VhYKZUgVeBIX8|us0of|l1e!255>B@<}Udy9q0G(YpL+?5E!tO zG(-$sU%8#pa({mGo>hPEQhqN*yeGJ(UB9mb__{3((YscCOfWq|zE(mWVx!zBFAJ-h^oKi$Cv~B~E z1)qvv7ccjZ(l$kX>@g*}F1Xzf-ZR=g|19l((?70VS~LCQ+pTyyzTMlS?QU6qX1h!#XxLj$`hLCP&eU*AYptB>}r(F-xzIv zxoEy_pgqCUQXOc6GUgr`=jXFfGHzk3Y}oH=ecQy}O2u0xhB(=!ZT$(>_};;4UUgu% z_eRxQNn4fJ1Mlrd)^rN;Oli-CV3q5uPxUzZU45y=;z{z=H}gKF&0Wv87*~pq*L+U4 z3ucG&(Jx4!dzC_KQoDB1u2O1txWAU6w9X+@Gy~5ay0dALw&_8eMYCZTJpvJ@0!tt5 zuesc#W}eQ|(ntx_4L3JDDf6F1V)s-}3U$^Sj>&@zWU6ie3g&@SDJ_1R^{CU@)|F>iy# zyp2-twuv*sKY-5^F}hMy;8ohPMfpZiPJ!?_Yhck_%+cgt^nH_Vfn*r;v$ST8dO^+m zXyUy0OtzS>KQ8v$!Gx$x@?&lF3gPe86Q|W{cP8%gocy zSYnlL8B6TuW%>%fOc&^y_5**oR1VFhpK}qjbvo#zW{p|WmgIS2Qez~p&qin0^i7WI z>=%Pls`#f|FNz&M!DQ+S3|tEjt7y+&aspZ1V5+{-kV!eAM3>n&kpi zl7RBsvTFVai8p^#Hr4FsJx(9?yG7yyf@4PGs+wE`yS^9iB6##KWH~wp5$@_`R?ls_ z>M6H)Eed*yf@@Kr1#_y^ydy;`wh1Zmv15jm2%rAy2pLJ>1@G6TZjGk@Yr5Mkuv%(1 z^LcPIp5N5>SG})|pQ5kvo$P)_CvV|Sitcnoca8*ej;MLHMPs*%?i@U7bO&>V^Y1kA zt-U5)lGj)R!A}jE7_+M}C{9#jN*o^=0@&kg_`DM?=F@e8lyXm8&n}0P`{<y>u)oz4%@=Dh1X2F{^~hup;XFxW^j2AxH)8k*8q{E-)GT}A0DEwJlCKzvw6q&~Q(m@BBb^&DkUCS_9>qVvSC+7nztJ^+Ki*=pT84taF{1U z&4byIHZaD%NX9ApxO@Ea>^@P-_jYaJ1Va|ko-;iMOwUhFFpq)BY5j6z44p9suZ#SP zmK$Sm$T9dg=wo;aPm-`Ms6OWyrZq-PGVT9-jXVF0u5tW+;d;cMtCsRwfPU#qeAriF zP0gw`uPI-Ct<787b9>F9INq#tx%)4TN8?YA$K(&(!nsY(dWhuEu}41PW8_`l78U>7oUzl<ZKGYZjcKxts)vV<0;d>*xJ@Ozq#y^)CW4z-N9^=<* zZRDsZ4XdhufH33~3vQp*i4<#eKruLd<-bkxSa7m6^E>Y-U&J~!CwQlA0|oe;Bh3Zz<BOQPRy z*=F9I|6u%jET{B{PQMqngo)0;t5ze}eaNZ@yXS@BE~|5wC$fXOcxBGrFe9Ak>baY; zU@K#G)?5}s@4JcKUy9y$M(;a_-nUiLeLvplJC)*fCT80QWS;amRojbVmn!pZYASwu z|4_&5^yQb^JlBX%SiM)M-ts`5Xe7TJ!4LDxlZ8-}U*6o)N);WJ(bBzk=Z8<(gTpe( z1Nfo^HsWQsAv49Ce9@zxbv1oLYF-t5uP{pjX!lPx$|siSZNtteE*hVwNvXRGV;C12 zoH^0%oI~+Mq&BfiOv>dLRu?g>3=FFyhSg3CtF<(>OYyYvoowRtf5P)9?YrJD0)-&z zvi62}R7$~_U`vjHI{p8IEq??R&mIG5r9@X?wzqC2W>7Ub%vs(DlN zH**W;YeS8vpn?3j$=4R)#wzfpyE2$pL3g5@=<-Op*c{eRgN1h$1&<4f9(Ju)`rE_L z$+%KTvg%D0-;3S{h#vy;zcc1FHYcp9(%GjjiM;ik&7!|Ugcbf#hE4t0Ov#^&Z8Y75 zwJK-=-#W+kaL0y-`Hl?d2Gz1XY;Q1p43sUiEY8(sb(;&kmnRzA4s&a z)BCg2$%i_*;A!jip8m5E`(Ej}sPAY`M?J_B><|~!A;zckQ(NxEcn$v3vj$oPWc$9O zSxaNU&Kj5?%58l|dsoWMJngRNovH5uN8|QzQ4hm@Px73pOAVg$;|I)h?phto-?2gb zEpNU)+Q#d$jW(-e`TG<9t&O@RMjLm@HojRE%ipg)Ya4v`f`g5>ZB2WD2OMkYq;&L| zWXo_m@rXmrmENCCvEs+r3Ef!&-F*cPmlb%L=n*4BYAc$p>#d&0joA{d?VU!mRe{;^ z?hX!2pt-osY8;Y2^=(O@Rxt(118a`TGw4XsZ7i=v!EEcST&w8Li+JZb^mDe7Bb7N< z(YjMx(S)BTCVT)-_-v!kIrdpCdhU;&-#Vg!cHlQnpD~}`D%3Hj$rtkMXShSk7vdE6 zt;t7Isxrr}gnT&5N8d73moTujzx=Aqx_NxDb*D1rxbelxH4y`jG_1xjK1SfwxEW znz9V=;w1F_*$l;yWccA0Omj&{cgz*X{w7LR<#R&w8|PJbg*sbCu3%he7iR`AlWnluT&3?e&Oo7PJ$?%zS63Q)!DRGo26{lhdF?jAIt|Q7wpg-i zew75T5C&-U0mLN=-ff*V7`u=|Fi^W6c{H2Q)>;Dc^L>{jW1!sH6vvP?binxT&kv68 zx;Zn55#(p70sIZ^s><9n?W96KI7#Dt4jZNvf-JO=p9=z5PotmaP}cK|p@yQ1P_KdO z$DR^vq>#ptAbR6pFK{w*lTtQwM~#d05ZV;tkb?cS0WUnV)p8|@cj?96u(DYq9dU)| z+t*M6ME;!9|9TUh5J0Dy^s$Ml!2ywiry^oDZW6P%HQ~yw1FUi~l)m~HW}bj=&pdQ4 zQ8~!%`HMYQ_q~E+9XaP-0{59tg0QTlsMWtOIyW3rg#L>6%gm#b9t#dm7LwGn7J*wy{$k8%$a+$xy5In- zQhIc$a#9k8-MM-bvE(Qx%}F>bCv^roP)0*~tr@>g`+{A_oMK-%A@+q}b|iC$)1R6M zl%0XDRG@2%j(E=nSW{h>^QkKJNvtV-N^ne87h*~R`#l%d(eM(z>Bs3oI)T$O%YfZz zh=d6mHAJwg%>oAmqaS~jqXUV_oe-4$m$I+xpNah1o^Gq~H**!xIqf>8UqQZG^UdUI zH2gXmj$Osd4(p%Fu5R?a;z}O&(RafiA;wYWQKui#1(dxtiT!6;`(7cw-^ueAXc>+Q z$`|1sU#)tk;q7u@N@_4Eh6ifs2X%O==%NZ_jh~e*& z5+0nCENMTy1imn%J-Nz3(a6TrXW4ASp_2mS3h#m7!~`J;19NM|x6y}>EzBw36@N|0 zRSwpC9K6#ytG`wB`d^fSaFO&W`t~m*_EV0A(?oIb>66%=WTqQiXV9WSt^c{$M3Dis z5*&D<;OP@$Z2!gzWtoId$k)q#GJTSnh{PfX{%j5(;XkVc^fa*6E14~sd~vVNA6@$AW{{KDR8nAPX4w3T`uiQPtj zIez9gDm!IY)-Ry#vPIl>xy5>p?UH&^@DwQao&<;iGYQRG1Mi4`uiqMgYq>?cYZ$Ui z23OGxh>1S`A{LQv$3@@`sN9NsD4Qt8-;ooOEoQXy*65u5EGq&9Mi)tp&JmDk@DlMi zx(A(W)8B3R@1vkZD}?%S<}*T~I3s9fKM@VK6?|AuHg#;;pDLk^ZV+{rp?$jk3}z9& zk-Sy`n=tJPol*Mg6Q-UpaY~vCpuvk4Zj$2II5nBOIZjF72jAv|@SJ)Rdl1a^mI=um zga=6ZXb2D+{us?|35VlAF9K+9ES~j%+rkJxWJ36qu4E--Ap61zd|$BUaWk^R&({4< z(6MaY8R)24Bn0u|1WFUF?E2)&@UYXdT`UkE3XiL!RS=$BhbcV|Q~H>(+j=LM=F?YY z6|~Py=#gD zNX?Ii0zmZe;P_-q%`9`tPL!-5o61_?z3b6T5>2P|k~pGY`DewE|Fbi2BxQiTN0;(E zY_+wuAdL?`*mxy9!+nhr&*(s%C=qCUU6kai?&X>8D$fJ~Hc(XDs0G$0 zS+YIX=}HjYe;<_Zc0^0*wjz^CDU8Apd!KB(rx^?v>ZOe)GLPw5-l>sE?nE|X_Eja+ ze5bnCWx8v_aleJ+bpdk3-A&1KAFy)xlrdIH zR_gSRpoe6qA32yQhwcDyoJ2hV_a-9C#>7l|jVxHHRBfu~!}EWa4#*EX1}!8zn; zVY?(t_=1>n(&6W$JUOPE^kWa8{5Ob6Sf5qS1rj&=qeZXFqHUZPn+tUuegZ+yAk80t zLPzbCRy?-9J%z{>o+0<8m|OTya$xIYlh;f6BaC>^2zQg`5FEsF9kMMB%WwsAj=`r1 zvT~32HyM$UtmO@4ojb^g1wEGnmKw2T)daFDJsF#;GT$X{lW+b7oD=%()=^#NVA5rJ zdj{{0WY)4)aRamrGD)(7Ly~p z;N%s~0OGnU72{Z+d4;FmzuPmk;N(Y_L6(ZChJilO3!lD>=_pd z=2}Cuniib6LbQ9Llh-x?eckS9R&e5aPqI=bfId>Tc0CxVo7w@NzryQQDr%ar9Cn5G z`YdI0*L|6LrqwF7q!c#VLqAW9Hro44wC7zR&R?@!;W2cB+jF~;U#)yy(~4~`j{Pgy zaw|7BwHY_ADWx^l$_X{UIgc^*Fuw|!_kv@p5mG>(_gGti#N7=X*5IUtjnJCUCWCo3*DmJBuI4%luD5vY zhG{(I)V3o+?;wssf;@N17S&r3sB_NzoUXO1#E!GX!pY1(TnMEjs*5>_SFF0pcOrp< zE@pm}e~03&6uauf;_I2??Vj1XfyjaXwU^U2lg?bgX))=22h2(^bRu~|3b6Ow z?=SY;Cyvq=ilcOgzSn#5ME$LzJ_jr8$%n;iP`1uWhFw(fcB^un7ep!+gmVD>@E%pZ z8&Gp>9B4TmYon!T?Yhjyi3!RnWsi9EHQ))UbUbZ@1kfdOjNNllaG*7Ft0%MTK@6;i zX<5@NqzV=_9H%i_tLE8fCD3dMo=}=V_LjQ8sl5Dn@KxNR9@ClDkw!`h>pN+k+FLL4 zcqtTf2HypA5KZBxpq0ESNR85k=r`G_#oahwE2+w*7Y{z8T= zma*Pg{!&xak&c2sQ(3p7RA{q*B;T|t>IDK#(}H)~dhS;8%a!kHnvVAdbpBim4tXEAUX;dsdDqK`T|!?ApQqoAG?8uY z9MTw}?^42vsR5bIR>?0@yxY_)AqnqPZJ}r&lzGqE^!@h4a}@8Cnb0(KvO~?=rY4Bt zO;o-S*i!b$I6fgYuZ(ea&qr}MTl@Ln;;apNE-hH^NP?NPr-}Ad1;x_8EaEOV=Eb`p z;@-)_$lIBjYj@7=FIo$)lzbw;j7G1z%d>REf>%{G8oUbrt>LYWw6IBN?Df7WEY?wX ztWT57r!aXw?m{SYKrbuZObq^>Zzh^r^@zxc&bf%}qff0PI<@0s=3&syjS;QQ^|+-k zH_b;j{H69|3}Py5^QFI(bB5tBjbRt__FC<8`5Kb6s&0EM4*2{q`f0~1L)hErBevO z|MeoKAUvI9WdW-ZtapFSA^m_m-aL_)4T_$8Z#7r67^KT&@Uxl+Ol>G`h%A9i`QmNS zkUR@fQ?*{yz^9x{9@Z|}vUXh28>qNvQzXJ=ew4kBvZ1kMD^YfxQPyRTC|ifJi;S}D zGEue_Wlp24`dd-t!~;9YWd9M%g03{f4q{jI!ddMcGM|Z8XYq(U)c)h_d&L zvhFBrfwGs3veTPISsRr3jIt7xbwJsFjI!A%>x{CyqHwE4SyzUkZ`8|bH;J+lDErYU+lhC_pzLd-tQ=(zpzJfFtP*99 zq3msxLAqb79TsI?l)bPq5*tBe69)$=5S2zifm=!&Vt}e8P{0h-H4dozE(TJ~K(;ub zT-nldW}rh`V}a5n&`V~ZwQ)cd#SFC23{)tA^q?MPUoy}VGtl@rpxHYZ=p8fA&^Vx~ z?F{sx8R(KYpb_$OtIR;wIG}6^w9X7v`FTT3%$9p4&=xb$r*S}iCD1lA(DR?i;;DxO zDl-E;CV?7dpBxgId(A-E=K!iQ16>r?rv*D1=w~xfV@WIuwtc}sznOvdmc+JHFQ?_0 z8E9o(OI0-t)L;gh8xQm=12y^31oTKrES{Eq$3W+qf!y&xwG7nG4AiNFa){$xr1}5F zE`MDfv09eEAWXmD>1=*u_|zoJVsmYGbL};v*8I_jewXpZ%s}sLiJhGCat7*a2AZ*j zde&c*X}>(eJ)84z)Ej=F8F+nul11N6*Gu60Ou)CAfkXL8F-FLhB_=kqO#(TK8)73U zeSQ`;^2^3pAb-hOIK=01K;28u!XXyL0hMn#3x{}mV;pPSc9z9|`^H#OtSvpu;_n&P zQt#5U(5oX3Xo^I^y=G+oyn%ph}9Vc9eB9NnAD= zWh-S_3oa`_*&IE9C}Sgk^L4zrK)(6S`dGweY+#^w%|IUrpvBu{f)u0l zp*69uu3OKqt~I|paeXYYRIgzm#I!JgZixeWbTtEQFt^k-4rsCj+GYl_#Q`mnecEjX zIl|afyQ8 z%s|#SppXPQVFs%FEEZ^+oEFGs2GFN*Knr9`wiPCz=i`8uNg#(A=&?AU+I1%8qXT8f z0qtC8Vm><1Me(0oXJS4&P~+NIAlGLM)Y9Ciy>UQkX1PiSS{Vm4x`=@wuNy#f7*Ix zqd1^zWJ}G=c$ystlrDiJSH1FNvESQrgYF5p~!a(C);$xe*79lZ8^gc zZqW)u`3?0#6TvNpI{nZ#ihe8+mD<#l1gXIwPq?4=a;7|(P?siclgX~&c$&y2&r&OK z&;qqsfrUdJh%YUMih&&F%mMLoFQZWS%Mv{g$iX=M^JpMPIE=iZ-JEd?!pM7XQH_Xt zq%w9=14m?j8`e%9qiq+>kvxXv00X&S-!gvFKl`s$&f?KSD3D#dR%RUcUfqHS!RZDT-_LnnfGJB_nfYc zktky8wj_F+%OLd0)0+XGhRwgBKe^^3@!sv?y~WGKYiH8aXw+ZZm0~Q?oW7fsV7Onm zt{_EUTZ-JbOycaXYXnv+qP~iI$DU&h*;mDlVFA8{ywWl4eROrSJ(F&jymU#)pZ+u_ z8_fb)aUOeZtiq&r%EEVx?wx9fV$jHb=bSzSC*zir+fPsU@gyd#gR{#>o0?@0+OmSz zY{@)2;g*^wLt=zkNNwVui^guV1$KLSC}XNr_fApM8fw+NojRozkF&Dv5$j#=gI$5U zY+T5K$)nD(an(($y>*uRac;a<}d}5E7hnsxv zaz~$j=(cnAU8Kw}3);>j4`N*>C+65m*<0mer}TIQhwa`u;o;B$jt#*^1CCm>WI-0u zc$CtRVp&^+TGa2Os`cev^-;|7zD#f~qy&jboQ3}#iI`$*Ewg%BE=%+d?XD6Y;MzBCEm-Vl zBni8#>2BkaQ0ACwk2C1FD`=aklv1A1qi+tB?`(Etp33hLaaS+K1P8Biskb26;Z7BX zL9n{tI4s%n4~2l$yefj9V)Az|?l0if(sZkZ0>nsPc)xg6ruj8!bC|Lj0rL?!LvgRe zogSPZ6nC+jS5i8FuSlY)o7wB`dZ)hyk!1y{iQgehHbw>#c;-m^)UIk?g|3Az5A62tQr*R7#@G5{FusbKH6ep> z`iOB>fpG@&N_2AGG>r0ZJPaZyCHFntgG*Hl0tF!aiCspQ(R;FQmgtFqM?ZR^6Mg5a zH@OgIBClL@OY~+-TyJJ(P;UfO%`(-!Zpm1R#VP}M4InLdH5pI25ZA9P{9R*&<557@ z?MQKg1hXf1E+&dvv9d8d_Gbz~qsQ8gFz*p?Z zJUOLWrMqvoQxp7Qu}kvuDc!}MHKtm%5;bQ`+lPh!t-!@S>f^RRooA%7Oy$e`WRrfeN!wfhoI-}zKZfKg9B(+2_Q5-cBFDYs%U5##5Rx@TP ziVagvCyL(gcS$QVD=Rg;Ba&#Ef|`PYqEVi4%uorD+k9)Sz4w_t2dww^`~Ls$dA{c< zIkV3?`@Yv+_qArt8qc09e|V1Wyg*8g|1=K4EjZ9q#t@h9M>=of8_}Cq-%Gu@(6>(0 z4*e!~^Vhzb?toli39(+tPY`(eGy(Y!D#7Hh!t4PxVtyNz;G zru-7?p|A1%$}=oikr`vLXmL}zW#B9i4?P0^I=g#sApfmpBhKHuGs$+nh*OjsDt@co z*M=H0@K@THSkulDa!Bqo9z#i}@53wi2}iav1glI7U$FCZh^ZN^UHi>6dj(g{>^x^q zGv9$99`BQFb$^U|AFGS?+-dfVvZO`CriC9?TCZp6N1u;A{PY60DHeoz=OpjhnS3lBk8PoLX2kj%*PIuEYZMae(uF!;Re4u{eS3#q_Um7On38prx!2 zv!;xO5?^`1UlQiHgZkc@P%`59XlxjBFZFf=Fud0Sv^2A$1ne=S1krDpv$1bbdbG)5 z^PHp@Mb67wJR7rTtXZ}5I&Y&o$-Htm6e(lPE3pE#C%zvX={t$Ee-RO7A})lD=N2^2v{4c&J*_fU0ZgB~os|^t7X3LBD(jVTp21$DZijE_bzgf8yjNP6!9*|1Ho&2Z z&a=LQhExH+QA{J_Y{V3G7BOZ8C-~CpSmy=To>-4*SrwYPEa|VbE@hc-k7cNo`F7bk zLzA4OWmSHw!LW3Ir=2Uyyb|B|HYTNGf?Q8RxyrJw1F7!J8qJA3ZysHcrJRcOEl=RF zjT3DcxX+@Z9~=weH^YyH{CCdQV*Ii=9wVtZ*vR>G#7shd1INY;m z3t~*bmzSY${WP@LgLYO!II&v*Czha{tIJ+$_Q#j_R)}Z;QHMNx)F03yx;Wr_O0lp{ zxz3uL;hbc1M}%mWqD`37hO2UfmmPo6rLIKFF@pvDQI6q>s3A=>#NH!0TLaT_>y#GJdEqv7JOXc7o+!C zU-%IK_}EI6_>#LXo<)GjRp;@OfQl48@IR7v|luexqXAsW$ED zr=i?ueen)5d9`5X7VNMGr~`ZH)3aeAhKJJhPuavL{~}C&oHqH<{7x$JI13bKDeBgt zzXzUf0W?usr`c)Yh0zDBFKiCs{XMp{L`f`CoCTOKGn~9`siC_94NaCC8m%=nG`OLp z^oH7bvY~cvw+)Xkd3qw>Mq{>U*Dh|OAzA}{Sp&`z90Tp87Sdj_zA#X#TU>2Oy1-q3 zn&-axZYtn1bR6Zm738Q37(T>>Lm5q%KmG^U;M%qc9ORz`P7oi1lLcGzn!7m??U#8+qXNl*M zMpt=n!$8Y$Tqk4A=ySnvPG%?ItW?7VxVGHtU+9@x3jZpd5fd--A%=GSR+HAL-FAH3 zgrW_KfJ^w7u__3OFQa!kB3wRm)FH*B_Nzvp2dv3?epwDSp~cb>c-W%;cvZ&3j89Y& z!uw?JtP0udy{}5+A6fid@0Rl5IMo<{Tu7%#%-xoe)2Bw612LxgxA$n@5}plL;suHy z!_Q_+@Y(FIoz3g$Y&MAFZ34%;a>6y7&Y!&nl{{a(=tFL$=mY#@HhGL1@=P(W%%ht; zFb}bvq7Lo#zRBuvv0Xk$1NY)yncU?iM~z20-> zfgGZdJf2_c97c%RfZ7OW5`@qSLyEJpD<_iKYcgAFi!hSiFpLCx&6re+L8UX{9ZMr2 z1bEYjn?nRBud@Sw>HK>P`|&3y?XO6Ef*;H)vu+QDpAwV0cof>m@sKN>_n2r zqTSe3GhV7i>{4~dq4!K^5vN%iIz3T`C^xzKDd01nTo0o{Kp$@9_F*M>rlD|tJ7AdF z$0j9;iVl&EH)Zz+G3^HDnWL8rFb*Nik!~D}FBr$WeQcR2){+Q4{(zJi7o0rx3 z)lfUo;jg4}xg~zMqovuPj=nwAp#J%%(Lj{o2pqmO^>qW<7j`aXQn=I`ObySI(u|Jf zUhAs|Fu;I)ITO%P?3?8c$>^Tx!eTtdI-0vGV;zm*h!&`?pnDlf(taQ3vM=Xiw8dMc z4pFj6^$i&4vJs+jtDEF(Br43Mgn<|+3&k%=Yiv1cZ&a3Pf+ZGZL

    jqfU6@(>;lA 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


    S{;v;_#>ii8JX@X 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

    `JS(dJtSzoaTQyR?ijQUw&w_>@C=m(to?uk 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 From caa6a81669be9a2e171223fb8c0d6c3343519599 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 26 Sep 2016 17:46:50 -0400 Subject: [PATCH 145/413] Add ruby library for linux x64 Built by @dseguin: https://github.com/DFHack/dfhack/pull/989 Closes dfhack/dfhack#989 --- plugins/ruby/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/ruby/CMakeLists.txt b/plugins/ruby/CMakeLists.txt index 1377155ec..d028ee998 100644 --- a/plugins/ruby/CMakeLists.txt +++ b/plugins/ruby/CMakeLists.txt @@ -15,7 +15,12 @@ ELSEIF(UNIX) SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/linux${DFHACK_BUILD_ARCH}/libruby.so) SET(RUBYLIB_INSTALL_NAME "libruby.so") IF(${DFHACK_BUILD_ARCH} STREQUAL 64) - MESSAGE("No ruby lib for 64-bit Linux yet") + DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/linux64-libruby187.so.gz" + "gz" + ${RUBYLIB}.gz + "8eb757bb9ada08608914d8ca8906c427" + ${RUBYLIB} + "e8c36a06f031cfbf02def28169bb5f1f") ELSE() DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/linux32-libruby187.so.gz" "gz" From 714ba1a0306b3789259b92d08218a94d75447a1e Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 26 Sep 2016 18:28:59 -0400 Subject: [PATCH 146/413] Warn if ruby library is missing instead of breaking installation --- plugins/ruby/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/ruby/CMakeLists.txt b/plugins/ruby/CMakeLists.txt index d028ee998..bfc41c032 100644 --- a/plugins/ruby/CMakeLists.txt +++ b/plugins/ruby/CMakeLists.txt @@ -65,7 +65,11 @@ INCLUDE_DIRECTORIES("${dfhack_SOURCE_DIR}/depends/tthread") DFHACK_PLUGIN(ruby ruby.cpp LINK_LIBRARIES dfhack-tinythread) ADD_DEPENDENCIES(ruby ruby-autogen-rb) -INSTALL(FILES ${RUBYLIB} DESTINATION ${DFHACK_LIBRARY_DESTINATION} RENAME ${RUBYLIB_INSTALL_NAME}) +IF(EXISTS ${RUBYLIB}) + INSTALL(FILES ${RUBYLIB} DESTINATION ${DFHACK_LIBRARY_DESTINATION} RENAME ${RUBYLIB_INSTALL_NAME}) +ELSE() + MESSAGE(WARNING "Ruby library not found at ${RUBYLIB} - will not be installed") +ENDIF() INSTALL(DIRECTORY . DESTINATION hack/ruby From a5338d2f594de69d903931bd853a141bced1add7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 28 Sep 2016 20:43:02 -0400 Subject: [PATCH 147/413] Fix rebase_delta type mismatch See #984. GCC wasn't complaining about this on x64 for some reason. Also reordered includes. --- library/include/VersionInfo.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/include/VersionInfo.h b/library/include/VersionInfo.h index b3d6c8346..dc959f1db 100644 --- a/library/include/VersionInfo.h +++ b/library/include/VersionInfo.h @@ -25,13 +25,13 @@ distribution. #pragma once -#include "Pragma.h" -#include "Export.h" -/* #include "Types.h" */ +#include #include #include #include -#include + +#include "Export.h" +#include "Pragma.h" namespace DFHack { @@ -53,7 +53,7 @@ namespace DFHack std::map Addresses; std::map VTables; uintptr_t base; - uintptr_t rebase_delta; + intptr_t rebase_delta; std::string version; OSType OS; public: @@ -76,7 +76,7 @@ namespace DFHack }; uintptr_t getBase () const { return base; }; - int getRebaseDelta() const { return rebase_delta; } + intptr_t getRebaseDelta() const { return rebase_delta; } void setBase (const uintptr_t _base) { base = _base; }; void rebaseTo(const uintptr_t new_base) { From 58ed20b25b6019aa95d8e44028bff091050723e2 Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 6 Oct 2016 22:16:40 +0530 Subject: [PATCH 148/413] Send world map snow coverage over remotefortressreader. --- plugins/proto/RemoteFortressReader.proto | 1 + plugins/remotefortressreader.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 36c2442ce..f0fc57a6b 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -524,6 +524,7 @@ message RegionTile repeated SiteRealizationBuilding buildings = 14; repeated MatPair stone_materials = 15; repeated MatPair tree_materials = 16; + optional int32 snow = 17; } message RegionMap diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 6bc7c8173..c3d2e42e5 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -2105,6 +2105,7 @@ static void SetRegionTile(RegionTile * out, df::region_map_entry * e1) plantMat->set_mat_type(419); } } + out->set_snow(e1->snowfall); } static command_result GetWorldMapNew(color_ostream &stream, const EmptyMessage *in, WorldMap *out) From d414e60ff0445b777fe7b01d3f7efa13cceaa087 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Oct 2016 16:57:33 -0400 Subject: [PATCH 149/413] Mention DFHACK_BUILD_ARCH and other settings in Compile.rst --- docs/Compile.rst | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index b693f4cc3..4cea7713b 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -33,8 +33,8 @@ To get the latest development code (develop branch), clone as above and then:: **Important note regarding submodule update and changing branches**: -You must run ``git submodule update`` every time you change Git branch, -for example when switching between master and develop branches and back. +You must run ``git submodule update`` every time you change branches, +such as when switching between the master and develop branches or vice versa. If a submodule only exists on the newer branch, you also need to run ``git submodule update --init``. Failure to do this may result in strange build errors or "not a known DF version" errors. @@ -67,8 +67,12 @@ For lots more details on contributing to DFHack, including pull requests, code f and more, please see `contributing-code`. -Build types -=========== +Build settings +============== + +Build type +---------- + ``cmake`` allows you to pick a build type by changing the ``CMAKE_BUILD_TYPE`` variable:: cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE @@ -78,8 +82,30 @@ Without specifying a build type or 'None', cmake uses the Valid and useful build types include 'Release', 'Debug' and 'RelWithDebInfo'. -'Debug' is not available on Windows, use 'RelWithDebInfo' instead. +'Debug' is not available on Windows; use 'RelWithDebInfo' instead. + +Target architecture (32-bit vs. 64-bit) +--------------------------------------- + +Set DFHACK_BUILD_ARCH to either ``32`` or ``64`` to build a 32-bit or 64-bit +version of DFHack (respectively). The default is currently ``32``, but this may +change, so specifying it explicitly is a good idea. + +:: + + cmake .. -DDFHACK_BUILD_ARCH=32 + +*or* +:: + + cmake .. -DDFHACK_BUILD_ARCH=64 +Other settings +-------------- +There are a variety of other settings which you can find in CMakeCache.txt in +your build folder or by running ``ccmake`` (or another CMake GUI). Most +DFHack-specific settings begin with ``BUILD_`` and control which parts of DFHack +are built. Linux ===== From f6a91c2f30dd482e44bbfced45e31bfa5d915468 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Oct 2016 16:58:08 -0400 Subject: [PATCH 150/413] Log architecture on startup --- library/Core.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Core.cpp b/library/Core.cpp index fb1dd80bb..75fe576f4 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -250,6 +250,7 @@ static string dfhack_version_desc() s << "(release)"; else s << "(development build " << Version::git_description() << ")"; + s << " on " << (sizeof(void*) == 8 ? "x86_64" : "x86"); return s.str(); } From 2806fe73a95f75368e74ac5451abdb024b2bfb50 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Oct 2016 16:59:03 -0400 Subject: [PATCH 151/413] ruby: Support for loading Ruby 2.x libruby Check for rb_float_new and rb_float_new_in_heap, as documented in #271 --- plugins/ruby/ruby.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 340f38c58..276e5052b 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -355,12 +355,14 @@ static int df_loadruby(void) rbloadsym(rb_string_value_ptr); rbloadsym(rb_eval_string_protect); rbloadsym(rb_ary_shift); - rbloadsym(rb_float_new); rbloadsym(rb_num2dbl); rbloadsym(rb_int2inum); rbloadsym(rb_uint2inum); rbloadsym(rb_num2ulong); #undef rbloadsym + if (!((rb_float_new = (decltype(rb_float_new))(LookupPlugin(libruby_handle, "rb_float_new"))) || + (rb_float_new = (decltype(rb_float_new))(LookupPlugin(libruby_handle, "rb_float_new_in_heap"))))) + return 0; return 1; } From 1c20ebe62cb91beae891b76b26cf0429a1f78399 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Oct 2016 17:02:45 -0400 Subject: [PATCH 152/413] Make title-folder work without SDL_WM_GetCaption --- plugins/title-folder.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/title-folder.cpp b/plugins/title-folder.cpp index ee69ccc5a..205f7225a 100644 --- a/plugins/title-folder.cpp +++ b/plugins/title-folder.cpp @@ -63,8 +63,7 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector Date: Sat, 8 Oct 2016 17:05:59 -0400 Subject: [PATCH 153/413] Add dseguin and figment to Authors.rst --- docs/Authors.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 8592dac0e..195b90c44 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -25,6 +25,7 @@ Carter Bray Qartar Chris Dombroski cdombroski Clayton Hughes David Corbett dscorbett +David Seguin dseguin Deon DoctorVanGogh DoctorVanGogh Donald Ruegsegger hashaash @@ -35,6 +36,7 @@ Erik Youngren Artanis Espen Wiborg expwnent expwnent Feng +figment figment gchristopher gchristopher Harlan Playford playfordh Hayati Ayguen hayguen From e6bb7357df6e21ca2ad3d37024193fe25b231a3a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Oct 2016 17:09:23 -0400 Subject: [PATCH 154/413] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 7422b712f..1c1479db1 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 7422b712fcdbb8ee767ff08949329936fc0d8bc9 +Subproject commit 1c1479db1d3f45a187c1f9d355db1b033c32d4ff From ada96b3162380cdcbe717c6589fa0a4f858aa4b1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 10 Oct 2016 09:33:52 -0400 Subject: [PATCH 155/413] Remove GCC version check in protobuf/CMakeLists.txt The only thing this check was used for was disabled, and the root CMakeLists.txt will enforce the minimum GCC version before protobuf is included. --- depends/protobuf/CMakeLists.txt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index 59fe3f0d8..24bac7988 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -2,16 +2,6 @@ PROJECT(protobuf) #Protocol buffers use C++0x hash maps, so we need to look for those. This is a rewrite of stl_hash.m4 in CMake. IF(CMAKE_COMPILER_IS_GNUCC) - EXECUTE_PROCESS(COMMAND ${CMAKE_C_COMPILER} -dumpversion - OUTPUT_VARIABLE GCC_VERSION) - STRING(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) - LIST(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR) - LIST(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR) - #IF(GCC_MAJOR LESS 4 OR (GCC_MAJOR EQUAL 4 AND GCC_MINOR LESS 2)) - #GCC is too old - # SET(STL_HASH_OLD_GCC 1) - #ENDIF() - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") ENDIF() From d5e8b5eeba79c267c823fabe44594966bfbeaf27 Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 13 Oct 2016 19:35:40 +0530 Subject: [PATCH 156/413] Update XML --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 1c1479db1..7422b712f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 1c1479db1d3f45a187c1f9d355db1b033c32d4ff +Subproject commit 7422b712fcdbb8ee767ff08949329936fc0d8bc9 From 980b6dd12f9bc216e3fd1da63513c7e8e0b86124 Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 13 Oct 2016 19:42:40 +0530 Subject: [PATCH 157/413] Update XML again. --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 7422b712f..693d58c85 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 7422b712fcdbb8ee767ff08949329936fc0d8bc9 +Subproject commit 693d58c8588120ad0a179bdd154cf0ce6035c782 From 0c0d68c9eddf8886c9e1216d3db5f20c984d0001 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 14 Oct 2016 08:56:54 -0400 Subject: [PATCH 158/413] Update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 0a022e862..352dc4ac8 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 0a022e862e009b37d06cd0f4e1d4097ae3395ecf +Subproject commit 352dc4ac8a169bf4789448f01d5121c740669400 From 2e290f483741cc24fbe2f877e33149a00e7c8bdc Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 15 Oct 2016 00:18:25 +0530 Subject: [PATCH 159/413] Ignore the new VS version folders. --- build/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/build/.gitignore b/build/.gitignore index 10192a42e..08f9b16d3 100644 --- a/build/.gitignore +++ b/build/.gitignore @@ -1,4 +1,5 @@ VC2010 +VC2015 DF_PATH.txt _CPack_Packages *.tar.* From 9f541481ea8b2267b330501fe3fdc4b9db2a6bef Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 15 Oct 2016 00:37:18 -0400 Subject: [PATCH 160/413] Fix some warnings with GCC -Wall --- library/Core.cpp | 11 +++++------ library/DataDefs.cpp | 2 -- library/LuaApi.cpp | 4 ++-- library/LuaTools.cpp | 1 + library/LuaTypes.cpp | 1 + library/LuaWrapper.cpp | 4 ---- library/PluginManager.cpp | 5 ++--- 7 files changed, 11 insertions(+), 17 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 75fe576f4..6afe907aa 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -300,12 +300,6 @@ static void listScripts(PluginManager *plug_mgr, std::map &pset, } } -static bool fileExists(std::string path) -{ - ifstream script(path.c_str()); - return script.good(); -} - namespace { struct ScriptArgs { const string *pcmd; @@ -1612,16 +1606,19 @@ bool Core::Init() cerr << "Starting IO thread.\n"; // create IO thread thread * IO = new thread(fIOthread, (void *) temp); + (void)IO; } else { cerr << "Starting dfhack.init thread.\n"; thread * init = new thread(fInitthread, (void *) temp); + (void)init; } cerr << "Starting DF input capture thread.\n"; // set up hotkey capture thread * HK = new thread(fHKthread, (void *) temp); + (void)HK; screen_window = new Windows::top_level_window(); screen_window->addChild(new Windows::dfhack_dummy(5,10)); started = true; @@ -1819,6 +1816,7 @@ void Core::Resume() lock_guard lock(d->AccessMutex); assert(d->df_suspend_depth > 0 && d->df_suspend_thread == tid); + (void)tid; if (--d->df_suspend_depth == 0) d->core_cond.Unlock(); @@ -1858,6 +1856,7 @@ void Core::DisclaimSuspend(int level) lock_guard lock(d->AccessMutex); assert(d->df_suspend_depth == level && d->df_suspend_thread == tid); + (void)tid; if (level == 1000000) d->df_suspend_depth = 0; diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index 06f1ac6c9..c9586fcc0 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -271,8 +271,6 @@ virtual_identity *virtual_identity::find(void *vtable) Core &core = Core::getInstance(); std::string name = core.p->doReadClassName(vtable); - virtual_identity *actual = NULL; - auto name_it = name_lookup.find(name); if (name_it != name_lookup.end()) { virtual_identity *p = name_it->second; diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 18b4ab270..47532c17b 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2243,7 +2243,7 @@ static int filesystem_listdir(lua_State *L) return 3; } lua_newtable(L); - for(int i=0;igetNumBits()); return 1; diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 6e7f81102..69fdd734e 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -46,8 +46,6 @@ distribution. using namespace DFHack; using namespace DFHack::LuaWrapper; -static luaL_Reg no_functions[] = { { NULL, NULL } }; - /** * Report an error while accessing a field (index = field name). */ @@ -1594,8 +1592,6 @@ static void RenderTypeChildren(lua_State *state, const std::vectorlock_add(); if(state == PS_LOADED) From 98ab357df0bd50b1f508242d98e2403fe038ba38 Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 15 Oct 2016 10:17:38 +0530 Subject: [PATCH 161/413] Use size_t in both path methods, to avoid warning C4267 --- library/include/df/custom/coord2d_path.methods.inc | 6 +++--- library/include/df/custom/coord_path.methods.inc | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/include/df/custom/coord2d_path.methods.inc b/library/include/df/custom/coord2d_path.methods.inc index c36c5c0fa..623dfe758 100644 --- a/library/include/df/custom/coord2d_path.methods.inc +++ b/library/include/df/custom/coord2d_path.methods.inc @@ -1,13 +1,13 @@ -unsigned size() const { return x.size(); } +size_t size() const { return x.size(); } -coord2d operator[] (unsigned idx) const { +coord2d operator[] (size_t idx) const { if (idx >= x.size()) return coord2d(); else return coord2d(x[idx], y[idx]); } -void erase(unsigned idx) { +void erase(size_t idx) { if (idx < x.size()) { x.erase(x.begin()+idx); y.erase(y.begin()+idx); diff --git a/library/include/df/custom/coord_path.methods.inc b/library/include/df/custom/coord_path.methods.inc index 5421796e3..cc9a67fa1 100644 --- a/library/include/df/custom/coord_path.methods.inc +++ b/library/include/df/custom/coord_path.methods.inc @@ -1,5 +1,5 @@ bool empty() const { return x.empty(); } -unsigned size() const { return x.size(); } +size_t size() const { return x.size(); } void clear() { x.clear(); @@ -7,14 +7,14 @@ void clear() { z.clear(); } -coord operator[] (unsigned idx) const { +coord operator[] (size_t idx) const { if (idx >= x.size()) return coord(); else return coord(x[idx], y[idx], z[idx]); } -void erase(unsigned idx) { +void erase(size_t idx) { if (idx < x.size()) { x.erase(x.begin()+idx); y.erase(y.begin()+idx); From 08cc9f3188e17555ac30df8bf145e63d7e180c44 Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 15 Oct 2016 10:31:38 +0530 Subject: [PATCH 162/413] Cast size_t to int explicitly to avoid compiler warning C4267 --- library/include/DataDefs.h | 2 +- library/include/DataIdentity.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index bccc9b3f5..ed37a91fc 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -398,7 +398,7 @@ int linear_index(const DFHack::enum_list_attr &lst, T val) { inline int linear_index(const DFHack::enum_list_attr &lst, const std::string &val) { for (size_t i = 0; i < lst.size; i++) if (lst.items[i] == val) - return i; + return (int)i; return -1; } diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index 556731e46..62a9ff274 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -319,7 +319,7 @@ namespace df protected: virtual int item_count(void *ptr, CountMode) { - return ((container*)ptr)->size(); + return (int)((container*)ptr)->size(); }; virtual void *item_pointer(type_identity *, void *ptr, int idx) { return &(*(container*)ptr)[idx]; @@ -385,7 +385,7 @@ namespace df } protected: - virtual int item_count(void *ptr, CountMode) { return ((T*)ptr)->size(); } + virtual int item_count(void *ptr, CountMode) { return (int)((T*)ptr)->size(); } virtual void *item_pointer(type_identity *item, void *ptr, int idx) { return &(*(T*)ptr)[idx]; } @@ -410,7 +410,7 @@ namespace df virtual bool insert(void *ptr, int idx, void *item) { return false; } protected: - virtual int item_count(void *ptr, CountMode) { return ((T*)ptr)->size(); } + virtual int item_count(void *ptr, CountMode) { return (int)((T*)ptr)->size(); } virtual void *item_pointer(type_identity *item, void *ptr, int idx) { auto iter = (*(T*)ptr).begin(); for (; idx > 0; idx--) ++iter; @@ -472,7 +472,7 @@ namespace df protected: virtual int item_count(void *ptr, CountMode) { - return ((container*)ptr)->size(); + return (int)((container*)ptr)->size(); } virtual bool get_item(void *ptr, int idx) { return (*(container*)ptr)[idx]; @@ -498,7 +498,7 @@ namespace df protected: virtual int item_count(void *ptr, CountMode cm) { - return cm == COUNT_WRITE ? 0 : ((container*)ptr)->size; + return cm == COUNT_WRITE ? 0 : (int)((container*)ptr)->size; } virtual void *item_pointer(type_identity *item, void *ptr, int idx) { return (void*)&((container*)ptr)->items[idx]; From 7f7102f90c0c061926702237a5b385450c02f7c5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 15 Oct 2016 12:07:50 -0400 Subject: [PATCH 163/413] Distribute a gunzip.pl script gunzip isn't reliably available on Windows, but IO::Uncompress::Gunzip should be. Suggested by Quietust. --- CMake/DownloadFile.cmake | 4 +++- depends/gunzip.pl | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100755 depends/gunzip.pl diff --git a/CMake/DownloadFile.cmake b/CMake/DownloadFile.cmake index 1a8a40562..8f9938f90 100644 --- a/CMake/DownloadFile.cmake +++ b/CMake/DownloadFile.cmake @@ -31,7 +31,9 @@ function(download_file_unzip URL ZIP_TYPE ZIP_DEST ZIP_MD5 UNZIP_DEST UNZIP_MD5) if(EXISTS "${ZIP_DEST}") message("* Decompressing ${FILENAME}") if("${ZIP_TYPE}" STREQUAL "gz") - execute_process(COMMAND gunzip --force "${ZIP_DEST}") + execute_process(COMMAND + "${PERL_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/depends/gunzip.pl" + "${ZIP_DEST}" --force) else() message(SEND_ERROR "Unknown ZIP_TYPE: ${ZIP_TYPE}") endif() diff --git a/depends/gunzip.pl b/depends/gunzip.pl new file mode 100755 index 000000000..4a21daafd --- /dev/null +++ b/depends/gunzip.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use IO::Uncompress::Gunzip qw(gunzip $GunzipError); + +my %args = map { $_ => 1 } @ARGV; + +my $in_file = $ARGV[0] or die "no input file"; +# remove extension +(my $out_file = $in_file) =~ s{\.[^.]+$}{}; + +if (! -f $in_file) { + die "input file does not exist: \"$in_file\"\n"; +} +if (-f $out_file and !exists($args{'--force'})) { + die "output file exists, not overwriting: \"$out_file\""; +} + +gunzip $in_file => $out_file or die "gunzip failed: $GunzipError\n"; From 8a138fcc4cc3d68222c255541736fc7e27627adb Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 15 Oct 2016 14:53:10 -0400 Subject: [PATCH 164/413] Avoid polluting global namespace in MapCache.h --- library/include/modules/MapCache.h | 6 +++--- plugins/Brushes.h | 11 +++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/library/include/modules/MapCache.h b/library/include/modules/MapCache.h index b1d411ab8..b64cc7859 100644 --- a/library/include/modules/MapCache.h +++ b/library/include/modules/MapCache.h @@ -38,8 +38,6 @@ distribution. #include "df/item.h" #include "df/inclusion_type.h" -using namespace DFHack; - namespace df { struct world_region_details; } @@ -47,6 +45,8 @@ namespace df { namespace MapExtras { +using namespace DFHack; + class DFHACK_EXPORT MapCache; class Block; @@ -626,4 +626,4 @@ private: std::map blocks; }; } -#endif \ No newline at end of file +#endif diff --git a/plugins/Brushes.h b/plugins/Brushes.h index 99e9e4125..eaf4240ea 100644 --- a/plugins/Brushes.h +++ b/plugins/Brushes.h @@ -152,10 +152,11 @@ public: class FloodBrush : public Brush { public: - FloodBrush(Core *c){c_ = c;}; + FloodBrush(DFHack::Core *c){c_ = c;}; ~FloodBrush(){}; coord_vec points(MapExtras::MapCache & mc, DFHack::DFCoord start) { + using namespace DFHack; coord_vec v; std::stack to_flood; @@ -198,19 +199,21 @@ public: return "flood"; } private: - void maybeFlood(DFCoord c, std::stack &to_flood, MapExtras::MapCache &mc) { + void maybeFlood(DFHack::DFCoord c, std::stack &to_flood, + MapExtras::MapCache &mc) { if (mc.testCoord(c)) { to_flood.push(c); } } - Core *c_; + DFHack::Core *c_; }; -command_result parseRectangle(color_ostream & out, +DFHack::command_result parseRectangle(DFHack::color_ostream & out, vector & input, int start, int end, int & width, int & height, int & zLevels, bool hasConsole = true) { + using namespace DFHack; int newWidth = 0, newHeight = 0, newZLevels = 0; if (end > start + 1) From 4c21bbd5aed028a9378b3d952044c368c947eb2f Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 15 Oct 2016 14:55:48 -0400 Subject: [PATCH 165/413] Add Lua::TableInsert() helper --- library/include/LuaTools.h | 8 ++++++++ plugins/confirm.cpp | 13 +++---------- plugins/dwarfmonitor.cpp | 16 ++++------------ 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index c8237eb56..e1d828271 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -341,6 +341,14 @@ namespace DFHack {namespace Lua { DFHACK_EXPORT int PushPosXYZ(lua_State *state, df::coord pos); DFHACK_EXPORT int PushPosXY(lua_State *state, df::coord2d pos); + template + inline void TableInsert(lua_State *state, T_Key key, T_Value value) + { + Lua::Push(state, key); + Lua::Push(state, value); + lua_settable(state, -3); + } + DFHACK_EXPORT void CheckPen(lua_State *L, Screen::Pen *pen, int index, bool allow_nil = false, bool allow_color = true); DFHACK_EXPORT bool IsCoreContext(lua_State *state); diff --git a/plugins/confirm.cpp b/plugins/confirm.cpp index 3ea5d540c..b9927f4ea 100644 --- a/plugins/confirm.cpp +++ b/plugins/confirm.cpp @@ -176,19 +176,12 @@ namespace conf_lua { { Lua::Push(l_state, val); } - template - void table_set (lua_State *L, KeyType k, ValueType v) - { - Lua::Push(L, k); - Lua::Push(L, v); - lua_settable(L, -3); - } namespace api { int get_ids (lua_State *L) { lua_newtable(L); for (auto it = confirmations.begin(); it != confirmations.end(); ++it) - table_set(L, it->first, true); + Lua::TableInsert(L, it->first, true); return 1; } int get_conf_data (lua_State *L) @@ -199,8 +192,8 @@ namespace conf_lua { { Lua::Push(L, i++); lua_newtable(L); - table_set(L, "id", it->first); - table_set(L, "enabled", it->second->is_enabled()); + Lua::TableInsert(L, "id", it->first); + Lua::TableInsert(L, "enabled", it->second->is_enabled()); lua_settable(L, -3); } return 1; diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 8e2a88611..2c78c0854 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -187,14 +187,6 @@ namespace dm_lua { return safe_call(nargs); } - template - void table_set (lua_State *L, KeyType k, ValueType v) - { - Lua::Push(L, k); - Lua::Push(L, v); - lua_settable(L, -3); - } - namespace api { int monitor_state (lua_State *L) { @@ -229,7 +221,7 @@ namespace dm_lua { } } lua_newtable(L); - #define WTYPE(type, name) dm_lua::table_set(L, #type, type); + #define WTYPE(type, name) Lua::TableInsert(L, #type, type); WEATHER_TYPES #undef WTYPE #undef WEATHER_TYPES @@ -242,9 +234,9 @@ namespace dm_lua { { Lua::Push(L, i); lua_newtable(L); - dm_lua::table_set(L, "value", misery[i]); - dm_lua::table_set(L, "color", monitor_colors[i]); - dm_lua::table_set(L, "last", (i == 6)); + Lua::TableInsert(L, "value", misery[i]); + Lua::TableInsert(L, "color", monitor_colors[i]); + Lua::TableInsert(L, "last", (i == 6)); lua_settable(L, -3); } return 1; From 16c77efb43aded0c4ba62928983d9fc0c2f98f3d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 15 Oct 2016 16:05:33 -0400 Subject: [PATCH 166/413] Fix whitespace issues --- plugins/proto/RemoteFortressReader.proto | 38 ++++++++++++------------ scripts | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index f0fc57a6b..3ca15e0ec 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -188,15 +188,15 @@ enum MatterState message Spatter { - optional MatPair material = 1; - optional int32 amount = 2; - optional MatterState state = 3; - optional MatPair item = 4; + optional MatPair material = 1; + optional int32 amount = 2; + optional MatterState state = 3; + optional MatPair item = 4; } message SpatterPile { - repeated Spatter spatters = 1; + repeated Spatter spatters = 1; } message MapBlock @@ -225,7 +225,7 @@ message MapBlock repeated int32 tree_y = 22; repeated int32 tree_z = 23; repeated TileDigDesignation tile_dig_designation = 24; - repeated SpatterPile spatterPile = 25; + repeated SpatterPile spatterPile = 25; } message MatPair { @@ -475,21 +475,21 @@ message SiteRealizationBuildingWall message SiteRealizationBuildingTower { optional int32 roof_z = 1; - optional bool round = 2; - optional bool goblin = 3; + optional bool round = 2; + optional bool goblin = 3; } message TrenchSpoke { - optional int32 mound_start = 1; - optional int32 trench_start = 2; - optional int32 trench_end = 3; - optional int32 mound_end = 4; + optional int32 mound_start = 1; + optional int32 trench_start = 2; + optional int32 trench_end = 3; + optional int32 mound_end = 4; } message SiteRealizationBuildingTrenches { - repeated TrenchSpoke spokes = 1; + repeated TrenchSpoke spokes = 1; } message SiteRealizationBuilding @@ -503,7 +503,7 @@ message SiteRealizationBuilding optional MatPair material = 7; optional SiteRealizationBuildingWall wall_info = 8; optional SiteRealizationBuildingTower tower_info = 9; - optional SiteRealizationBuildingTrenches trench_info = 10; + optional SiteRealizationBuildingTrenches trench_info = 10; } message RegionTile @@ -519,11 +519,11 @@ message RegionTile optional int32 salinity = 9; optional RiverTile river_tiles = 10; optional int32 water_elevation = 11; - optional MatPair surface_material = 12; - repeated MatPair plant_materials = 13; + optional MatPair surface_material = 12; + repeated MatPair plant_materials = 13; repeated SiteRealizationBuilding buildings = 14; - repeated MatPair stone_materials = 15; - repeated MatPair tree_materials = 16; + repeated MatPair stone_materials = 15; + repeated MatPair tree_materials = 16; optional int32 snow = 17; } @@ -725,4 +725,4 @@ message KeyboardEvent optional uint32 mod = 6; optional uint32 unicode = 7; } - + diff --git a/scripts b/scripts index 352dc4ac8..de9962079 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 352dc4ac8a169bf4789448f01d5121c740669400 +Subproject commit de996207994e4ce3e221c010c9cc042b06620a2e From 55d2f00555c482191456fc93e8ffbcba30f36e69 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 15 Oct 2016 16:37:16 -0400 Subject: [PATCH 167/413] Update NEWS.rst and Plugins.rst --- NEWS.rst | 40 ++++++++++++++++++++++++++++++++++++---- docs/Plugins.rst | 6 ++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 0715ccae4..dd16cef7d 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -33,8 +33,31 @@ Changelog DFHack future ============= +Internals +--------- +- 64-bit support on all platforms +- Visual Studio 2015 now required on Windows instead of 2010 +- GCC 4.8 recommended on Linux and OS X (and now supported on OS X) +- Several structure fixes to match 64-bit DF's memory layout + +Lua +--- +- Lua has been updated to 5.3 - see http://www.lua.org/manual/5.3/readme.html for details + + - Floats are no longer implicitly converted to integers in DFHack API calls + +- ``df.new()`` supports more types: ``char``, ``intptr_t``, ``uintptr_t``, ``long``, ``unsigned long`` +- String representations of vectors and a few other containers now include their lengths + +Ruby +---- +- Added support for loading ruby 2.x libraries +- Fixed some layouts on x64 (incomplete) + New Plugins ----------- +- `dwarfvet` enables animal caretaking +- `labormanager` (formerly autolabor2): a more advanced alternative to `autolabor` - `title-folder`: shows DF folder name in window title bar when enabled New Scripts @@ -43,7 +66,20 @@ New Scripts Fixes ----- +- The DF path on OS X can now contain spaces and ``:`` characters - Buildings::setOwner() changes now persist properly when saved +- `devel/find-offsets`: fixed a crash when vtables used by globals aren't available + +Misc Improvements +----------------- +- `lua` and `gui/gm-editor` now support the same aliases (``scr``, ``unit``, etc.) +- `remotefortressreader`: Added support for + + - world map snow coverage + - spatters + - wall info + - site towers, world buildings + - surface material DFHack 0.43.03-r1 ================= @@ -52,10 +88,6 @@ Lua --- - Label widgets can now easily register handlers for mouse clicks -New Plugins ------------ -- `dwarfvet` enables animal caretaking. - New Features ------------ - `add-thought`: allow syndrome name as ``-thought`` argument diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 7746b8b51..90533aa96 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -818,6 +818,12 @@ Examples: ``autolabor CUTWOOD disable`` Turn off autolabor for wood cutting. +.. _labormanager: + +labormanager +============ +A more advanced alternative to `autolabor`. + .. _autohauler: autohauler From 4d74090b34b10fc64d72d2aa56242ea161e56f71 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 15 Oct 2016 17:27:02 -0400 Subject: [PATCH 168/413] Bump version in CMakeLists.txt --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d25404e27..1cae58c8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,8 +137,8 @@ endif() # set up versioning. set(DF_VERSION "0.43.05") -SET(DFHACK_RELEASE "alpha0") -SET(DFHACK_PRERELEASE FALSE) +SET(DFHACK_RELEASE "alpha1") +SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 0e0da1edbe0dd6ae264019cda7ee3ee8b47da684 Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 16 Oct 2016 06:32:35 +0530 Subject: [PATCH 169/413] Update windows build scripts to reflect the new folder structure. --- build/win32/generate-MSVC-all-breakfast.bat | 2 +- build/win32/generate-MSVC-all.bat | 2 +- build/win32/generate-MSVC-gui.bat | 2 +- build/win32/generate-MSVC-minimal.bat | 2 +- build/win32/generate-MSVC-release.bat | 2 +- build/win64/generate-MSVC-all-breakfast.bat | 2 +- build/win64/generate-MSVC-all.bat | 2 +- build/win64/generate-MSVC-gui.bat | 2 +- build/win64/generate-MSVC-minimal.bat | 2 +- build/win64/generate-MSVC-release.bat | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build/win32/generate-MSVC-all-breakfast.bat b/build/win32/generate-MSVC-all-breakfast.bat index 4ef5ed677..ac26c4f75 100644 --- a/build/win32/generate-MSVC-all-breakfast.bat +++ b/build/win32/generate-MSVC-all-breakfast.bat @@ -6,4 +6,4 @@ cd VC2015_32 echo generating a build folder rem for /f "delims=" %%a in ('DATE /T') do @set myvar=breakfast-%BUILD_NUMBER% set myvar=breakfast-%BUILD_NUMBER% -cmake ..\.. -G"Visual Studio 14" -DDFHACK_RELEASE="%myvar%" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 +cmake ..\..\.. -G"Visual Studio 14" -DDFHACK_RELEASE="%myvar%" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 diff --git a/build/win32/generate-MSVC-all.bat b/build/win32/generate-MSVC-all.bat index 106913925..254492f2e 100755 --- a/build/win32/generate-MSVC-all.bat +++ b/build/win32/generate-MSVC-all.bat @@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2015_32 cd VC2015_32 echo generating a build folder -cmake ..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 +cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 diff --git a/build/win32/generate-MSVC-gui.bat b/build/win32/generate-MSVC-gui.bat index fe4503717..514f894e7 100755 --- a/build/win32/generate-MSVC-gui.bat +++ b/build/win32/generate-MSVC-gui.bat @@ -3,5 +3,5 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2015_32 cd VC2015_32 echo Pre-generating a build folder -cmake ..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" +cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" cmake-gui . diff --git a/build/win32/generate-MSVC-minimal.bat b/build/win32/generate-MSVC-minimal.bat index ae0187d02..e42072d05 100755 --- a/build/win32/generate-MSVC-minimal.bat +++ b/build/win32/generate-MSVC-minimal.bat @@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2015_32 cd VC2015_32 echo generating a build folder -cmake ..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=0 -DBUILD_DFUSION=0 -DBUILD_STONESENSE=0 -DBUILD_SERVER=0 +cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=0 -DBUILD_DFUSION=0 -DBUILD_STONESENSE=0 -DBUILD_SERVER=0 diff --git a/build/win32/generate-MSVC-release.bat b/build/win32/generate-MSVC-release.bat index eeecad111..9735a1469 100755 --- a/build/win32/generate-MSVC-release.bat +++ b/build/win32/generate-MSVC-release.bat @@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2015_32 cd VC2015_32 echo generating a build folder -cmake ..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 +cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 diff --git a/build/win64/generate-MSVC-all-breakfast.bat b/build/win64/generate-MSVC-all-breakfast.bat index edf540f48..8fd64caaf 100644 --- a/build/win64/generate-MSVC-all-breakfast.bat +++ b/build/win64/generate-MSVC-all-breakfast.bat @@ -6,4 +6,4 @@ cd VC2015 echo generating a build folder rem for /f "delims=" %%a in ('DATE /T') do @set myvar=breakfast-%BUILD_NUMBER% set myvar=breakfast-%BUILD_NUMBER% -cmake ..\.. -G"Visual Studio 14 Win64" -T v140_xp -DDFHACK_RELEASE="%myvar%" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 +cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DDFHACK_RELEASE="%myvar%" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 diff --git a/build/win64/generate-MSVC-all.bat b/build/win64/generate-MSVC-all.bat index c34e03d70..a27f12697 100755 --- a/build/win64/generate-MSVC-all.bat +++ b/build/win64/generate-MSVC-all.bat @@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2015 cd VC2015 echo generating a build folder -cmake ..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 +cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 diff --git a/build/win64/generate-MSVC-gui.bat b/build/win64/generate-MSVC-gui.bat index e798897c6..c9f35ff4a 100755 --- a/build/win64/generate-MSVC-gui.bat +++ b/build/win64/generate-MSVC-gui.bat @@ -3,5 +3,5 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2015 cd VC2015 echo Pre-generating a build folder -cmake ..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" +cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" cmake-gui . diff --git a/build/win64/generate-MSVC-minimal.bat b/build/win64/generate-MSVC-minimal.bat index 895215a27..ea57b99f6 100755 --- a/build/win64/generate-MSVC-minimal.bat +++ b/build/win64/generate-MSVC-minimal.bat @@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2015 cd VC2015 echo generating a build folder -cmake ..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=0 -DBUILD_DFUSION=0 -DBUILD_RUBY=0 -DBUILD_STONESENSE=0 -DBUILD_SERVER=0 +cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=0 -DBUILD_DFUSION=0 -DBUILD_RUBY=0 -DBUILD_STONESENSE=0 -DBUILD_SERVER=0 diff --git a/build/win64/generate-MSVC-release.bat b/build/win64/generate-MSVC-release.bat index b84c85cdd..7a564a1d1 100755 --- a/build/win64/generate-MSVC-release.bat +++ b/build/win64/generate-MSVC-release.bat @@ -3,4 +3,4 @@ IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF mkdir VC2015 cd VC2015 echo generating a build folder -cmake ..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 +cmake ..\..\.. -G"Visual Studio 14 Win64" -T v140_xp -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1 From b04083690e5dd6ceb02fc67ee7729acf09893eb0 Mon Sep 17 00:00:00 2001 From: Japa Date: Mon, 17 Oct 2016 19:48:24 +0530 Subject: [PATCH 170/413] Update .gitignore to ignore the 32bit build folder --- build/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/build/.gitignore b/build/.gitignore index 08f9b16d3..3ee46f78e 100644 --- a/build/.gitignore +++ b/build/.gitignore @@ -1,5 +1,6 @@ VC2010 VC2015 +VC2015_32 DF_PATH.txt _CPack_Packages *.tar.* From b1e3c1088ca84fa30c2e548f8cd2258155bc3e8d Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 19 Oct 2016 09:51:48 -0400 Subject: [PATCH 171/413] Give loadfile() result a better name for tracebacks --- library/lua/dfhack.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 900607c08..340b6ce64 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -543,23 +543,23 @@ function dfhack.run_script_with_env(envVars, name, flags, ...) end env.dfhack_flags = flags env.moduleMode = flags.module - local f + local script_code local perr local time = dfhack.filesystem.mtime(file) if time == scripts[file].mtime and scripts[file].run then - f = scripts[file].run + script_code = scripts[file].run else --reload - f, perr = loadfile(file, 't', env) - if not f then + script_code, perr = loadfile(file, 't', env) + if not script_code then error(perr) end -- avoid updating mtime if the script failed to load scripts[file].mtime = time end scripts[file].env = env - scripts[file].run = f - return f(...), env + scripts[file].run = script_code + return script_code(...), env end local function _run_command(...) From b19a0b4305331a98e130f4085902d88c3cbad097 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 19 Oct 2016 09:52:15 -0400 Subject: [PATCH 172/413] Update scripts, xml Fixes #1005 --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 693d58c85..81e2cf023 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 693d58c8588120ad0a179bdd154cf0ce6035c782 +Subproject commit 81e2cf023422ad6f01061db12586a0589ef6eac5 diff --git a/scripts b/scripts index de9962079..b285334a8 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit de996207994e4ce3e221c010c9cc042b06620a2e +Subproject commit b285334a8a91c0b43bac9d3e362b95fcbfa472c7 From 919507d9a0f7fa639182410d80c3b3a8638de465 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 19 Oct 2016 20:00:30 +0530 Subject: [PATCH 173/413] Send over dig designations from un-taken job postings in remotefortressreader.cpp. --- plugins/remotefortressreader.cpp | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index d0272b854..b0f64b680 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -62,6 +62,8 @@ #include "df/historical_figure.h" #include "df/item.h" #include "df/itemdef.h" +#include "df/job.h" +#include "df/job_type.h" #include "df/job_item.h" #include "df/job_material_category.h" #include "df/map_block_column.h" @@ -1334,6 +1336,54 @@ void CopyDesignation(df::map_block * DfBlock, RemoteFortressReader::MapBlock * N } } } + for (int i = 0; i < world->job_postings.size(); i++) + { + auto job = world->job_postings[i]->job; + if (job == nullptr) + continue; + if ( + job->pos.z > DfBlock->map_pos.z + || job->pos.z < DfBlock->map_pos.z + || job->pos.x >= (DfBlock->map_pos.x + 16) + || job->pos.x < (DfBlock->map_pos.x) + || job->pos.y >= (DfBlock->map_pos.y + 16) + || job->pos.y < (DfBlock->map_pos.y) + ) + continue; + + int index = (job->pos.x - DfBlock->map_pos.x) + (16 * (job->pos.y - DfBlock->map_pos.y)); + + switch (job->job_type) + { + case job_type::Dig: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); + break; + case job_type::CarveUpwardStaircase: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::UP_STAIR_DIG); + break; + case job_type::CarveDownwardStaircase: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DOWN_STAIR_DIG); + break; + case job_type::CarveUpDownStaircase: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::UP_DOWN_STAIR_DIG); + break; + case job_type::CarveRamp: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::RAMP_DIG); + break; + case job_type::DigChannel: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::CHANNEL_DIG); + break; + case job_type::FellTree: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); + break; + case job_type::GatherPlants: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); + break; + default: + break; + } + } + } void CopyBuildings(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) From adad7e75c399609ffec4cb9bdbb0e129c0b3e99c Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 19 Oct 2016 20:00:56 +0530 Subject: [PATCH 174/413] Ignore df_path. again. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 5ef3ce759..4d3986c67 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,7 @@ tags # Mac OS X .DS_Store files .DS_Store + +#VS is annoying about this one. +/build/win64/DF_PATH.txt +/build/win32/DF_PATH.txt From 701adc12b3ff837d0894c89874e2deb2941fc096 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 19 Oct 2016 22:21:50 +0530 Subject: [PATCH 175/413] Add ability for remotefortressreader.cpp to accept dig designations. --- plugins/CMakeLists.txt | 2 +- plugins/proto/RemoteFortressReader.proto | 12 +++++++ plugins/remotefortressreader.cpp | 41 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index a81d0993a..9522491dd 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -124,7 +124,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(prospector prospector.cpp) DFHACK_PLUGIN(power-meter power-meter.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(regrass regrass.cpp) - DFHACK_PLUGIN(RemoteFortressReader remotefortressreader.cpp PROTOBUFS RemoteFortressReader) + DFHACK_PLUGIN(RemoteFortressReader remotefortressreader.cpp proto/RemoteFortressReader.proto PROTOBUFS RemoteFortressReader) DFHACK_PLUGIN(rename rename.cpp LINK_LIBRARIES lua PROTOBUFS rename) add_subdirectory(rendermax) DFHACK_PLUGIN(resume resume.cpp) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 3ca15e0ec..4c049d1a9 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -117,6 +117,13 @@ enum TileDigDesignation UP_STAIR_DIG = 6; } +message Coord +{ + optional int32 x = 1; + optional int32 y = 2; + optional int32 z = 3; +} + message Tiletype { required int32 id = 1; @@ -726,3 +733,8 @@ message KeyboardEvent optional uint32 unicode = 7; } +message DigCommand +{ + optional TileDigDesignation designation = 1; + repeated Coord locations = 2; +} \ No newline at end of file diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index b0f64b680..afd7e2dc7 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -140,6 +140,7 @@ static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in, PlantRawList *out); static command_result CopyScreen(color_ostream &stream, const EmptyMessage *in, ScreenCapture *out); static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEvent *in); +static command_result SendDigCommand(color_ostream &stream, const DigCommand *in); void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos); @@ -243,6 +244,7 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("GetPlantRaws", GetPlantRaws); svc->addFunction("CopyScreen", CopyScreen); svc->addFunction("PassKeyboardEvent", PassKeyboardEvent); + svc->addFunction("SendDigCommand", SendDigCommand); return svc; } @@ -2856,3 +2858,42 @@ static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEve SDL_PushEvent(&e); return CR_OK; } + +static command_result SendDigCommand(color_ostream &stream, const DigCommand *in) +{ + MapExtras::MapCache mc; + + for (int i = 0; i < in->locations.locations_size(); i++) + { + auto pos = in->locations(i); + auto des = mc.designationAt(DFCoord(pos.x(), pos.y(), pos.z())); + switch (in->designation()) + { + case NO_DIG: + des.bits.dig = tile_dig_designation::No; + break; + case DEFAULT_DIG: + des.bits.dig = tile_dig_designation::Default; + break; + case UP_DOWN_STAIR_DIG: + des.bits.dig = tile_dig_designation::UpDownStair; + break; + case CHANNEL_DIG: + des.bits.dig = tile_dig_designation::Channel; + break; + case RAMP_DIG: + des.bits.dig = tile_dig_designation::Ramp; + break; + case DOWN_STAIR_DIG: + des.bits.dig = tile_dig_designation::DownStair; + break; + case UP_STAIR_DIG: + des.bits.dig = tile_dig_designation::UpStair; + break; + default: + break; + } + mc.setDesignationAt(DFCoord(pos.x(), pos.y(), pos.z()), des); + } + return CR_OK; +} \ No newline at end of file From e3ff89ba03b143acf8030324fa46869f3f0c013c Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 19 Oct 2016 16:21:38 -0400 Subject: [PATCH 176/413] Fix compile error --- plugins/remotefortressreader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index afd7e2dc7..bbf998704 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -2863,7 +2863,7 @@ static command_result SendDigCommand(color_ostream &stream, const DigCommand *in { MapExtras::MapCache mc; - for (int i = 0; i < in->locations.locations_size(); i++) + for (int i = 0; i < in->locations_size(); i++) { auto pos = in->locations(i); auto des = mc.designationAt(DFCoord(pos.x(), pos.y(), pos.z())); @@ -2896,4 +2896,4 @@ static command_result SendDigCommand(color_ostream &stream, const DigCommand *in mc.setDesignationAt(DFCoord(pos.x(), pos.y(), pos.z()), des); } return CR_OK; -} \ No newline at end of file +} From b3ff4814610dfc2ad8ecec1cf626eea452321526 Mon Sep 17 00:00:00 2001 From: James Logsdon Date: Wed, 19 Oct 2016 20:55:14 -0400 Subject: [PATCH 177/413] Add documentation for manipulator professions --- docs/Plugins.rst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index ba502c38e..7882d0298 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -405,7 +405,7 @@ military and social skills. .. image:: images/manipulator2.png -Press :kbd:`t` to toggle between Profession and Squad view. +Press :kbd:`t` to toggle between Profession, Squad, and Job views. .. image:: images/manipulator3.png @@ -440,6 +440,20 @@ The following mouse shortcuts are also available: Pressing :kbd:`Esc` normally returns to the unit screen, but :kbd:`Shift`:kbd:`Esc` would exit directly to the main dwarf mode screen. +Professions +----------- + +The manipulator plugin supports saving Professions: a named set of Labors labors that can be +quickly applied to one or multiple Dwarves. + +To save a Profession highlight a Dwarf and press :kbd:`P`. The Profession will be saved using +the Custom Profession Name of the Dwarf, or the default for that Dwarf if no Custom Profession +Name has been set. + +To apply a Profession either highlight a single Dwarf, or select multiple with :kbd:`x`, and press +:kbd:`p` to select the Profession to apply. All labors for the selected Dwarves will be reset to +the labors of the chosen Profession. + .. comment - the link target "search" is reserved for the Sphinx search page .. _search-plugin: From 951d2930500781698ed0b1dd74045d34459521dc Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Thu, 25 Aug 2016 10:28:07 +1000 Subject: [PATCH 178/413] Add, use, and require auto docs for all keybindings --- NEWS.rst | 2 + conf.py | 105 +++++++++++++++++++++++++++++++++++++++++------ docs/Plugins.rst | 34 ++++++++++++--- 3 files changed, 123 insertions(+), 18 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index dd16cef7d..b7e80cf77 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -72,6 +72,8 @@ Fixes Misc Improvements ----------------- +- Documented all default keybindings (from :file:`dfhack.init-example`) in the + docs for the relevant commands; updates enforced by build system. - `lua` and `gui/gm-editor` now support the same aliases (``scr``, ``unit``, etc.) - `remotefortressreader`: Added support for diff --git a/conf.py b/conf.py index dc033016f..b3f8949e7 100644 --- a/conf.py +++ b/conf.py @@ -15,15 +15,70 @@ serve to show the default. # pylint:disable=redefined-builtin -import fnmatch from io import open -from itertools import starmap import os import re import shlex # pylint:disable=unused-import import sys +# -- Support :dfhack-keybind:`command` ------------------------------------ +# this is a custom directive that pulls info from dfhack.init-example + +from docutils import nodes +from docutils.parsers.rst import roles + + +def get_keybinds(): + """Get the implemented keybinds, and return a dict of + {tool: [(full_command, keybinding, context), ...]}. + """ + with open('dfhack.init-example') as f: + lines = [l.replace('keybinding add', '').strip() for l in f.readlines() + if l.startswith('keybinding add')] + keybindings = dict() + for k in lines: + first, command = k.split(' ', maxsplit=1) + bind, context = (first.split('@') + [''])[:2] + if ' ' not in command: + command = command.replace('"', '') + tool = command.split(' ')[0].replace('"', '') + keybindings[tool] = keybindings.get(tool, []) + [ + (command, bind.split('-'), context)] + return keybindings + +KEYBINDS = get_keybinds() + + +# pylint:disable=unused-argument,dangerous-default-value,too-many-arguments +def dfhack_keybind_role_func(role, rawtext, text, lineno, inliner, + options={}, content=[]): + """Custom role parser for DFHack default keybinds.""" + roles.set_classes(options) + if text not in KEYBINDS: + msg = inliner.reporter.error( + 'no keybinding for {} in dfhack.init-example'.format(text), + line=lineno) + prb = inliner.problematic(rawtext, rawtext, msg) + return [prb], [msg] + newnode = nodes.paragraph() + for cmd, key, ctx in KEYBINDS[text]: + n = nodes.paragraph() + newnode += n + n += nodes.strong('Keybinding: ', 'Keybinding: ') + for k in key: + n += nodes.inline(k, k, classes=['kbd']) + if cmd != text: + n += nodes.inline(' -> ', ' -> ') + n += nodes.literal(cmd, cmd, classes=['guilabel']) + if ctx: + n += nodes.inline(' in ', ' in ') + n += nodes.literal(ctx, ctx) + return [newnode], [] + + +roles.register_canonical_role('dfhack-keybind', dfhack_keybind_role_func) + # -- Autodoc for DFhack scripts ------------------------------------------- def doc_dir(dirname, files): @@ -46,28 +101,41 @@ def doc_dir(dirname, files): command = line +def doc_all_dirs(): + """Collect the commands and paths to include in our docs.""" + scripts = [] + for root, _, files in os.walk('scripts'): + scripts.extend(doc_dir(root, files)) + return tuple(scripts) + +DOC_ALL_DIRS = doc_all_dirs() + + def document_scripts(): """Autodoc for files with the magic script documentation marker strings. Returns a dict of script-kinds to lists of .rst include directives. """ - # First, we collect the commands and paths to include in our docs - scripts = [] - for root, _, files in os.walk('scripts'): - scripts.extend(doc_dir(root, files)) # Next we split by type and create include directives sorted by command kinds = {'base': [], 'devel': [], 'fix': [], 'gui': [], 'modtools': []} - for s in scripts: + for s in DOC_ALL_DIRS: k_fname = s[0].split('/', 1) if len(k_fname) == 1: kinds['base'].append(s) else: kinds[k_fname[0]].append(s) - template = '.. _{}:\n\n.. include:: /{}\n' +\ - ' :start-after: {}\n :end-before: {}\n' - return {key: '\n\n'.join(starmap(template.format, sorted(value))) + + def template(arg): + tmp = '.. _{}:\n\n.. include:: /{}\n' +\ + ' :start-after: {}\n :end-before: {}\n' + if arg[0] in KEYBINDS: + tmp += '\n:dfhack-keybind:`{}`\n'.format(arg[0]) + return tmp.format(*arg) + + return {key: '\n\n'.join(map(template, sorted(value))) for key, value in kinds.items()} + def write_script_docs(): """ Creates a file for eack kind of script (base/devel/fix/gui/modtools) @@ -97,10 +165,23 @@ def write_script_docs(): outfile.write(kinds[k]) -# Actually call the docs generator -write_script_docs() +def all_keybinds_documented(): + """Check that all keybindings are documented with the :dfhack-keybind: + directive somewhere.""" + configured_binds = set(KEYBINDS) + script_commands = set(i[0] for i in DOC_ALL_DIRS) + with open('./docs/Plugins.rst') as f: + plugin_binds = set(re.findall(':dfhack-keybind:`(.*?)`', f.read())) + undocumented_binds = configured_binds - script_commands - plugin_binds + if undocumented_binds: + raise ValueError('The following DFHack commands have undocumented' + 'keybindings: {}'.format(sorted(undocumented_binds))) +# Actually call the docs generator and run test +write_script_docs() +all_keybinds_documented() + # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 90533aa96..54a9ccb81 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -353,7 +353,8 @@ This plugin adds an option to the :kbd:`q` menu when `enabled `. command-prompt ============== An in-game DFHack terminal, where you can enter other commands. -Best used from a keybinding; by default :kbd:`Ctrl`:kbd:`Shift`:kbd:`P`. + +:dfhack-keybind:`command-prompt` Usage: ``command-prompt [entry]`` @@ -372,13 +373,11 @@ Otherwise somewhat similar to `gui/quickcmd`. hotkeys ======= Opens an in-game screen showing which DFHack keybindings are -active in the current context. +active in the current context. See also `hotkey-notes`. .. image:: images/hotkeys.png -Type ``hotkeys`` into the DFHack console to open the screen, -or bind the command to a globally active hotkey. The default -keybinding is :kbd:`Ctrl`:kbd:`F1`. See also `hotkey-notes`. +:dfhack-keybind:`hotkeys` .. _rb: @@ -659,12 +658,16 @@ Unit order examples:: The orderings are defined in ``hack/lua/plugins/sort/*.lua`` +:dfhack-keybind:`sort-units` + .. _stocks: stocks ====== Replaces the DF stocks screen with an improved version. +:dfhack-keybind:`stocks` + .. _stocksettings: .. _stockpiles: @@ -676,6 +679,7 @@ See `gui/stockpiles` for an in-game interface. :copystock: Copies the parameters of the currently highlighted stockpile to the custom stockpile settings and switches to custom stockpile placement mode, effectively allowing you to copy/paste stockpiles easily. + :dfhack-keybind:`copystock` :savestock: Saves the currently highlighted stockpile's settings to a file in your Dwarf Fortress folder. This file can be used to copy settings between game saves or @@ -874,7 +878,7 @@ Invoked as:: job-material -Intended to be used as a keybinding: +:dfhack-keybind:`job-material` * In :kbd:`q` mode, when a job is highlighted within a workshop or furnace, changes the material of the job. Only inorganic materials can be used @@ -887,6 +891,8 @@ job-duplicate In :kbd:`q` mode, when a job is highlighted within a workshop or furnace building, calling ``job-duplicate`` instantly duplicates the job. +:dfhack-keybind:`job-duplicate` + .. _autogems: autogems @@ -1076,6 +1082,8 @@ spotclean Works like ``clean map snow mud``, but only for the tile under the cursor. Ideal if you want to keep that bloody entrance ``clean map`` would clean up. +:dfhack-keybind:`spotclean` + .. _autodump: autodump @@ -1098,10 +1106,16 @@ Options: :destroy-here: As ``destroy``, but only the selected item in the :kbd:`k` list, or inside a container. Alias ``autodump-destroy-here``, for keybindings. + :dfhack-keybind:`autodump-destroy-here` :visible: Only process items that are not hidden. :hidden: Only process hidden items. :forbidden: Only process forbidden items (default: only unforbidden). +``autodump-destroy-item`` destroys the selected item, which may be selected +in the :kbd:`k` list, or inside a container. If called again before the game +is resumed, cancels destruction of the item. +:dfhack-keybind:`autodump-destroy-item` + cleanowned ========== @@ -1139,6 +1153,8 @@ Options: :prefs: Show dwarf preferences summary :reload: Reload configuration file (``dfhack-config/dwarfmonitor.json``) +:dfhack-keybind:`dwarfmonitor` + Widget configuration: The following types of widgets (defined in :file:`hack/lua/plugins/dwarfmonitor.lua`) @@ -1264,6 +1280,8 @@ zone ==== Helps a bit with managing activity zones (pens, pastures and pits) and cages. +:dfhack-keybind:`zone` + Options: :set: Set zone or cage under cursor as default for future assigns. @@ -1738,6 +1756,8 @@ Basic commands: to remove designations, for if you accidentally set 50 levels at once. :diglx: Also cross z-levels, digging stairs as needed. Alias for ``digl x``. +:dfhack-keybind:`digv` + .. _digexp: digexp @@ -2209,6 +2229,8 @@ Usage: * When viewing unit details, body-swaps into that unit. * In the main adventure mode screen, reverts transient swap. +:dfhack-keybind:`adv-bodyswap` + .. _createitem: createitem From f170b70fde3e5dfca7e9b98123c2ac2c8087a7f6 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Fri, 2 Sep 2016 20:43:04 +1000 Subject: [PATCH 179/413] Expand plugin docs for workNow --- docs/Plugins.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 54a9ccb81..37cad8a94 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -1242,7 +1242,16 @@ Options: workNow ======= -Force all dwarves to look for a job immediately, or as soon as the game is unpaused. +Don't allow dwarves to idle if any jobs are available. + +When workNow is active, every time the game pauses, DF will make dwarves +perform any appropriate available jobs. This includes when you one step +through the game using the pause menu. Usage: + +:workNow: print workNow status +:workNow 0: deactivate workNow +:workNow 1: activate workNow (look for jobs on pause, and only then) +:workNow 2: make dwarves look for jobs whenever a job completes .. _seedwatch: From 75d7773a945d66e3cdda4c6c84685a7f93abff58 Mon Sep 17 00:00:00 2001 From: Jon Pamala Illo Date: Fri, 21 Oct 2016 10:26:20 +0530 Subject: [PATCH 180/413] Move set_df_path.vbs into the directories where it's actually useful. --- build/{ => win32}/set_df_path.vbs | 0 build/win64/set_df_path.vbs | 32 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) rename build/{ => win32}/set_df_path.vbs (100%) create mode 100644 build/win64/set_df_path.vbs diff --git a/build/set_df_path.vbs b/build/win32/set_df_path.vbs similarity index 100% rename from build/set_df_path.vbs rename to build/win32/set_df_path.vbs diff --git a/build/win64/set_df_path.vbs b/build/win64/set_df_path.vbs new file mode 100644 index 000000000..1d494a2e5 --- /dev/null +++ b/build/win64/set_df_path.vbs @@ -0,0 +1,32 @@ +Option Explicit + +Const BIF_returnonlyfsdirs = &H0001 + +Dim wsh, objDlg, objF, fso, spoFile +Set objDlg = WScript.CreateObject("Shell.Application") +Set objF = objDlg.BrowseForFolder (&H0,"Select your DF folder", BIF_returnonlyfsdirs) + +Set fso = CreateObject("Scripting.FileSystemObject") +If fso.FileExists("DF_PATH.txt") Then + fso.DeleteFile "DF_PATH.txt", True +End If + +If IsValue(objF) Then + If InStr(1, TypeName(objF), "Folder") > 0 Then + Set spoFile = fso.CreateTextFile("DF_PATH.txt", True) + spoFile.WriteLine(objF.Self.Path) + End If +End If + +Function IsValue(obj) + ' Check whether the value has been returned. + Dim tmp + On Error Resume Next + tmp = " " & obj + If Err <> 0 Then + IsValue = False + Else + IsValue = True + End If + On Error GoTo 0 +End Function \ No newline at end of file From f586692ed67371272f134f2c993913a9b56e2a5c Mon Sep 17 00:00:00 2001 From: jj Date: Fri, 21 Oct 2016 14:52:26 +0200 Subject: [PATCH 181/413] plugins/ruby: update for 64bits --- plugins/ruby/codegen.pl | 30 ++++++------ plugins/ruby/ruby-autogen-defs.rb | 79 ++++++++++++++++++++++++------- plugins/ruby/ruby.cpp | 60 +++++++++++++++++++---- 3 files changed, 126 insertions(+), 43 deletions(-) diff --git a/plugins/ruby/codegen.pl b/plugins/ruby/codegen.pl index eb9828490..3a9db2c61 100755 --- a/plugins/ruby/codegen.pl +++ b/plugins/ruby/codegen.pl @@ -227,7 +227,7 @@ sub render_global_class { $seen_class{$name}++; local $compound_off = 0; - $compound_off = 4 if ($meta eq 'class-type'); + $compound_off = $SIZEOF_PTR if ($meta eq 'class-type'); $compound_off = sizeof($global_types{$parent}) if $parent; local $current_typename = $rbname; @@ -244,7 +244,7 @@ sub render_global_class { indent_rb { my $sz = sizeof($type); # see comment is sub sizeof ; but gcc has sizeof(cls) aligned - $sz = align_field($sz, 4) if $os eq 'linux' and $meta eq 'class-type'; + $sz = align_field($sz, $SIZEOF_PTR) if $os eq 'linux' and $meta eq 'class-type'; push @lines_rb, "sizeof $sz\n"; push @lines_rb, "rtti_classname :$rtti_name\n" if $rtti_name; @@ -425,8 +425,8 @@ sub render_class_vmethods_voff { for my $meth ($vms->findnodes('child::vmethod')) { - $voff += 4 if $meth->getAttribute('is-destructor') and $os eq 'linux'; - $voff += 4; + $voff += $SIZEOF_PTR if $meth->getAttribute('is-destructor') and $os eq 'linux'; + $voff += $SIZEOF_PTR; } return $voff; @@ -470,8 +470,8 @@ sub render_class_vmethods { } # on linux, the destructor uses 2 entries - $voff += 4 if $meth->getAttribute('is-destructor') and $os eq 'linux'; - $voff += 4; + $voff += $SIZEOF_PTR if $meth->getAttribute('is-destructor') and $os eq 'linux'; + $voff += $SIZEOF_PTR; } } @@ -598,14 +598,14 @@ sub align_field { sub get_field_align { my ($field) = @_; - my $al = 4; + my $al = $SIZEOF_PTR; my $meta = $field->getAttribute('ld:meta'); if ($meta eq 'number') { $al = sizeof($field); - # linux aligns int64_t to 4, windows to 8 + # linux aligns int64_t to $SIZEOF_PTR, windows to 8 # floats are 4 bytes so no pb - $al = 4 if ($al > 4 and ($os eq 'linux' or $al != 8)); + $al = 4 if ($al > 4 and (($os eq 'linux' and $arch == 32) or $al != 8)); } elsif ($meta eq 'global') { $al = get_global_align($field); } elsif ($meta eq 'compound') { @@ -800,11 +800,9 @@ sub sizeof_compound { $sizeof_cache{$typename} = $SIZEOF_LONG if $typename; return $SIZEOF_LONG; } - else { - print "$st type $base\n" if $base !~ /int(\d+)_t/; - $sizeof_cache{$typename} = $1/8 if $typename; - return $1/8; - } + print "$st type $base\n" if $base !~ /int(\d+)_t/; + $sizeof_cache{$typename} = $1/8 if $typename; + return $1/8; } if ($field->getAttribute('is-union')) @@ -820,11 +818,11 @@ sub sizeof_compound { my $parent = $field->getAttribute('inherits-from'); my $off = 0; - $off = 4 if ($meta eq 'class-type'); + $off = $SIZEOF_PTR if ($meta eq 'class-type'); $off = sizeof($global_types{$parent}) if ($parent); my $al = 1; - $al = 4 if ($meta eq 'class-type'); + $al = $SIZEOF_PTR if ($meta eq 'class-type'); for my $f ($field->findnodes('child::ld:field')) { diff --git a/plugins/ruby/ruby-autogen-defs.rb b/plugins/ruby/ruby-autogen-defs.rb index 7e26e93ac..c1fb07ac1 100644 --- a/plugins/ruby/ruby-autogen-defs.rb +++ b/plugins/ruby/ruby-autogen-defs.rb @@ -1,5 +1,32 @@ # definition of classes used by ruby-autogen +$sizeof_ptr = case RUBY_PLATFORM + when /x86_64|x64/i; 64 + else 32 + end + module DFHack + def self.memory_read_int64(addr) + (memory_read_int32(addr) & 0xffffffff) + (memory_read_int32(addr+4) << 32) + end + def self.memory_write_int64(addr, v) + memory_write_int32(addr, v & 0xffffffff) ; memory_write_int32(addr+4, v>>32) + end + if $sizeof_ptr == 64 + def self.memory_read_ptr(addr) + memory_read_int64(addr) & 0xffffffff_ffffffff + end + def self.memory_write_ptr(addr, v) + memory_write_int64(addr, v) + end + else + def self.memory_read_ptr(addr) + memory_read_int32(addr) & 0xffffffff + end + def self.memory_write_ptr(addr, v) + memory_write_int32(addr, v) + end + end + module MemHack INSPECT_SIZE_LIMIT=16384 class MemStruct @@ -62,6 +89,8 @@ module DFHack case tglen when 1; StlVector8.new(tg) when 2; StlVector16.new(tg) + when 4; StlVector32.new(tg) + when 8; StlVector64.new(tg) else StlVector32.new(tg) end end @@ -207,10 +236,10 @@ module DFHack def _get v = case @_bits + when 64; DFHack.memory_read_int64(@_memaddr) when 32; DFHack.memory_read_int32(@_memaddr) when 16; DFHack.memory_read_int16(@_memaddr) when 8; DFHack.memory_read_int8( @_memaddr) - when 64;(DFHack.memory_read_int32(@_memaddr) & 0xffffffff) + (DFHack.memory_read_int32(@_memaddr+4) << 32) end v &= (1 << @_bits) - 1 if not @_signed v = @_enum.sym(v) if @_enum @@ -220,10 +249,10 @@ module DFHack def _set(v) v = @_enum.int(v) if @_enum case @_bits + when 64; DFHack.memory_write_int64(@_memaddr, v) when 32; DFHack.memory_write_int32(@_memaddr, v) when 16; DFHack.memory_write_int16(@_memaddr, v) when 8; DFHack.memory_write_int8( @_memaddr, v) - when 64; DFHack.memory_write_int32(@_memaddr, v & 0xffffffff) ; DFHack.memory_write_int32(@memaddr+4, v>>32) end end @@ -299,11 +328,11 @@ module DFHack end def _getp - DFHack.memory_read_int32(@_memaddr) & 0xffffffff + DFHack.memory_read_ptr(@_memaddr) end def _setp(v) - DFHack.memory_write_int32(@_memaddr, v) + DFHack.memory_write_ptr(@_memaddr, v) end def _get @@ -316,8 +345,8 @@ module DFHack # XXX shaky... def _set(v) case v - when Pointer; DFHack.memory_write_int32(@_memaddr, v._getp) - when MemStruct; DFHack.memory_write_int32(@_memaddr, v._memaddr) + when Pointer; DFHack.memory_write_ptr(@_memaddr, v._getp) + when MemStruct; DFHack.memory_write_ptr(@_memaddr, v._memaddr) when Integer if @_tg and @_tg.kind_of?(MemHack::Number) if _getp == 0 @@ -325,9 +354,9 @@ module DFHack end @_tg._at(_getp)._set(v) else - DFHack.memory_write_int32(@_memaddr, v) + DFHack.memory_write_ptr(@_memaddr, v) end - when nil; DFHack.memory_write_int32(@_memaddr, 0) + when nil; DFHack.memory_write_ptr(@_memaddr, 0) else @_tg._at(_getp)._set(v) end end @@ -353,7 +382,7 @@ module DFHack def _getp(i=0) delta = (i != 0 ? i*@_tglen : 0) - (DFHack.memory_read_int32(@_memaddr) & 0xffffffff) + delta + DFHack.memory_read_ptr(@_memaddr) + delta end def _get @@ -364,10 +393,10 @@ module DFHack def _set(v) case v - when Pointer; DFHack.memory_write_int32(@_memaddr, v._getp) - when MemStruct; DFHack.memory_write_int32(@_memaddr, v._memaddr) - when Integer; DFHack.memory_write_int32(@_memaddr, v) - when nil; DFHack.memory_write_int32(@_memaddr, 0) + when Pointer; DFHack.memory_write_ptr(@_memaddr, v._getp) + when MemStruct; DFHack.memory_write_ptr(@_memaddr, v._memaddr) + when Integer; DFHack.memory_write_ptr(@_memaddr, v) + when nil; DFHack.memory_write_ptr(@_memaddr, 0) else raise "cannot PointerAry._set(#{v.inspect})" end end @@ -557,6 +586,20 @@ module DFHack end end end + class StlVector64 < StlVector32 + def length + DFHack.memory_vector64_length(@_memaddr) + end + def valueptr_at(idx) + DFHack.memory_vector64_ptrat(@_memaddr, idx) + end + def insert_at(idx, val) + DFHack.memory_vector64_insertat(@_memaddr, idx, val) + end + def delete_at(idx) + DFHack.memory_vector64_deleteat(@_memaddr, idx) + end + end class StlVector16 < StlVector32 def length DFHack.memory_vector16_length(@_memaddr) @@ -733,8 +776,8 @@ module DFHack @_tg = tg end - field(:_ptr, 0) { number 32, false } - field(:_length, 4) { number 16, false } + field(:_ptr, 0) { number $sizeof_ptr, false } + field(:_length, $sizeof_ptr/8) { number 16, false } def length ; _length ; end def size ; _length ; end @@ -769,8 +812,8 @@ module DFHack end field(:_ptr, 0) { pointer } - field(:_prev, 4) { pointer } - field(:_next, 8) { pointer } + field(:_prev, $sizeof_ptr/8) { pointer } + field(:_next, 2*$sizeof_ptr/8) { pointer } def item # With the current xml structure, currently _tg designate @@ -946,7 +989,7 @@ module DFHack def self.vmethod_call(obj, voff, a0=0, a1=0, a2=0, a3=0, a4=0, a5=0) this = obj._memaddr vt = df.get_vtable_ptr(this) - fptr = df.memory_read_int32(vt + voff) & 0xffffffff + fptr = df.memory_read_ptr(vt + voff) vmethod_do_call(this, fptr, vmethod_arg(a0), vmethod_arg(a1), vmethod_arg(a2), vmethod_arg(a3), vmethod_arg(a4), vmethod_arg(a5)) end diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 276e5052b..70250a5eb 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -284,16 +284,15 @@ static command_result df_rubyeval(color_ostream &out, std::vector // this code should work with ruby1.9, but ruby1.9 doesn't like running // in a dedicated non-main thread, so use ruby1.8 binaries only for now -// these ruby definitions are invalid for windows 64bit (need long long) -typedef unsigned long VALUE; -typedef unsigned long ID; +typedef uintptr_t VALUE; +typedef uintptr_t ID; #define Qfalse ((VALUE)0) #define Qtrue ((VALUE)2) #define Qnil ((VALUE)4) -#define INT2FIX(i) ((VALUE)((((long)i) << 1) | 1)) -#define FIX2INT(i) (((long)i) >> 1) +#define INT2FIX(i) ((VALUE)((((intptr_t)i) << 1) | 1)) +#define FIX2INT(i) (((intptr_t)i) >> 1) #define RUBY_METHOD_FUNC(func) ((VALUE(*)(...))func) void (*ruby_init_stack)(VALUE*); @@ -313,9 +312,9 @@ VALUE (*rb_eval_string_protect)(const char*, int*); VALUE (*rb_ary_shift)(VALUE); VALUE (*rb_float_new)(double); double (*rb_num2dbl)(VALUE); -VALUE (*rb_int2inum)(long); -VALUE (*rb_uint2inum)(unsigned long); -unsigned long (*rb_num2ulong)(VALUE); +VALUE (*rb_int2inum)(intptr_t); // XXX check on win64 long vs intptr_t +VALUE (*rb_uint2inum)(uintptr_t); +uintptr_t (*rb_num2ulong)(VALUE); // end of rip(ruby.h) DFHack::DFLibrary *libruby_handle; @@ -582,12 +581,27 @@ static VALUE rb_dfget_vtable(VALUE self, VALUE name) static VALUE rb_dfget_rtti_classname(VALUE self, VALUE vptr) { char *ptr = (char*)rb_num2ulong(vptr); -#ifdef WIN32 +#if defined(_WIN64) + // win64 + char *rtti = *(char**)(ptr - 0x8); + char *typeinfo = Core::getInstance().p->getBase() + *(uint32_t*)(rtti + 0xC); + // skip the .?AV, trim @@ from end + return rb_str_new(typeinfo+0x14, strlen(typeinfo+0x14)-2); +#elif defined(WIN32) + // win32 char *rtti = *(char**)(ptr - 0x4); char *typeinfo = *(char**)(rtti + 0xC); // skip the .?AV, trim @@ from end return rb_str_new(typeinfo+0xc, strlen(typeinfo+0xc)-2); +#elif defined(__amd64__) || defined(__x86_64__) + // lin64 + char *typeinfo = *(char**)(ptr - 0x8); + char *typestring = *(char**)(typeinfo + 0x8); + while (*typestring >= '0' && *typestring <= '9') + typestring++; + return rb_str_new(typestring, strlen(typestring)); #else + // lin32 char *typeinfo = *(char**)(ptr - 0x4); char *typestring = *(char**)(typeinfo + 0x4); while (*typestring >= '0' && *typestring <= '9') @@ -909,6 +923,30 @@ static VALUE rb_dfmemory_vec32_deleteat(VALUE self, VALUE addr, VALUE idx) return Qtrue; } +// vector +static VALUE rb_dfmemory_vec64_length(VALUE self, VALUE addr) +{ + std::vector *v = (std::vector*)rb_num2ulong(addr); + return rb_uint2inum(v->size()); +} +static VALUE rb_dfmemory_vec64_ptrat(VALUE self, VALUE addr, VALUE idx) +{ + std::vector *v = (std::vector*)rb_num2ulong(addr); + return rb_uint2inum((uintptr_t)&v->at(FIX2INT(idx))); +} +static VALUE rb_dfmemory_vec64_insertat(VALUE self, VALUE addr, VALUE idx, VALUE val) +{ + std::vector *v = (std::vector*)rb_num2ulong(addr); + v->insert(v->begin()+FIX2INT(idx), rb_num2ulong(val)); + return Qtrue; +} +static VALUE rb_dfmemory_vec64_deleteat(VALUE self, VALUE addr, VALUE idx) +{ + std::vector *v = (std::vector*)rb_num2ulong(addr); + v->erase(v->begin()+FIX2INT(idx)); + return Qtrue; +} + // vector static VALUE rb_dfmemory_vecbool_new(VALUE self) { @@ -1136,6 +1174,10 @@ static void ruby_bind_dfhack(void) { rb_define_singleton_method(rb_cDFHack, "memory_vector32_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec32_ptrat), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector32_insertat", RUBY_METHOD_FUNC(rb_dfmemory_vec32_insertat), 3); rb_define_singleton_method(rb_cDFHack, "memory_vector32_deleteat", RUBY_METHOD_FUNC(rb_dfmemory_vec32_deleteat), 2); + rb_define_singleton_method(rb_cDFHack, "memory_vector64_length", RUBY_METHOD_FUNC(rb_dfmemory_vec64_length), 1); + rb_define_singleton_method(rb_cDFHack, "memory_vector64_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec64_ptrat), 2); + rb_define_singleton_method(rb_cDFHack, "memory_vector64_insertat", RUBY_METHOD_FUNC(rb_dfmemory_vec64_insertat), 3); + rb_define_singleton_method(rb_cDFHack, "memory_vector64_deleteat", RUBY_METHOD_FUNC(rb_dfmemory_vec64_deleteat), 2); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_new", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_new), 0); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_delete", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_delete), 1); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_init", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_init), 1); From 97f29229cd8fc330c65bdf55cee33c19524dc68b Mon Sep 17 00:00:00 2001 From: jj Date: Fri, 21 Oct 2016 17:00:02 +0200 Subject: [PATCH 182/413] ruby: fix weird freeze when printing large strings to the console on linux64 --- plugins/ruby/ruby.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/ruby/ruby.rb b/plugins/ruby/ruby.rb index 850ca0912..7709276c8 100644 --- a/plugins/ruby/ruby.rb +++ b/plugins/ruby/ruby.rb @@ -2,14 +2,24 @@ module Kernel def puts(*a) a.flatten.each { |l| - DFHack.print_str(l.to_s.chomp + "\n") + # XXX looks like print_str crashes with strings longer than 4096... maybe not nullterminated ? + # this workaround fixes it + s = l.to_s.chomp + "\n" + while s.length > 0 + DFHack.print_str(s[0, 4000]) + s[0, 4000] = '' + end } nil end def puts_err(*a) a.flatten.each { |l| - DFHack.print_err(l.to_s.chomp + "\n") + s = l.to_s.chomp + "\n" + while s.length > 0 + DFHack.print_err(s[0, 4000]) + s[0, 4000] = '' + end } nil end From 3df74de021e864c97ac75a8a33978470cd3d8f51 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 21 Oct 2016 11:46:53 -0400 Subject: [PATCH 183/413] Fix rb_dfget_vtable_ptr on x64 This was causing rb_dfget_rtti_classname to receive a truncated pointer and crash --- plugins/ruby/ruby.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 70250a5eb..bb3b7fe30 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -593,17 +593,10 @@ static VALUE rb_dfget_rtti_classname(VALUE self, VALUE vptr) char *typeinfo = *(char**)(rtti + 0xC); // skip the .?AV, trim @@ from end return rb_str_new(typeinfo+0xc, strlen(typeinfo+0xc)-2); -#elif defined(__amd64__) || defined(__x86_64__) - // lin64 - char *typeinfo = *(char**)(ptr - 0x8); - char *typestring = *(char**)(typeinfo + 0x8); - while (*typestring >= '0' && *typestring <= '9') - typestring++; - return rb_str_new(typestring, strlen(typestring)); #else - // lin32 - char *typeinfo = *(char**)(ptr - 0x4); - char *typestring = *(char**)(typeinfo + 0x4); + // linux/osx 32/64 + char *typeinfo = *(char**)(ptr - sizeof(void*)); + char *typestring = *(char**)(typeinfo + sizeof(void*)); while (*typestring >= '0' && *typestring <= '9') typestring++; return rb_str_new(typestring, strlen(typestring)); @@ -612,8 +605,7 @@ static VALUE rb_dfget_rtti_classname(VALUE self, VALUE vptr) static VALUE rb_dfget_vtable_ptr(VALUE self, VALUE objptr) { - // actually, rb_dfmemory_read_int32 - return rb_uint2inum(*(uint32_t*)rb_num2ulong(objptr)); + return rb_uint2inum(*(uintptr_t*)rb_num2ulong(objptr)); } // run a dfhack command, as if typed from the dfhack console From a0b0c16a8b184e85dd31d8d2c9900223e703fba6 Mon Sep 17 00:00:00 2001 From: Japa Date: Fri, 21 Oct 2016 22:55:28 +0530 Subject: [PATCH 184/413] Actually apply the designation changes in RemoteFortressReader --- plugins/remotefortressreader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index bbf998704..05ad56e75 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -2895,5 +2895,7 @@ static command_result SendDigCommand(color_ostream &stream, const DigCommand *in } mc.setDesignationAt(DFCoord(pos.x(), pos.y(), pos.z()), des); } + + mc.WriteAll(); return CR_OK; } From 33ca7638f2c23cb3860c0aed88e0aca327f2e47d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 22 Oct 2016 13:04:15 -0400 Subject: [PATCH 185/413] Make DFHack libraries take priority on Linux Fixes #1008 --- package/linux/dfhack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/linux/dfhack b/package/linux/dfhack index b7ce1d812..7c01fcbd7 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -59,7 +59,7 @@ fi # Now run -export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"./hack/libs":"./hack" +export LD_LIBRARY_PATH="./hack/libs:./hack:$LD_LIBRARY_PATH" PRELOAD_LIB="${PRELOAD_LIB:+$PRELOAD_LIB:}./hack/libdfhack.so" From 4feab67a9311c80c262d39ed7875835cb52723d8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 23 Oct 2016 18:28:41 -0400 Subject: [PATCH 186/413] Fix Python 2 compatibility Ref #972 --- conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf.py b/conf.py index b3f8949e7..ed62ad5c6 100644 --- a/conf.py +++ b/conf.py @@ -38,7 +38,7 @@ def get_keybinds(): if l.startswith('keybinding add')] keybindings = dict() for k in lines: - first, command = k.split(' ', maxsplit=1) + first, command = k.split(' ', 1) bind, context = (first.split('@') + [''])[:2] if ' ' not in command: command = command.replace('"', '') From 5c83c16a99516d2ef0d9364705ca83a558a7524e Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 24 Oct 2016 10:06:41 -0400 Subject: [PATCH 187/413] Fix memview x64 address display --- plugins/devel/memview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/devel/memview.cpp b/plugins/devel/memview.cpp index 27dc72861..b93319a07 100644 --- a/plugins/devel/memview.cpp +++ b/plugins/devel/memview.cpp @@ -69,7 +69,7 @@ void outputHex(uint8_t *buf,uint8_t *lbuf,size_t len,size_t start,color_ostream for(size_t i=0;i Date: Mon, 24 Oct 2016 10:06:55 -0400 Subject: [PATCH 188/413] Fix mismatched backquotes in History.rst --- docs/History.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/History.rst b/docs/History.rst index b399fbbdd..e789d48c6 100644 --- a/docs/History.rst +++ b/docs/History.rst @@ -221,7 +221,8 @@ DFHack 0.40.11-r1 ================= Internals -- Plugins on OS X now use ``.plug.dylib` as an extension instead of ``.plug.so`` +--------- +- Plugins on OS X now use ``.plug.dylib`` as an extension instead of ``.plug.so`` Fixes ----- From 4fdbba0207f1dbabedb86c26fca200d082b82871 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 24 Oct 2016 22:28:51 -0400 Subject: [PATCH 189/413] Only touch protobuf generated files if they actually changed --- library/CMakeLists.txt | 28 +++++++++++++++++++++++++--- library/proto/.gitignore | 1 + library/proto/tmp/.gitignore | 1 + plugins/CMakeLists.txt | 26 +++++++++++++++++++++++--- plugins/proto/.gitignore | 1 + plugins/proto/tmp/.gitignore | 1 + 6 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 library/proto/tmp/.gitignore create mode 100644 plugins/proto/tmp/.gitignore diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 0958a6efc..cb919f935 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -215,20 +215,42 @@ ENDIF() # Protobuf FILE(GLOB PROJECT_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto) +SET(PROTO_STATUS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/proto/status.txt) STRING(REPLACE ".proto" ".pb.cc" PROJECT_PROTO_SRCS "${PROJECT_PROTOS}") STRING(REPLACE ".proto" ".pb.h" PROJECT_PROTO_HDRS "${PROJECT_PROTOS}") +STRING(REPLACE "/proto/" "/proto/tmp/" PROJECT_PROTO_TMP_FILES "${PROJECT_PROTO_SRCS};${PROJECT_PROTO_HDRS}") +SET_SOURCE_FILES_PROPERTIES(${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS} + PROPERTIES GENERATED TRUE) + +# Force a re-gen if any *.pb.* files are missing +IF(EXISTS ${PROTO_STATUS_FILE}) + FOREACH(file IN LISTS PROJECT_PROTO_SRCS PROJECT_PROTO_HDRS) + IF(NOT EXISTS ${file}) + MESSAGE("Resetting generate_proto_core because '${file}' is missing") + FILE(REMOVE ${PROTO_STATUS_FILE}) + BREAK() + ENDIF() + ENDFOREACH() +ENDIF() LIST(APPEND PROJECT_HEADERS ${PROJECT_PROTO_HDRS}) LIST(APPEND PROJECT_SOURCES ${PROJECT_PROTO_SRCS}) ADD_CUSTOM_COMMAND( - OUTPUT ${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS} + OUTPUT ${PROTO_STATUS_FILE} COMMAND protoc-bin -I=${CMAKE_CURRENT_SOURCE_DIR}/proto/ - --cpp_out=dllexport_decl=DFHACK_EXPORT:${CMAKE_CURRENT_SOURCE_DIR}/proto/ + --cpp_out=dllexport_decl=DFHACK_EXPORT:${CMAKE_CURRENT_SOURCE_DIR}/proto/tmp/ ${PROJECT_PROTOS} + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${PROJECT_PROTO_TMP_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/proto/ + COMMAND ${CMAKE_COMMAND} -E touch ${PROTO_STATUS_FILE} + COMMENT "Generating core protobufs" DEPENDS protoc-bin ${PROJECT_PROTOS} ) +ADD_CUSTOM_TARGET(generate_proto_core DEPENDS ${PROTO_STATUS_FILE}) + # Merge headers into sources SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HEADERS} PROPERTIES HEADER_FILE_ONLY TRUE ) LIST(APPEND PROJECT_SOURCES ${PROJECT_HEADERS}) @@ -299,7 +321,7 @@ ADD_CUSTOM_TARGET(git-describe ADD_DEPENDENCIES(dfhack-version git-describe) ADD_LIBRARY(dfhack SHARED ${PROJECT_SOURCES}) -ADD_DEPENDENCIES(dfhack generate_headers) +ADD_DEPENDENCIES(dfhack generate_headers generate_proto_core) ADD_LIBRARY(dfhack-client SHARED RemoteClient.cpp ColorText.cpp MiscUtils.cpp ${PROJECT_PROTO_SRCS}) ADD_DEPENDENCIES(dfhack-client dfhack) diff --git a/library/proto/.gitignore b/library/proto/.gitignore index befabf79d..3a96bb3d9 100644 --- a/library/proto/.gitignore +++ b/library/proto/.gitignore @@ -1,3 +1,4 @@ *.pb.cc *.pb.cc.rule *.pb.h +status.txt diff --git a/library/proto/tmp/.gitignore b/library/proto/tmp/.gitignore new file mode 100644 index 000000000..75feca5b1 --- /dev/null +++ b/library/proto/tmp/.gitignore @@ -0,0 +1 @@ +*.pb.* diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 9522491dd..f0bb847bf 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -42,18 +42,38 @@ install(DIRECTORY raw/ # Protobuf FILE(GLOB PROJECT_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto) +SET(PROTO_STATUS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/proto/status.txt) STRING(REPLACE ".proto" ".pb.cc" PROJECT_PROTO_SRCS "${PROJECT_PROTOS}") STRING(REPLACE ".proto" ".pb.h" PROJECT_PROTO_HDRS "${PROJECT_PROTOS}") +STRING(REPLACE "/proto/" "/proto/tmp/" PROJECT_PROTO_TMP_FILES "${PROJECT_PROTO_SRCS};${PROJECT_PROTO_HDRS}") +SET_SOURCE_FILES_PROPERTIES(${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS} + PROPERTIES GENERATED TRUE) + +# Force a re-gen if any *.pb.* files are missing +IF(EXISTS ${PROTO_STATUS_FILE}) + FOREACH(file IN LISTS PROJECT_PROTO_SRCS PROJECT_PROTO_HDRS) + IF(NOT EXISTS ${file}) + MESSAGE("Resetting generate_proto because '${file}' is missing") + FILE(REMOVE ${PROTO_STATUS_FILE}) + BREAK() + ENDIF() + ENDFOREACH() +ENDIF() ADD_CUSTOM_COMMAND( - OUTPUT ${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS} + OUTPUT ${PROTO_STATUS_FILE} COMMAND protoc-bin -I=${dfhack_SOURCE_DIR}/library/proto/ -I=${CMAKE_CURRENT_SOURCE_DIR}/proto/ - --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/proto/ + --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/proto/tmp/ ${PROJECT_PROTOS} + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${PROJECT_PROTO_TMP_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/proto/ + COMMAND ${CMAKE_COMMAND} -E touch ${PROTO_STATUS_FILE} + COMMENT "Generating plugin protobufs" DEPENDS protoc-bin ${PROJECT_PROTOS} ) -add_custom_target(generate_proto DEPENDS ${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS}) +add_custom_target(generate_proto DEPENDS ${PROTO_STATUS_FILE}) SET_SOURCE_FILES_PROPERTIES( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) diff --git a/plugins/proto/.gitignore b/plugins/proto/.gitignore index befabf79d..3a96bb3d9 100644 --- a/plugins/proto/.gitignore +++ b/plugins/proto/.gitignore @@ -1,3 +1,4 @@ *.pb.cc *.pb.cc.rule *.pb.h +status.txt diff --git a/plugins/proto/tmp/.gitignore b/plugins/proto/tmp/.gitignore new file mode 100644 index 000000000..75feca5b1 --- /dev/null +++ b/plugins/proto/tmp/.gitignore @@ -0,0 +1 @@ +*.pb.* From 2c230f0d3e38579c56640751df871cc93fc06878 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 24 Oct 2016 22:51:27 -0400 Subject: [PATCH 190/413] Improve protobuf file regeneration (no longer uses a dummy status.txt file) --- library/CMakeLists.txt | 23 ++++++++++------------- library/proto/.gitignore | 1 - plugins/CMakeLists.txt | 23 ++++++++++------------- plugins/proto/.gitignore | 1 - 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index cb919f935..ed5bfdcd2 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -215,7 +215,6 @@ ENDIF() # Protobuf FILE(GLOB PROJECT_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto) -SET(PROTO_STATUS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/proto/status.txt) STRING(REPLACE ".proto" ".pb.cc" PROJECT_PROTO_SRCS "${PROJECT_PROTOS}") STRING(REPLACE ".proto" ".pb.h" PROJECT_PROTO_HDRS "${PROJECT_PROTOS}") STRING(REPLACE "/proto/" "/proto/tmp/" PROJECT_PROTO_TMP_FILES "${PROJECT_PROTO_SRCS};${PROJECT_PROTO_HDRS}") @@ -223,33 +222,31 @@ SET_SOURCE_FILES_PROPERTIES(${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS} PROPERTIES GENERATED TRUE) # Force a re-gen if any *.pb.* files are missing -IF(EXISTS ${PROTO_STATUS_FILE}) - FOREACH(file IN LISTS PROJECT_PROTO_SRCS PROJECT_PROTO_HDRS) - IF(NOT EXISTS ${file}) - MESSAGE("Resetting generate_proto_core because '${file}' is missing") - FILE(REMOVE ${PROTO_STATUS_FILE}) - BREAK() - ENDIF() - ENDFOREACH() -ENDIF() +# (only runs when cmake is run, but better than nothing) +FOREACH(file IN LISTS PROJECT_PROTO_SRCS PROJECT_PROTO_HDRS) + IF(NOT EXISTS ${file}) + # MESSAGE("Resetting generate_proto_core because '${file}' is missing") + FILE(REMOVE ${PROJECT_PROTO_TMP_FILES}) + BREAK() + ENDIF() +ENDFOREACH() LIST(APPEND PROJECT_HEADERS ${PROJECT_PROTO_HDRS}) LIST(APPEND PROJECT_SOURCES ${PROJECT_PROTO_SRCS}) ADD_CUSTOM_COMMAND( - OUTPUT ${PROTO_STATUS_FILE} + OUTPUT ${PROJECT_PROTO_TMP_FILES} COMMAND protoc-bin -I=${CMAKE_CURRENT_SOURCE_DIR}/proto/ --cpp_out=dllexport_decl=DFHACK_EXPORT:${CMAKE_CURRENT_SOURCE_DIR}/proto/tmp/ ${PROJECT_PROTOS} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_PROTO_TMP_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/proto/ - COMMAND ${CMAKE_COMMAND} -E touch ${PROTO_STATUS_FILE} COMMENT "Generating core protobufs" DEPENDS protoc-bin ${PROJECT_PROTOS} ) -ADD_CUSTOM_TARGET(generate_proto_core DEPENDS ${PROTO_STATUS_FILE}) +ADD_CUSTOM_TARGET(generate_proto_core DEPENDS ${PROJECT_PROTO_TMP_FILES}) # Merge headers into sources SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HEADERS} PROPERTIES HEADER_FILE_ONLY TRUE ) diff --git a/library/proto/.gitignore b/library/proto/.gitignore index 3a96bb3d9..befabf79d 100644 --- a/library/proto/.gitignore +++ b/library/proto/.gitignore @@ -1,4 +1,3 @@ *.pb.cc *.pb.cc.rule *.pb.h -status.txt diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index f0bb847bf..612a49715 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -42,7 +42,6 @@ install(DIRECTORY raw/ # Protobuf FILE(GLOB PROJECT_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto) -SET(PROTO_STATUS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/proto/status.txt) STRING(REPLACE ".proto" ".pb.cc" PROJECT_PROTO_SRCS "${PROJECT_PROTOS}") STRING(REPLACE ".proto" ".pb.h" PROJECT_PROTO_HDRS "${PROJECT_PROTOS}") STRING(REPLACE "/proto/" "/proto/tmp/" PROJECT_PROTO_TMP_FILES "${PROJECT_PROTO_SRCS};${PROJECT_PROTO_HDRS}") @@ -50,18 +49,17 @@ SET_SOURCE_FILES_PROPERTIES(${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS} PROPERTIES GENERATED TRUE) # Force a re-gen if any *.pb.* files are missing -IF(EXISTS ${PROTO_STATUS_FILE}) - FOREACH(file IN LISTS PROJECT_PROTO_SRCS PROJECT_PROTO_HDRS) - IF(NOT EXISTS ${file}) - MESSAGE("Resetting generate_proto because '${file}' is missing") - FILE(REMOVE ${PROTO_STATUS_FILE}) - BREAK() - ENDIF() - ENDFOREACH() -ENDIF() +# (only runs when cmake is run, but better than nothing) +FOREACH(file IN LISTS PROJECT_PROTO_SRCS PROJECT_PROTO_HDRS) + IF(NOT EXISTS ${file}) + # MESSAGE("Resetting generate_proto because '${file}' is missing") + FILE(REMOVE ${PROJECT_PROTO_TMP_FILES}) + BREAK() + ENDIF() +ENDFOREACH() ADD_CUSTOM_COMMAND( - OUTPUT ${PROTO_STATUS_FILE} + OUTPUT ${PROJECT_PROTO_TMP_FILES} COMMAND protoc-bin -I=${dfhack_SOURCE_DIR}/library/proto/ -I=${CMAKE_CURRENT_SOURCE_DIR}/proto/ --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/proto/tmp/ @@ -69,11 +67,10 @@ ADD_CUSTOM_COMMAND( COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_PROTO_TMP_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/proto/ - COMMAND ${CMAKE_COMMAND} -E touch ${PROTO_STATUS_FILE} COMMENT "Generating plugin protobufs" DEPENDS protoc-bin ${PROJECT_PROTOS} ) -add_custom_target(generate_proto DEPENDS ${PROTO_STATUS_FILE}) +ADD_CUSTOM_TARGET(generate_proto DEPENDS ${PROJECT_PROTO_TMP_FILES}) SET_SOURCE_FILES_PROPERTIES( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) diff --git a/plugins/proto/.gitignore b/plugins/proto/.gitignore index 3a96bb3d9..befabf79d 100644 --- a/plugins/proto/.gitignore +++ b/plugins/proto/.gitignore @@ -1,4 +1,3 @@ *.pb.cc *.pb.cc.rule *.pb.h -status.txt From cffd3be591be530438a58f22f27675a3390a6948 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 25 Oct 2016 16:34:20 -0500 Subject: [PATCH 191/413] Move labormanager out of dev --- plugins/CMakeLists.txt | 1 + plugins/devel/CMakeLists.txt | 1 - plugins/{devel => }/labormanager.cpp | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename plugins/{devel => }/labormanager.cpp (100%) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index c24b940b9..97491a90d 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -110,6 +110,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) DFHACK_PLUGIN(jobutils jobutils.cpp) DFHACK_PLUGIN(lair lair.cpp) + DFHACK_PLUGIN(labormanager labormanager.cpp) DFHACK_PLUGIN(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) DFHACK_PLUGIN(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) DFHACK_PLUGIN(manipulator manipulator.cpp) diff --git a/plugins/devel/CMakeLists.txt b/plugins/devel/CMakeLists.txt index a1e5b7f14..e5001fff7 100644 --- a/plugins/devel/CMakeLists.txt +++ b/plugins/devel/CMakeLists.txt @@ -9,7 +9,6 @@ DFHACK_PLUGIN(counters counters.cpp) DFHACK_PLUGIN(dumpmats dumpmats.cpp) DFHACK_PLUGIN(eventExample eventExample.cpp) DFHACK_PLUGIN(frozen frozen.cpp) -DFHACK_PLUGIN(labormanager labormanager.cpp) DFHACK_PLUGIN(kittens kittens.cpp) DFHACK_PLUGIN(memview memview.cpp) DFHACK_PLUGIN(nestboxes nestboxes.cpp) diff --git a/plugins/devel/labormanager.cpp b/plugins/labormanager.cpp similarity index 100% rename from plugins/devel/labormanager.cpp rename to plugins/labormanager.cpp From 18235da9d60f16de276bd0f7bc8ccd522a0bf129 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 25 Oct 2016 16:45:25 -0500 Subject: [PATCH 192/413] add a misisng labor rule for leather crafts --- plugins/labormanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 7d41c7814..5a2774cd2 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1001,6 +1001,8 @@ private: return df::unit_labor::WOOD_CRAFT; case df::item_type::CLOTH: return df::unit_labor::CLOTHESMAKER; + case df::item_type::SKIN_TANNED: + return df::unit_labor::LEATHER; default: debug ("LABORMANAGER: Cannot deduce labor for make crafts job, item type %s\n", ENUM_KEY_STR(item_type, jobitem).c_str()); From 9aa6b84e24097b5596dcbe739be7d2aa8a38a404 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 25 Oct 2016 16:55:37 -0500 Subject: [PATCH 193/413] alphabetical order --- plugins/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 97491a90d..13425d2c6 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -109,8 +109,8 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(infiniteSky infiniteSky.cpp) DFHACK_PLUGIN(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) DFHACK_PLUGIN(jobutils jobutils.cpp) - DFHACK_PLUGIN(lair lair.cpp) DFHACK_PLUGIN(labormanager labormanager.cpp) + DFHACK_PLUGIN(lair lair.cpp) DFHACK_PLUGIN(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) DFHACK_PLUGIN(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) DFHACK_PLUGIN(manipulator manipulator.cpp) From a04ed641b723e9a8d664280e07c9dbf805910b6d Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 25 Oct 2016 17:03:45 -0500 Subject: [PATCH 194/413] SPACES not TABS --- plugins/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 13425d2c6..6763c2c56 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -109,7 +109,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(infiniteSky infiniteSky.cpp) DFHACK_PLUGIN(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) DFHACK_PLUGIN(jobutils jobutils.cpp) - DFHACK_PLUGIN(labormanager labormanager.cpp) + DFHACK_PLUGIN(labormanager labormanager.cpp) DFHACK_PLUGIN(lair lair.cpp) DFHACK_PLUGIN(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) DFHACK_PLUGIN(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) From 385d34490bd51d3395018e7c7d7200a2ea05cad8 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 25 Oct 2016 18:02:07 -0500 Subject: [PATCH 195/413] Docs for labormanager --- docs/Plugins.rst | 100 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index ac73bb58f..c8f24e12d 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -840,7 +840,105 @@ Examples: labormanager ============ -A more advanced alternative to `autolabor`. +Automatically manage dwarf labors to efficiently complete jobs. +Labormanager is derived from autolabor (above) but uses a completely +different approach to assigning jobs to dwarves. While autolabor tries +to keep as many dwarves busy as possible, labormanager instead strives +to get jobs done as quickly as possible. + +Labormanager frequently scans the current job list, current list of +dwarfs, and the map to determine how many dwarves need to be assigned to +what labors in order to meet all current labor needs without starving +any particular type of job. + +.. warning:: + + *As with autolabor, labormanager will override any manual changes you + make to labors while it is enabled, including through other tools such + as Dwarf Therapist* + +Simple usage: + +:enable labormanager: Enables the plugin with default settings. +(Persistent per fortress) :disable labormanager: Disables the plugin. + +Anything beyond this is optional - autolabor works fairly well on the +default settings. + +The default priorities for each labor vary (some labors are higher +priority by default than others). The way the plugin works is that, once +it determines how many of each labor is needed, it then sorts them by +adjusted priority. (Labors other than hauling have a bias added to them +based on how long it's been since they were last used, to prevent job +starvation.) The labor with the highest priority is selected, the "best +fit" dwarf for that labor is assigned to that labor, and then its +priority is *halved*. This process is repeated until either dwarfs or +labors run out. + +Because there is no easy way to detect how many haulers are actually +needed at any moment, the plugin always ensures that at least one dwarf +is assigned to each of the hauling labors, even if no hauling jobs are +detected. At least one dwarf is always assigned to construction removing +and cleaning because these jobs also cannot be easily detected. Lever +pulling is always assigned to everyone. Any dwarfs for which there are +no jobs will be assigned hauling, lever pulling, and cleaning labors. If +you use animal trainers, note that labormanager + +Labormanager also sometimes assigns extra labors to currently busy +dwarfs so that when they finish their current job, they will go off and +do something useful instead of standing around waiting for a job. + +There is special handling to ensure that at least one dwarf is assigned +to haul food whenever food is detected left in a place where it will rot +if not stored. This will cause a dwarf to go idle if you have no +storepiles to haul food to. + +Dwarfs who are unable to work (child, in the military, wounded, +handless, asleep, in a meeting) are entirely excluded from labor +assignment. Any dwarf explicitly assigned to a burrow will also be +completely ignored by labormanager. + +The fitness algorithm for assigning jobs to dwarfs generally attempts to +favor dwarfs who are more skilled over those who are less skilled. It +also tries to avoid assigning female dwarfs with children to jobs that +are "outside", favors assigning "outside" jobs to dwarfs who are +carrying a tool that could be used as a weapon, and tries to minimize +how often dwarfs have to reequip. + +Labormanager automatically determines medical needs and reserves health +care providers as needed. Note that this may cause idling if you have +injured dwarfs but no or inadequate hospital facilities. + +Hunting is never assigned without a butchery, and fishing is never +assigned without a fishery, and neither of these labors is assigned +unless specifically enabled. + +The method by which labormanager determines what labor is needed for a +particular job is complicated and, in places, incomplete. In some +situations, labormanager will detect that it cannot determine what labor +is required. It will, by default, pause and print an error message on +the dfhack console, followed by the message "LABORMANAGER: Game paused +so you can investigate the above message.". If this happens, please open +an issue on github, reporting the lines that immediately preceded this +message. You can tell labormanager to ignore this error and carry on by +typing "autolabor pause-on-error no", but be warned that some job may go +undone in this situation. + +Advanced usage: + +:autolabor enable: Turn plugin on. +:autolabor disable: Turn plugin off. +:autolabor priority : Set the priority value (see above) for labor to . +:autolabor reset : Reset the priority value of labor to its default. +:autolabor reset-all: Reset all priority values to their defaults. +:autolabor allow-fishing: Allow dwarfs to fish. *Warning* This tends to result in most of the fort going fishing. +:autolabor forbid-fishing: Forbid dwarfs from fishing. Default behavior. +:autolabor allow-hunting: Allow dwarfs to hunt. *Warning* This tends to result in as many dwarfs going hunting as you have crossbows. +:autolabor forbid-hunting: Forbid dwarfs from hunting. Default behavior. +:autolabor list: Show current priorities and current allocation stats. +:autolabor pause-on-error yes: Make labormanager pause if the labor inference engine fails. See above. +:autolabor pause-on-error no: Allow labormanager to continue past a labor inference engine failure. + .. _autohauler: From 6383ca13bf86bfda4c06e5067cd2dd2fa315d108 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 25 Oct 2016 18:10:29 -0500 Subject: [PATCH 196/413] Finish clipped sentence. (erk.) --- docs/Plugins.rst | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index c8f24e12d..13ea50661 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -882,7 +882,10 @@ detected. At least one dwarf is always assigned to construction removing and cleaning because these jobs also cannot be easily detected. Lever pulling is always assigned to everyone. Any dwarfs for which there are no jobs will be assigned hauling, lever pulling, and cleaning labors. If -you use animal trainers, note that labormanager +you use animal trainers, note that labormanager will misbehave if you +assign specific trainers to specific animals; results are only guaranteed +if you use "any trainer", and animal trainers will probably be +overallocated in any case. Labormanager also sometimes assigns extra labors to currently busy dwarfs so that when they finish their current job, they will go off and @@ -926,18 +929,18 @@ undone in this situation. Advanced usage: -:autolabor enable: Turn plugin on. -:autolabor disable: Turn plugin off. -:autolabor priority : Set the priority value (see above) for labor to . -:autolabor reset : Reset the priority value of labor to its default. -:autolabor reset-all: Reset all priority values to their defaults. -:autolabor allow-fishing: Allow dwarfs to fish. *Warning* This tends to result in most of the fort going fishing. -:autolabor forbid-fishing: Forbid dwarfs from fishing. Default behavior. -:autolabor allow-hunting: Allow dwarfs to hunt. *Warning* This tends to result in as many dwarfs going hunting as you have crossbows. -:autolabor forbid-hunting: Forbid dwarfs from hunting. Default behavior. -:autolabor list: Show current priorities and current allocation stats. -:autolabor pause-on-error yes: Make labormanager pause if the labor inference engine fails. See above. -:autolabor pause-on-error no: Allow labormanager to continue past a labor inference engine failure. +:labormanager enable: Turn plugin on. +:labormanager disable: Turn plugin off. +:labormanager priority : Set the priority value (see above) for labor to . +:labormanager reset : Reset the priority value of labor to its default. +:labormanager reset-all: Reset all priority values to their defaults. +:labormanager allow-fishing: Allow dwarfs to fish. *Warning* This tends to result in most of the fort going fishing. +:labormanager forbid-fishing: Forbid dwarfs from fishing. Default behavior. +:labormanager allow-hunting: Allow dwarfs to hunt. *Warning* This tends to result in as many dwarfs going hunting as you have crossbows. +:labormanager forbid-hunting: Forbid dwarfs from hunting. Default behavior. +:labormanager list: Show current priorities and current allocation stats. +:labormanager pause-on-error yes: Make labormanager pause if the labor inference engine fails. See above. +:labormanager pause-on-error no: Allow labormanager to continue past a labor inference engine failure. .. _autohauler: From defedb351ec9fc96cebc926f565cd088fdca320c Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 26 Oct 2016 09:34:14 -0400 Subject: [PATCH 197/413] Fix raw_vcall crash on Linux/OS X x64 --- plugins/ruby/ruby.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index bb3b7fe30..6d3f5d8e4 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -1086,7 +1086,8 @@ __declspec(naked) static int raw_vcall(void *that, void *fptr, unsigned long a0, static int raw_vcall(void *that, void *fptr, unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5) { - int (*t_fptr)(void *me, int, int, int, int, int, int); + int (*t_fptr)(void *me, unsigned long, unsigned long, unsigned long, + unsigned long, unsigned long, unsigned long); t_fptr = (decltype(t_fptr))fptr; return t_fptr(that, a0, a1, a2, a3, a4, a5); } From cf329c7cebad4a1fcbb1860e1332a7dace6a9e8d Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 26 Oct 2016 20:40:47 -0400 Subject: [PATCH 198/413] Ruby: fix Qnil and Qtrue constants with 64-bit Ruby 2.x These have different values on x64 Ruby 2.x (see USE_FLONUM in ruby.h in the ruby source). This was causing dump_rb_error to crash, since it was walking an array until it got to Qnil (but thinking Qnil was 4 instead of 8) and trying to print each element as a string. There were probably more subtle issues with Qnil and Qtrue being wrong too. --- plugins/ruby/ruby.cpp | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 6d3f5d8e4..10e63c706 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -287,9 +287,15 @@ static command_result df_rubyeval(color_ostream &out, std::vector typedef uintptr_t VALUE; typedef uintptr_t ID; -#define Qfalse ((VALUE)0) -#define Qtrue ((VALUE)2) -#define Qnil ((VALUE)4) +static struct { + int major; + int minor; + int teeny; +} libruby_version; + +static VALUE Qfalse; +static VALUE Qtrue; +static VALUE Qnil; #define INT2FIX(i) ((VALUE)((((intptr_t)i) << 1) | 1)) #define FIX2INT(i) (((intptr_t)i) >> 1) @@ -337,6 +343,26 @@ static int df_loadruby(void) return 0; } + const char *ruby_version = (const char*)LookupPlugin(libruby_handle, "ruby_version"); + if (!ruby_version) + return 0; + sscanf(ruby_version, "%d.%d.%d", + &libruby_version.major, &libruby_version.minor, &libruby_version.teeny); + + if (libruby_version.major >= 2 && sizeof(VALUE) >= sizeof(double)) + { + // USE_FLONUM defined on x64 + Qfalse = (VALUE)0; + Qtrue = (VALUE)0x14; + Qnil = (VALUE)0x08; + } + else + { + Qfalse = (VALUE)0; + Qtrue = (VALUE)2; + Qnil = (VALUE)4; + } + // ruby_sysinit is optional (ruby1.9 only) ruby_sysinit = (decltype(ruby_sysinit))LookupPlugin(libruby_handle, "ruby_sysinit"); #define rbloadsym(s) if (!(s = (decltype(s))LookupPlugin(libruby_handle, #s))) return 0 @@ -359,6 +385,7 @@ static int df_loadruby(void) rbloadsym(rb_uint2inum); rbloadsym(rb_num2ulong); #undef rbloadsym + // rb_float_new_in_heap in ruby 2 if (!((rb_float_new = (decltype(rb_float_new))(LookupPlugin(libruby_handle, "rb_float_new"))) || (rb_float_new = (decltype(rb_float_new))(LookupPlugin(libruby_handle, "rb_float_new_in_heap"))))) return 0; From d62d26379302dea38819681295cd235de4ab8a61 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 26 Oct 2016 20:55:16 -0400 Subject: [PATCH 199/413] ruby: Fix potential onupdate crash when cur_year is missing --- plugins/ruby/ruby.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 10e63c706..97a4a4553 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -214,15 +214,17 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) if (!onupdate_active) return CR_OK; - if (df::global::cur_year && (*df::global::cur_year < onupdate_minyear)) + using namespace df::global; + + if (cur_year && (*cur_year < onupdate_minyear)) return CR_OK; - if (df::global::cur_year_tick && onupdate_minyeartick >= 0 && - (*df::global::cur_year == onupdate_minyear && - *df::global::cur_year_tick < onupdate_minyeartick)) + if (cur_year && cur_year_tick && onupdate_minyeartick >= 0 && + (*cur_year == onupdate_minyear && + *cur_year_tick < onupdate_minyeartick)) return CR_OK; - if (df::global::cur_year_tick_advmode && onupdate_minyeartickadv >= 0 && - (*df::global::cur_year == onupdate_minyear && - *df::global::cur_year_tick_advmode < onupdate_minyeartickadv)) + if (cur_year && cur_year_tick_advmode && onupdate_minyeartickadv >= 0 && + (*cur_year == onupdate_minyear && + *cur_year_tick_advmode < onupdate_minyeartickadv)) return CR_OK; return plugin_eval_ruby(out, "DFHack.onupdate"); From cdf24efe43c09ecb92fed56565a5a6cb100c7238 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Thu, 27 Oct 2016 23:35:29 +1100 Subject: [PATCH 200/413] Remove plugins - all broken since 34.11 This changes nothing at all as far as any DFHack user is concerned, as these plugins have not been possible to build since DF 34.11 - and would have to be rewritten for compatiblity with new native-DF systems. "treefarm" is additionally replaced by "autochop". In the unlikely event that a developer wants the source code for something... that's what version control is for! --- plugins/CMakeLists.txt | 3 - plugins/advtools.cpp | 826 ----------------------------------------- plugins/misery.cpp | 218 ----------- plugins/treefarm.cpp | 175 --------- 4 files changed, 1222 deletions(-) delete mode 100644 plugins/advtools.cpp delete mode 100644 plugins/misery.cpp delete mode 100644 plugins/treefarm.cpp diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 612a49715..c9f120867 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -82,7 +82,6 @@ OPTION(BUILD_SUPPORTED "Build the supported plugins (reveal, probe, etc.)." ON) if (BUILD_SUPPORTED) DFHACK_PLUGIN(3dveins 3dveins.cpp) DFHACK_PLUGIN(add-spatter add-spatter.cpp) -# DFHACK_PLUGIN(advtools advtools.cpp) DFHACK_PLUGIN(autochop autochop.cpp) DFHACK_PLUGIN(autodump autodump.cpp) DFHACK_PLUGIN(autogems autogems.cpp) @@ -133,7 +132,6 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) DFHACK_PLUGIN(manipulator manipulator.cpp) DFHACK_PLUGIN(mode mode.cpp) - #DFHACK_PLUGIN(misery misery.cpp) DFHACK_PLUGIN(mousequery mousequery.cpp) DFHACK_PLUGIN(petcapRemover petcapRemover.cpp) DFHACK_PLUGIN(plants plants.cpp) @@ -160,7 +158,6 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(title-folder title-folder.cpp) DFHACK_PLUGIN(title-version title-version.cpp) DFHACK_PLUGIN(trackstop trackstop.cpp) -# DFHACK_PLUGIN(treefarm treefarm.cpp) DFHACK_PLUGIN(tubefill tubefill.cpp) add_subdirectory(tweak) DFHACK_PLUGIN(workflow workflow.cpp LINK_LIBRARIES lua) diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp deleted file mode 100644 index 77cc02934..000000000 --- a/plugins/advtools.cpp +++ /dev/null @@ -1,826 +0,0 @@ -#include "Core.h" -#include "Console.h" -#include "Export.h" -#include "PluginManager.h" -#include "MiscUtils.h" -#include "modules/World.h" -#include "modules/Translation.h" -#include "modules/Materials.h" -#include "modules/Maps.h" -#include "modules/Items.h" -#include "modules/Gui.h" -#include "modules/Units.h" - -#include "DataDefs.h" -#include "df/world.h" -#include "df/ui_advmode.h" -#include "df/item.h" -#include "df/unit.h" -#include "df/unit_inventory_item.h" -#include "df/map_block.h" -#include "df/nemesis_record.h" -#include "df/historical_figure.h" -#include "df/general_ref_is_nemesisst.h" -#include "df/general_ref_contains_itemst.h" -#include "df/general_ref_contained_in_itemst.h" -#include "df/general_ref_unit_holderst.h" -#include "df/general_ref_building_civzone_assignedst.h" -#include "df/material.h" -#include "df/craft_material_class.h" -#include "df/viewscreen_optionst.h" -#include "df/viewscreen_dungeonmodest.h" -#include "df/viewscreen_dungeon_monsterstatusst.h" -#include "df/nemesis_flags.h" - -#include - -using namespace DFHack; -using namespace df::enums; - -using df::nemesis_record; -using df::historical_figure; - -using namespace DFHack::Translation; -/* -advtools -======== -A package of different adventure mode tools. Usage: - -:list-equipped [all]: List armor and weapons equipped by your companions. - If all is specified, also lists non-metal clothing. -:metal-detector [all-types] [non-trader]: - Reveal metal armor and weapons in shops. The options - disable the checks on item type and being in shop. -*/ - -DFHACK_PLUGIN("advtools"); -REQUIRE_GLOBAL(world); -REQUIRE_GLOBAL(ui_advmode); - -/********************* - * PLUGIN INTERFACE * - *********************/ - -static bool bodyswap_hotkey(df::viewscreen *top); - -command_result adv_bodyswap (color_ostream &out, std::vector & parameters); -command_result adv_tools (color_ostream &out, std::vector & parameters); - -DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) -{ - if (!ui_advmode) - return CR_OK; - - commands.push_back(PluginCommand( - "advtools", "Adventure mode tools.", - adv_tools, false, - " list-equipped [all]\n" - " List armor and weapons equipped by your companions.\n" - " If all is specified, also lists non-metal clothing.\n" - " metal-detector [all-types] [non-trader]\n" - " Reveal metal armor and weapons in shops. The options\n" - " disable the checks on item type and being in shop.\n" - )); - - commands.push_back(PluginCommand( - "adv-bodyswap", "Change the adventurer unit.", - adv_bodyswap, bodyswap_hotkey, - " - When viewing unit details, body-swaps into that unit.\n" - " - In the main adventure mode screen, reverts transient swap.\n" - "Options:\n" - " force\n" - " Allow swapping into non-companion units.\n" - " permanent\n" - " Permanently change the unit to be the adventurer.\n" - " Otherwise it will revert if adv-bodyswap is called\n" - " in the main screen, or if the main menu, Fast Travel\n" - " or Sleep/Wait screen is opened.\n" - " noinherit\n" - " In permanent mode, don't reassign companions to the new unit.\n" - )); - - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ - return CR_OK; -} - -df::nemesis_record *getPlayerNemesis(color_ostream &out, bool restore_swap); - -DFHACK_PLUGIN_IS_ENABLED(in_transient_swap); - -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) -{ - switch (event) { - case SC_WORLD_LOADED: - case SC_WORLD_UNLOADED: - in_transient_swap = false; - break; - default: - break; - } - return CR_OK; -} - -DFhackCExport command_result plugin_onupdate ( color_ostream &out ) -{ - // Revert transient swaps before trouble happens - if (in_transient_swap) - { - auto screen = Core::getTopViewscreen(); - bool revert = false; - - if (strict_virtual_cast(screen)) - { - using namespace df::enums::ui_advmode_menu; - - switch (ui_advmode->menu) - { - case Travel: - case Sleep: - revert = true; - break; - default: - break; - } - } - else if (strict_virtual_cast(screen)) - { - // Options may mean save game - revert = true; - } - - if (revert) - { - getPlayerNemesis(out, true); - in_transient_swap = false; - } - } - - return CR_OK; -} - -/********************* - * UTILITY FUNCTIONS * - *********************/ - -static bool bodyswap_hotkey(df::viewscreen *top) -{ - return !!virtual_cast(top) || - !!virtual_cast(top); -} - -bool bodySwap(color_ostream &out, df::unit *player) -{ - if (!player) - { - out.printerr("Unit to swap is NULL\n"); - return false; - } - - auto &vec = world->units.active; - - int idx = linear_index(vec, player); - if (idx < 0) - { - out.printerr("Unit to swap not found: %d\n", player->id); - return false; - } - - if (idx != 0) - std::swap(vec[0], vec[idx]); - - return true; -} - -df::nemesis_record *getPlayerNemesis(color_ostream &out, bool restore_swap) -{ - auto real_nemesis = vector_get(world->nemesis.all, ui_advmode->player_id); - if (!real_nemesis || !real_nemesis->unit) - { - out.printerr("Invalid player nemesis id: %d\n", ui_advmode->player_id); - return NULL; - } - - if (restore_swap) - { - df::unit *ctl = world->units.active[0]; - auto ctl_nemesis = Units::getNemesis(ctl); - - if (ctl_nemesis != real_nemesis) - { - if (!bodySwap(out, real_nemesis->unit)) - return NULL; - - auto name = TranslateName(&real_nemesis->unit->name, false); - out.print("Returned into the body of %s.\n", name.c_str()); - } - - real_nemesis->unit->relations.group_leader_id = -1; - in_transient_swap = false; - } - - return real_nemesis; -} - -void changeGroupLeader(df::nemesis_record *new_nemesis, df::nemesis_record *old_nemesis) -{ - auto &cvec = new_nemesis->companions; - - // Swap companions - cvec.swap(old_nemesis->companions); - - vector_erase_at(cvec, linear_index(cvec, new_nemesis->id)); - insert_into_vector(cvec, old_nemesis->id); - - // Update follow - new_nemesis->group_leader_id = -1; - new_nemesis->unit->relations.group_leader_id = -1; - - for (unsigned i = 0; i < cvec.size(); i++) - { - auto nm = df::nemesis_record::find(cvec[i]); - if (!nm) - continue; - - nm->group_leader_id = new_nemesis->id; - if (nm->unit) - nm->unit->relations.group_leader_id = new_nemesis->unit_id; - } -} - -void copyAcquaintances(df::nemesis_record *new_nemesis, df::nemesis_record *old_nemesis) -{ - auto &svec = old_nemesis->unit->adventurer_knows; - auto &tvec = new_nemesis->unit->adventurer_knows; - - for (unsigned i = 0; i < svec.size(); i++) - insert_into_vector(tvec, svec[i]); - - insert_into_vector(tvec, old_nemesis->unit_id); -} - -void sortCompanionNemesis(std::vector *list, int player_id = -1) -{ - std::map table; - std::vector output; - - output.reserve(list->size()); - - if (player_id < 0) - { - auto real_nemesis = vector_get(world->nemesis.all, ui_advmode->player_id); - if (real_nemesis) - player_id = real_nemesis->id; - } - - // Index records; find the player - for (size_t i = 0; i < list->size(); i++) - { - auto item = (*list)[i]; - if (item->id == player_id) - output.push_back(item); - else - table[item->figure->id] = item; - } - - // Pull out the items by the persistent sort order - auto &order_vec = ui_advmode->companions.all_histfigs; - for (size_t i = 0; i < order_vec.size(); i++) - { - auto it = table.find(order_vec[i]); - if (it == table.end()) - continue; - output.push_back(it->second); - table.erase(it); - } - - // The remaining ones in reverse id order - for (auto it = table.rbegin(); it != table.rend(); ++it) - output.push_back(it->second); - - list->swap(output); -} - -void listCompanions(color_ostream &out, std::vector *list, bool units = true) -{ - nemesis_record *player = getPlayerNemesis(out, false); - if (!player) - return; - - list->push_back(player); - - for (size_t i = 0; i < player->companions.size(); i++) - { - auto item = nemesis_record::find(player->companions[i]); - if (item && (item->unit || !units)) - list->push_back(item); - } -} - -std::string getUnitNameProfession(df::unit *unit) -{ - std::string name = TranslateName(&unit->name, false) + ", "; - if (unit->custom_profession.empty()) - name += ENUM_ATTR_STR(profession, caption, unit->profession); - else - name += unit->custom_profession; - return name; -} - -enum InventoryMode { - INV_HAULED, - INV_WEAPON, - INV_WORN, - INV_IN_CONTAINER -}; - -typedef std::pair inv_item; - -static void listContainerInventory(std::vector *list, df::item *container) -{ - auto &refs = container->general_refs; - for (size_t i = 0; i < refs.size(); i++) - { - auto ref = refs[i]; - if (!strict_virtual_cast(ref)) - continue; - - df::item *child = ref->getItem(); - if (!child) continue; - - list->push_back(inv_item(child, INV_IN_CONTAINER)); - listContainerInventory(list, child); - } -} - -void listUnitInventory(std::vector *list, df::unit *unit) -{ - auto &items = unit->inventory; - for (size_t i = 0; i < items.size(); i++) - { - auto item = items[i]; - InventoryMode mode; - - switch (item->mode) { - case df::unit_inventory_item::Hauled: - mode = INV_HAULED; - break; - case df::unit_inventory_item::Weapon: - mode = INV_WEAPON; - break; - default: - mode = INV_WORN; - } - - list->push_back(inv_item(item->item, mode)); - listContainerInventory(list, item->item); - } -} - -bool isShopItem(df::item *item) -{ - for (size_t k = 0; k < item->general_refs.size(); k++) - { - auto ref = item->general_refs[k]; - if (virtual_cast(ref)) - return true; - } - - return false; -} - -bool isWeaponArmor(df::item *item) -{ - using namespace df::enums::item_type; - - switch (item->getType()) { - case HELM: - case ARMOR: - case WEAPON: - case AMMO: - case GLOVES: - case PANTS: - case SHOES: - return true; - default: - return false; - } -} - -int containsMetalItems(df::item *item, bool all, bool non_trader, bool rec = false) -{ - int cnt = 0; - - auto &refs = item->general_refs; - for (size_t i = 0; i < refs.size(); i++) - { - auto ref = refs[i]; - - if (strict_virtual_cast(ref)) - return 0; - if (!rec && strict_virtual_cast(ref)) - return 0; - - if (strict_virtual_cast(ref)) - { - df::item *child = ref->getItem(); - if (!child) continue; - - cnt += containsMetalItems(child, all, non_trader, true); - } - } - - if (!non_trader && !isShopItem(item)) - return cnt; - if (!all && !isWeaponArmor(item)) - return cnt; - - MaterialInfo minfo(item); - if (minfo.getCraftClass() != craft_material_class::Metal) - return cnt; - - return ++cnt; -} - -void joinCounts(std::map &counts) -{ - for (auto it = counts.begin(); it != counts.end(); it++) - { - df::coord pt = it->first; - while (pt.x > 0 && counts.count(pt - df::coord(1,0,0))) - pt.x--; - while (pt.y > 0 &&counts.count(pt - df::coord(0,1,0))) - pt.y--; - while (pt.x < 0 && counts.count(pt + df::coord(1,0,0))) - pt.x++; - while (pt.y < 0 &&counts.count(pt + df::coord(0,1,0))) - pt.y++; - - if (pt == it->first) - continue; - - counts[pt] += it->second; - it->second = 0; - } -} - -/********************* - * FORMATTING * - *********************/ - -static void printCompanionHeader(color_ostream &out, size_t i, df::unit *unit) -{ - out.color(COLOR_GREY); - - if (i < 28) - out << char('a'+i); - else - out << i; - - out << ": " << getUnitNameProfession(unit); - if (unit->flags1.bits.dead) - out << " (DEAD)"; - if (unit->flags3.bits.ghostly) - out << " (GHOST)"; - out << endl; - - out.reset_color(); -} - -static size_t formatSize(std::vector *out, const std::map in, size_t *cnt) -{ - size_t len = 0; - - for (auto it = in.begin(); it != in.end(); ++it) - { - std::string line = it->first; - if (it->second != 1) - line += stl_sprintf(" [%d]", it->second); - len = std::max(len, line.size()); - out->push_back(line); - } - - if (out->empty()) - { - out->push_back("(none)"); - len = 6; - } - - if (cnt) - *cnt = std::max(*cnt, out->size()); - - return len; -} - -static std::string formatDirection(df::coord delta) -{ - std::string ns, ew, dir; - - if (delta.x > 0) - ew = "E"; - else if (delta.x < 0) - ew = "W"; - - if (delta.y > 0) - ns = "S"; - else if (delta.y < 0) - ns = "N"; - - if (abs(delta.x) > abs(delta.y)*5) - dir = ew; - else if (abs(delta.y) > abs(delta.x)*5) - dir = ns; - else if (abs(delta.x) > abs(delta.y)*2) - dir = ew + ns + ew; - else if (abs(delta.y) > abs(delta.x)*2) - dir = ns + ns + ew; - else if (delta.x || delta.y) - dir = ns + ew; - else - dir = "***"; - - int dist = (int)sqrt((double)(delta.x*delta.x + delta.y*delta.y)); - return stl_sprintf("%d away %s %+d", dist, dir.c_str(), delta.z); -} - -static void printEquipped(color_ostream &out, df::unit *unit, bool all) -{ - std::vector items; - listUnitInventory(&items, unit); - - std::map head, body, legs, weapons; - - for (auto it = items.begin(); it != items.end(); ++it) - { - df::item *item = it->first; - - // Skip non-worn non-weapons - ItemTypeInfo iinfo(item); - - bool is_weapon = (it->second == INV_WEAPON || iinfo.type == item_type::AMMO); - if (!(is_weapon || it->second == INV_WORN)) - continue; - - // Skip non-metal, unless all - MaterialInfo minfo(item); - df::craft_material_class mclass = minfo.getCraftClass(); - - bool is_metal = (mclass == craft_material_class::Metal); - if (!(is_weapon || all || is_metal)) - continue; - - // Format the name - std::string name; - if (is_metal) - name = minfo.toString() + " "; - else if (mclass != craft_material_class::None) - name = toLower(ENUM_KEY_STR(craft_material_class,mclass)) + " "; - name += iinfo.toString(); - - // Add to the right table - int count = item->getStackSize(); - - if (is_weapon) - { - weapons[name] += count; - continue; - } - - switch (iinfo.type) { - case item_type::HELM: - head[name] += count; - break; - case item_type::ARMOR: - case item_type::GLOVES: - case item_type::BACKPACK: - case item_type::QUIVER: - body[name] += count; - break; - case item_type::PANTS: - case item_type::SHOES: - legs[name] += count; - break; - default: - weapons[name] += count; - } - } - - std::vector cols[4]; - size_t sizes[4]; - size_t lines = 0; - - sizes[0] = formatSize(&cols[0], head, &lines); - sizes[1] = formatSize(&cols[1], body, &lines); - sizes[2] = formatSize(&cols[2], legs, &lines); - sizes[3] = formatSize(&cols[3], weapons, &lines); - - for (size_t i = 0; i < lines; i++) - { - for (int j = 0; j < 4; j++) - { - size_t sz = std::max(sizes[j], size_t(18)); - out << "| " << std::left << std::setw(sz) << vector_get(cols[j],i) << " "; - } - - out << "|" << std::endl; - } -} - -/********************* - * COMMANDS * - *********************/ - -command_result adv_bodyswap (color_ostream &out, std::vector & parameters) -{ - // HOTKEY COMMAND; CORE IS SUSPENDED - bool force = false; - bool permanent = false; - bool no_make_leader = false; - - for (unsigned i = 0; i < parameters.size(); i++) - { - auto &item = parameters[i]; - - if (item == "force") - force = true; - else if (item == "permanent") - permanent = true; - else if (item == "noinherit") - no_make_leader = true; - else - return CR_WRONG_USAGE; - } - - // Get the real player; undo previous transient swap - auto real_nemesis = getPlayerNemesis(out, true); - if (!real_nemesis) - return CR_FAILURE; - - // Get the unit to swap to - auto new_unit = Gui::getSelectedUnit(out, true); - auto new_nemesis = Units::getNemesis(new_unit); - - if (!new_nemesis) - { - if (new_unit) - { - out.printerr("Cannot swap into a non-historical unit.\n"); - return CR_FAILURE; - } - - return CR_OK; - } - - if (new_nemesis == real_nemesis) - return CR_OK; - - // Verify it's a companion - if (!force && linear_index(real_nemesis->companions, new_nemesis->id) < 0) - { - out.printerr("This is not your companion - use force to bodyswap.\n"); - return CR_FAILURE; - } - - // Swap - if (!bodySwap(out, new_nemesis->unit)) - return CR_FAILURE; - - auto name = TranslateName(&new_nemesis->unit->name, false); - out.print("Swapped into the body of %s.\n", name.c_str()); - - // Permanently re-link everything - if (permanent) - { - using namespace df::enums::nemesis_flags; - - ui_advmode->player_id = linear_index(world->nemesis.all, new_nemesis); - - // Flag 0 appears to be the 'active adventurer' flag, and - // the player_id field above seems to be computed using it - // when a savegame is loaded. - // Also, unless this is set, it is impossible to retire. - real_nemesis->flags.set(ACTIVE_ADVENTURER, false); - new_nemesis->flags.set(ACTIVE_ADVENTURER, true); - - real_nemesis->flags.set(RETIRED_ADVENTURER, true); // former retired adventurer - new_nemesis->flags.set(ADVENTURER, true); // blue color in legends - - // Reassign companions and acquaintances - if (!no_make_leader) - { - changeGroupLeader(new_nemesis, real_nemesis); - copyAcquaintances(new_nemesis, real_nemesis); - } - } - else - { - in_transient_swap = true; - - // Make the player unit follow around to avoid bad consequences - // if it is unloaded before the transient swap is reverted. - real_nemesis->unit->relations.group_leader_id = new_nemesis->unit_id; - } - - return CR_OK; -} - -command_result adv_tools (color_ostream &out, std::vector & parameters) -{ - if (parameters.empty()) - return CR_WRONG_USAGE; - - CoreSuspender suspend; - - const auto &command = parameters[0]; - if (command == "list-equipped") - { - bool all = false; - for (size_t i = 1; i < parameters.size(); i++) - { - if (parameters[i] == "all") - all = true; - else - return CR_WRONG_USAGE; - } - - std::vector list; - - listCompanions(out, &list); - sortCompanionNemesis(&list); - - for (size_t i = 0; i < list.size(); i++) - { - auto item = list[i]; - auto unit = item->unit; - - printCompanionHeader(out, i, unit); - printEquipped(out, unit, all); - } - - return CR_OK; - } - else if (command == "metal-detector") - { - bool all = false, non_trader = false; - for (size_t i = 1; i < parameters.size(); i++) - { - if (parameters[i] == "all-types") - all = true; - else if (parameters[i] == "non-trader") - non_trader = true; - else - return CR_WRONG_USAGE; - } - - auto *player = getPlayerNemesis(out, false); - if (!player) - return CR_FAILURE; - - df::coord player_pos = player->unit->pos; - - int total = 0; - std::map counts; - - auto &items = world->items.all; - for (size_t i = 0; i < items.size(); i++) - { - df::item *item = items[i]; - - int num = containsMetalItems(item, all, non_trader); - if (!num) - continue; - - df::map_block *block = Maps::getTileBlock(item->pos); - if (!block) - continue; - - total += num; - counts[(item->pos - player_pos)/10] += num; - - auto &designations = block->designation; - auto &dgn = designations[item->pos.x%16][item->pos.y%16]; - - dgn.bits.hidden = 0; // revealed - dgn.bits.pile = 1; // visible - } - - joinCounts(counts); - - out.print("%d items of metal merchandise found in the vicinity.\n", total); - for (auto it = counts.begin(); it != counts.end(); it++) - { - if (!it->second) - continue; - - df::coord delta = it->first * 10; - out.print(" %s: %d\n", formatDirection(delta).c_str(), it->second); - } - - return CR_OK; - } - else - return CR_WRONG_USAGE; -} diff --git a/plugins/misery.cpp b/plugins/misery.cpp deleted file mode 100644 index a4468079c..000000000 --- a/plugins/misery.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "PluginManager.h" -#include "Export.h" - -#include "DataDefs.h" -#include "df/world.h" -#include "df/ui.h" -#include "df/unit.h" -#include "df/unit_thought.h" -#include "df/unit_thought_type.h" - -#include -#include -#include - -using namespace std; -using namespace DFHack; -/* -misery -====== -When enabled, every new negative dwarven thought will be multiplied by a factor (2 by default). - -Usage: - -:misery enable n: enable misery with optional magnitude n. If specified, n must be positive. -:misery n: same as "misery enable n" -:misery enable: same as "misery enable 2" -: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. -*/ - -DFHACK_PLUGIN("misery"); -DFHACK_PLUGIN_IS_ENABLED(is_enabled); - -REQUIRE_GLOBAL(world); -REQUIRE_GLOBAL(ui); - -static int factor = 1; -static map processedThoughtCountTable; - -//keep track of fake thoughts so you can remove them if requested -static vector > fakeThoughts; -static int count; -const int maxCount = 1000; - -command_result misery(color_ostream& out, vector& parameters); - -DFhackCExport command_result plugin_shutdown(color_ostream& out) { - factor = 1; - return CR_OK; -} - -DFhackCExport command_result plugin_onupdate(color_ostream& out) { - static bool wasLoaded = false; - if ( factor == 1 || !world || !world->map.block_index ) { - if ( wasLoaded ) { - //we just unloaded the game: clear all data - factor = 1; - is_enabled = false; - processedThoughtCountTable.clear(); - fakeThoughts.clear(); - wasLoaded = false; - } - return CR_OK; - } - - if ( !wasLoaded ) { - wasLoaded = true; - } - - if ( count < maxCount ) { - count++; - return CR_OK; - } - count = 0; - - int32_t race_id = ui->race_id; - int32_t civ_id = ui->civ_id; - for ( size_t a = 0; a < world->units.all.size(); a++ ) { - df::unit* unit = world->units.all[a]; //TODO: consider units.active - //living, native units only - if ( unit->race != race_id || unit->civ_id != civ_id ) - continue; - if ( unit->flags1.bits.dead ) - continue; - - int processedThoughtCount; - map::iterator i = processedThoughtCountTable.find(unit->id); - if ( i == processedThoughtCountTable.end() ) { - processedThoughtCount = unit->status.recent_events.size(); - processedThoughtCountTable[unit->id] = processedThoughtCount; - } else { - processedThoughtCount = (*i).second; - } - - if ( processedThoughtCount == unit->status.recent_events.size() ) { - continue; - } else if ( processedThoughtCount > unit->status.recent_events.size() ) { - processedThoughtCount = unit->status.recent_events.size(); - } - - //don't reprocess any old thoughts - vector newThoughts; - for ( size_t b = processedThoughtCount; b < unit->status.recent_events.size(); b++ ) { - df::unit_thought* oldThought = unit->status.recent_events[b]; - const char* bob = ENUM_ATTR(unit_thought_type, value, oldThought->type); - if ( bob[0] != '-' ) { - //out.print("unit %4d: old thought value = %s\n", unit->id, bob); - continue; - } - /*out.print("unit %4d: Duplicating thought type %d (%s), value %s, age %d, subtype %d, severity %d\n", - unit->id, - oldThought->type.value, - ENUM_ATTR(unit_thought_type, caption, (oldThought->type)), - //df::enum_traits::attr_table[oldThought->type].caption - bob, - oldThought->age, - oldThought->subtype, - oldThought->severity - );*/ - //add duplicate thoughts to the temp list - for ( size_t c = 0; c < factor; c++ ) { - df::unit_thought* thought = new df::unit_thought; - thought->type = unit->status.recent_events[b]->type; - thought->age = unit->status.recent_events[b]->age; - thought->subtype = unit->status.recent_events[b]->subtype; - thought->severity = unit->status.recent_events[b]->severity; - newThoughts.push_back(thought); - } - } - for ( size_t b = 0; b < newThoughts.size(); b++ ) { - fakeThoughts.push_back(std::pair(a, unit->status.recent_events.size())); - unit->status.recent_events.push_back(newThoughts[b]); - } - processedThoughtCountTable[unit->id] = unit->status.recent_events.size(); - } - - return CR_OK; -} - -DFhackCExport command_result plugin_init(color_ostream& out, vector &commands) { - commands.push_back(PluginCommand("misery", "increase the intensity of negative dwarven thoughts", - &misery, false, - "misery: When enabled, every new negative dwarven thought will be multiplied by a factor (2 by default).\n" - "Usage:\n" - " misery enable n\n" - " enable misery with optional magnitude n. If specified, n must be positive.\n" - " misery n\n" - " same as \"misery enable n\"\n" - " misery enable\n" - " same as \"misery enable 2\"\n" - " misery disable\n" - " stop adding new negative thoughts. This will not remove existing duplicated thoughts. Equivalent to \"misery 1\"\n" - " misery clear\n" - " remove fake thoughts added in this session of DF. Saving makes them permanent! Does not change factor.\n\n" - )); - return CR_OK; -} - -DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) -{ - if (enable != is_enabled) - { - is_enabled = enable; - factor = enable ? 2 : 1; - } - - return CR_OK; -} - -command_result misery(color_ostream &out, vector& parameters) { - if ( !world || !world->map.block_index ) { - out.printerr("misery can only be enabled in fortress mode with a fully-loaded game.\n"); - return CR_FAILURE; - } - - if ( parameters.size() < 1 || parameters.size() > 2 ) { - return CR_WRONG_USAGE; - } - - if ( parameters[0] == "disable" ) { - if ( parameters.size() > 1 ) { - return CR_WRONG_USAGE; - } - factor = 1; - is_enabled = false; - return CR_OK; - } else if ( parameters[0] == "enable" ) { - is_enabled = true; - factor = 2; - if ( parameters.size() == 2 ) { - int a = atoi(parameters[1].c_str()); - if ( a <= 1 ) { - out.printerr("Second argument must be a positive integer.\n"); - return CR_WRONG_USAGE; - } - factor = a; - } - } else if ( parameters[0] == "clear" ) { - for ( size_t a = 0; a < fakeThoughts.size(); a++ ) { - int dorfIndex = fakeThoughts[a].first; - int thoughtIndex = fakeThoughts[a].second; - world->units.all[dorfIndex]->status.recent_events[thoughtIndex]->age = 1000000; - } - fakeThoughts.clear(); - } else { - int a = atoi(parameters[0].c_str()); - if ( a < 1 ) { - return CR_WRONG_USAGE; - } - factor = a; - is_enabled = factor > 1; - } - - return CR_OK; -} - diff --git a/plugins/treefarm.cpp b/plugins/treefarm.cpp deleted file mode 100644 index 0e24ad28f..000000000 --- a/plugins/treefarm.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include "Console.h" -#include "Core.h" -#include "DataDefs.h" -#include "Export.h" -#include "PluginManager.h" - -#include "modules/EventManager.h" -#include "modules/Once.h" - -#include "df/block_burrow.h" -#include "df/block_burrow_link.h" -#include "df/burrow.h" -#include "df/map_block.h" -#include "df/tile_bitmask.h" -#include "df/tile_dig_designation.h" -#include "df/tiletype.h" -#include "df/tiletype_shape.h" -#include "df/world.h" - -//#include "df/world.h" - -using namespace DFHack; -/* -treefarm -======== -Automatically manages special burrows and regularly schedules tree chopping -and digging when appropriate. - -Every time the plugin runs, it checks for burrows with a name containing the -string ``"treefarm"``. For each such burrow, it checks every tile in it for -fully-grown trees and for diggable walls. For each fully-grown tree it finds, -it designates the tree to be chopped, and for each natural wall it finds, it -designates the wall to be dug. - -Usage: - -:treefarm: Enables treefarm monitoring, starting next frame -:treefarm n: Enables treefarm monitoring, starting next frame, and sets - interval to n frames. If n is less than one, disables monitoring. -*/ - -DFHACK_PLUGIN("treefarm"); -DFHACK_PLUGIN_IS_ENABLED(enabled); - -REQUIRE_GLOBAL(world); -REQUIRE_GLOBAL(ui); - -void checkFarms(color_ostream& out, void* ptr); -command_result treefarm (color_ostream &out, std::vector & parameters); - -EventManager::EventHandler handler(&checkFarms, -1); -int32_t frequency = 1200*30; - -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) -{ - commands.push_back(PluginCommand( - "treefarm", - "automatically manages special burrows and regularly schedules tree chopping and digging when appropriate", - treefarm, - false, //allow non-interactive use - "treefarm\n" - " enables treefarm monitoring, starting next frame\n" - "treefarm n\n" - " enables treefarm monitoring, starting next frame\n" - " sets monitoring interval to n frames\n" - " if n is less than one, disables monitoring\n" - "\n" - "Every time the plugin runs, it checks for burrows with a name containing the string \"treefarm\". For each such burrow, it checks every tile in it for fully-grown trees and for diggable walls. For each fully-grown tree it finds, it designates the tree to be chopped, and for each natural wall it finds, it designates the wall to be dug.\n" - )); - return CR_OK; -} - -DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) { - enabled = enable; - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ - return CR_OK; -} - -void checkFarms(color_ostream& out, void* ptr) { - EventManager::unregisterAll(plugin_self); - if ( !enabled ) - return; - EventManager::registerTick(handler, frequency, plugin_self); - CoreSuspender suspend; - - int32_t xOffset = world->map.region_x*3; - int32_t yOffset = world->map.region_y*3; - int32_t zOffset = world->map.region_z; - //for each burrow named treefarm or obsidianfarm, check if you can dig/chop any obsidian/trees - for ( size_t a = 0; a < df::burrow::get_vector().size(); a++ ) { - df::burrow* burrow = df::burrow::get_vector()[a]; - if ( !burrow || burrow->name.find("treefarm") == std::string::npos ) - continue; - - if ( burrow->block_x.size() != burrow->block_y.size() || burrow->block_x.size() != burrow->block_z.size() ) - continue; - - for ( size_t b = 0; b < burrow->block_x.size(); b++ ) { - int32_t x=burrow->block_x[b] - xOffset; - int32_t y=burrow->block_y[b] - yOffset; - int32_t z=burrow->block_z[b] - zOffset; - - df::map_block* block = world->map.block_index[x][y][z]; - if ( !block ) - continue; - - df::block_burrow_link* link = &block->block_burrows; - df::tile_bitmask mask; - for ( ; link != NULL; link = link->next ) { - if ( link->item == NULL ) - continue; - if ( link->item->id == burrow->id ) { - mask = link->item->tile_bitmask; - break; - } - } - if ( link == NULL ) - continue; - - for ( int32_t x = 0; x < 16; x++ ) { - for ( int32_t y = 0; y < 16; y++ ) { - if ( !mask.getassignment(x,y) ) - continue; - df::tiletype type = block->tiletype[x][y]; - df::tiletype_shape shape = ENUM_ATTR(tiletype, shape, type); - if ( !block->designation[x][y].bits.hidden && - shape != df::enums::tiletype_shape::WALL && - shape != df::enums::tiletype_shape::TREE ) - continue; - if ( shape != df::enums::tiletype_shape::TREE ) { - if ( x == 0 && (block->map_pos.x/16) == 0 ) - continue; - if ( y == 0 && (block->map_pos.y/16) == 0 ) - continue; - if ( x == 15 && (block->map_pos.x/16) == world->map.x_count_block-1 ) - continue; - if ( y == 15 && (block->map_pos.y/16) == world->map.y_count_block-1 ) - continue; - } - - block->designation[x][y].bits.dig = df::enums::tile_dig_designation::Default; - } - } - } - } -} - -command_result treefarm (color_ostream &out, std::vector & parameters) -{ - EventManager::unregisterAll(plugin_self); - - if ( parameters.size() > 1 ) - return CR_WRONG_USAGE; - if ( parameters.size() == 1 ) { - int32_t i = atoi(parameters[0].c_str()); - if ( i < 1 ) { - plugin_enable(out, false); - out.print("treefarm disabled\n"); - return CR_OK; - } - plugin_enable(out, true); - frequency = i; - } - - if ( enabled ) { - EventManager::registerTick(handler, 1, plugin_self); - out.print("treefarm enabled with update frequency %d ticks\n", frequency); - } - return CR_OK; -} - From c64000606968a532cc188ee52a613de91cf406bd Mon Sep 17 00:00:00 2001 From: jj Date: Fri, 28 Oct 2016 16:40:14 +0200 Subject: [PATCH 201/413] ruby: some more updates for x64, fix df_flagarray size --- plugins/ruby/codegen.pl | 12 +++++--- plugins/ruby/ruby.cpp | 65 ++++++++++++----------------------------- plugins/ruby/ruby.rb | 5 ++-- 3 files changed, 30 insertions(+), 52 deletions(-) diff --git a/plugins/ruby/codegen.pl b/plugins/ruby/codegen.pl index 3a9db2c61..3f5ea4ffe 100755 --- a/plugins/ruby/codegen.pl +++ b/plugins/ruby/codegen.pl @@ -577,10 +577,14 @@ sub render_global_objects { # define friendlier accessors, eg df.world -> DFHack::GlobalObjects.new._at(0).world indent_rb { push @lines_rb, "Global = GlobalObjects.new._at(0)"; - for my $obj (@global_objects) + for my $oname (@global_objects) { - push @lines_rb, "def self.$obj ; Global.$obj ; end"; - push @lines_rb, "def self.$obj=(v) ; Global.$obj = v ; end"; + push @lines_rb, "if DFHack.get_global_address('$oname') != 0"; + indent_rb { + push @lines_rb, "def self.$oname ; Global.$oname ; end"; + push @lines_rb, "def self.$oname=(v) ; Global.$oname = v ; end"; + }; + push @lines_rb, "end"; } }; } @@ -743,7 +747,7 @@ sub sizeof { } elsif ($subtype eq 'df-linked-list') { return 3 * $SIZEOF_PTR; } elsif ($subtype eq 'df-flagarray') { - return 4 + $SIZEOF_PTR; + return 2 * $SIZEOF_PTR; # XXX length may be 4 on windows? } elsif ($subtype eq 'df-static-flagarray') { return $field->getAttribute('count'); } elsif ($subtype eq 'df-array') { diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 97a4a4553..f9368fdf6 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -214,17 +214,13 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) if (!onupdate_active) return CR_OK; - using namespace df::global; - - if (cur_year && (*cur_year < onupdate_minyear)) + if (df::global::cur_year && *df::global::cur_year < onupdate_minyear) return CR_OK; - if (cur_year && cur_year_tick && onupdate_minyeartick >= 0 && - (*cur_year == onupdate_minyear && - *cur_year_tick < onupdate_minyeartick)) + if (df::global::cur_year_tick && onupdate_minyeartick >= 0 && + *df::global::cur_year_tick < onupdate_minyeartick) return CR_OK; - if (cur_year && cur_year_tick_advmode && onupdate_minyeartickadv >= 0 && - (*cur_year == onupdate_minyear && - *cur_year_tick_advmode < onupdate_minyeartickadv)) + if (df::global::cur_year_tick_advmode && onupdate_minyeartickadv >= 0 && + *df::global::cur_year_tick_advmode < onupdate_minyeartickadv) return CR_OK; return plugin_eval_ruby(out, "DFHack.onupdate"); @@ -283,21 +279,13 @@ static command_result df_rubyeval(color_ostream &out, std::vector // - ruby.h with gcc -m32 on linux 64 is broken // so we dynamically load libruby with dlopen/LoadLibrary // lib path is hardcoded here, and by default downloaded by cmake -// this code should work with ruby1.9, but ruby1.9 doesn't like running -// in a dedicated non-main thread, so use ruby1.8 binaries only for now typedef uintptr_t VALUE; typedef uintptr_t ID; -static struct { - int major; - int minor; - int teeny; -} libruby_version; - -static VALUE Qfalse; -static VALUE Qtrue; -static VALUE Qnil; +static VALUE Qfalse = 0; +static VALUE Qtrue = 2; +static VALUE Qnil = 4; #define INT2FIX(i) ((VALUE)((((intptr_t)i) << 1) | 1)) #define FIX2INT(i) (((intptr_t)i) >> 1) @@ -345,26 +333,6 @@ static int df_loadruby(void) return 0; } - const char *ruby_version = (const char*)LookupPlugin(libruby_handle, "ruby_version"); - if (!ruby_version) - return 0; - sscanf(ruby_version, "%d.%d.%d", - &libruby_version.major, &libruby_version.minor, &libruby_version.teeny); - - if (libruby_version.major >= 2 && sizeof(VALUE) >= sizeof(double)) - { - // USE_FLONUM defined on x64 - Qfalse = (VALUE)0; - Qtrue = (VALUE)0x14; - Qnil = (VALUE)0x08; - } - else - { - Qfalse = (VALUE)0; - Qtrue = (VALUE)2; - Qnil = (VALUE)4; - } - // ruby_sysinit is optional (ruby1.9 only) ruby_sysinit = (decltype(ruby_sysinit))LookupPlugin(libruby_handle, "ruby_sysinit"); #define rbloadsym(s) if (!(s = (decltype(s))LookupPlugin(libruby_handle, #s))) return 0 @@ -465,6 +433,11 @@ static void df_rubythread(void *p) r_result = CR_OK; r_type = RB_IDLE; + // initialize ruby constants (may depend on libruby compilation flags/version) + Qnil = rb_eval_string_protect("nil", &state); + Qtrue = rb_eval_string_protect("true", &state); + Qfalse = rb_eval_string_protect("false", &state); + // load the default ruby-level definitions in the background state=0; rb_eval_string_protect("require './hack/ruby/ruby'", &state); @@ -1085,8 +1058,8 @@ static VALUE rb_dfmemory_set_clear(VALUE self, VALUE set) /* call an arbitrary object virtual method */ #if defined(_WIN32) && !defined(_WIN64) -__declspec(naked) static int raw_vcall(void *that, void *fptr, unsigned long a0, - unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5) +__declspec(naked) static intptr_t raw_vcall(void *that, void *fptr, uintptr_t a0, + uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5) { // __thiscall requires that the callee cleans up the stack // here we dont know how many arguments it will take, so @@ -1112,11 +1085,11 @@ __declspec(naked) static int raw_vcall(void *that, void *fptr, unsigned long a0, } } #else -static int raw_vcall(void *that, void *fptr, unsigned long a0, - unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5) +static intptr_t raw_vcall(void *that, void *fptr, uintptr_t a0, + uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5) { - int (*t_fptr)(void *me, unsigned long, unsigned long, unsigned long, - unsigned long, unsigned long, unsigned long); + intptr_t (*t_fptr)(void *me, uintptr_t, uintptr_t, uintptr_t, + uintptr_t, uintptr_t, uintptr_t); t_fptr = (decltype(t_fptr))fptr; return t_fptr(that, a0, a1, a2, a3, a4, a5); } diff --git a/plugins/ruby/ruby.rb b/plugins/ruby/ruby.rb index 7709276c8..c696c23e5 100644 --- a/plugins/ruby/ruby.rb +++ b/plugins/ruby/ruby.rb @@ -109,13 +109,14 @@ module DFHack def onupdate @onupdate_list ||= [] - y = cur_year + y = yt = 0 + y = cur_year rescue 0 ytmax = TICKS_PER_YEAR if df.gamemode == :ADVENTURE and df.respond_to?(:cur_year_tick_advmode) yt = cur_year_tick_advmode ytmax *= 144 else - yt = cur_year_tick + yt = cur_year_tick rescue 0 end @onupdate_list.each { |o| From 30801697d924ff15f993466d9f91e4fd637de521 Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 29 Oct 2016 00:28:37 +0530 Subject: [PATCH 202/413] Send items sitting on the floor through remoteFortressReader --- plugins/proto/RemoteFortressReader.proto | 11 ++++ plugins/remotefortressreader.cpp | 84 ++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 4c049d1a9..6b730d8c2 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -206,6 +206,16 @@ message SpatterPile repeated Spatter spatters = 1; } +message Item +{ + optional int32 id = 1; + optional Coord pos = 2; + optional uint32 flags1 = 3; + optional uint32 flags2 = 4; + optional MatPair type = 5; + optional MatPair material = 6; +} + message MapBlock { required int32 map_x = 1; @@ -233,6 +243,7 @@ message MapBlock repeated int32 tree_z = 23; repeated TileDigDesignation tile_dig_designation = 24; repeated SpatterPile spatterPile = 25; + repeated Item items = 26; } message MatPair { diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 05ad56e75..5c5068ed2 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -141,6 +141,7 @@ static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in static command_result CopyScreen(color_ostream &stream, const EmptyMessage *in, ScreenCapture *out); static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEvent *in); static command_result SendDigCommand(color_ostream &stream, const DigCommand *in); +void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos); @@ -958,12 +959,45 @@ bool IsspatterChanged(DFCoord pos) return false; } +map itemHashes; + +bool isItemChanged(int i) +{ + uint16_t hash = 0; + if (i >= 0 && i < world->items.all.size()) + { + auto item = world->items.all[i]; + if (item) + { + hash = fletcher16((uint8_t*)item, sizeof(df::item)); + } + } + if (itemHashes[i] != hash) + { + itemHashes[i] = hash; + return true; + } + return false; +} + +bool areItemsChanged(vector * items) +{ + bool result = false; + for (int i = 0; i < items->size(); i++) + { + if (isItemChanged(items->at(i))) + result = true; + } + return result; +} + static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage *in) { hashes.clear(); waterHashes.clear(); buildingHashes.clear(); spatterHashes.clear(); + itemHashes.clear(); return CR_OK; } @@ -1417,6 +1451,17 @@ void CopyBuildings(df::map_block * DfBlock, RemoteFortressReader::MapBlock * Net continue; auto out_bld = NetBlock->add_buildings(); CopyBuilding(i, out_bld); + df::building_actual* actualBuilding = strict_virtual_cast(bld); + if (actualBuilding) + { + for (int i = 0; i < actualBuilding->contained_items.size(); i++) + { + if (isItemChanged(actualBuilding->contained_items[i]->item->id)) + { + CopyItem(NetBlock->add_items(), actualBuilding->contained_items[i]->item); + } + } + } } } @@ -1459,6 +1504,42 @@ void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetB } } +void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) +{ + NetItem->set_id(DfItem->id); + NetItem->set_flags1(DfItem->flags.whole); + NetItem->set_flags2(DfItem->flags2.whole); + auto pos = NetItem->mutable_pos(); + pos->set_x(DfItem->pos.x); + pos->set_y(DfItem->pos.y); + pos->set_z(DfItem->pos.z); + auto mat = NetItem->mutable_material(); + mat->set_mat_index(DfItem->getMaterialIndex()); + mat->set_mat_type(DfItem->getMaterial()); + auto type = NetItem->mutable_type(); + type->set_mat_type(DfItem->getType()); + type->set_mat_index(DfItem->getSubtype()); +} + +void CopyItems(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) +{ + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + for (int i = 0; i < DfBlock->items.size(); i++) + { + int id = DfBlock->items[i]; + + if (id < 0) + continue; + if (id >= world->items.all.size()) + continue; + + auto item = world->items.all[id]; + CopyItem(NetBlock->add_items(), item); + } +} + static command_result GetBlockList(color_ostream &stream, const BlockRequest *in, BlockList *out) { int x, y, z; @@ -1518,6 +1599,7 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in bool desChanged = IsDesignationChanged(pos); bool spatterChanged = IsspatterChanged(pos); bool buildingChanged = IsBuildingChanged(pos); + bool itemsChanged = areItemsChanged(&block->items); //bool bldChanged = IsBuildingChanged(pos); RemoteFortressReader::MapBlock *net_block; if (tileChanged || desChanged || spatterChanged || buildingChanged) @@ -1533,6 +1615,8 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in CopyBuildings(block, net_block, &MC, pos); if (spatterChanged) Copyspatters(block, net_block, &MC, pos); + if (itemsChanged) + CopyItems(block, net_block, &MC, pos); } } } From 148202bcba8c700647fc7b79acb62a0a3a29a93e Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 29 Oct 2016 08:54:27 +0530 Subject: [PATCH 203/413] Use Binsearch for finding items. --- plugins/remotefortressreader.cpp | 42 ++++++++++++++------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 5c5068ed2..0ec2056db 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -964,13 +964,10 @@ map itemHashes; bool isItemChanged(int i) { uint16_t hash = 0; - if (i >= 0 && i < world->items.all.size()) + auto item = df::item::find(i); + if (item) { - auto item = world->items.all[i]; - if (item) - { - hash = fletcher16((uint8_t*)item, sizeof(df::item)); - } + hash = fletcher16((uint8_t*)item, sizeof(df::item)); } if (itemHashes[i] != hash) { @@ -1451,17 +1448,17 @@ void CopyBuildings(df::map_block * DfBlock, RemoteFortressReader::MapBlock * Net continue; auto out_bld = NetBlock->add_buildings(); CopyBuilding(i, out_bld); - df::building_actual* actualBuilding = strict_virtual_cast(bld); - if (actualBuilding) - { - for (int i = 0; i < actualBuilding->contained_items.size(); i++) - { - if (isItemChanged(actualBuilding->contained_items[i]->item->id)) - { - CopyItem(NetBlock->add_items(), actualBuilding->contained_items[i]->item); - } - } - } + //df::building_actual* actualBuilding = strict_virtual_cast(bld); + //if (actualBuilding) + //{ + // for (int i = 0; i < actualBuilding->contained_items.size(); i++) + // { + // if (isItemChanged(actualBuilding->contained_items[i]->item->id)) + // { + // CopyItem(NetBlock->add_items(), actualBuilding->contained_items[i]->item); + // } + // } + //} } } @@ -1530,13 +1527,10 @@ void CopyItems(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBloc { int id = DfBlock->items[i]; - if (id < 0) - continue; - if (id >= world->items.all.size()) - continue; - - auto item = world->items.all[id]; - CopyItem(NetBlock->add_items(), item); + + auto item = df::item::find(id); + if(item) + CopyItem(NetBlock->add_items(), item); } } From ec222c0b245c3d93070635f8ab0f67712fbb729b Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 29 Oct 2016 02:35:27 -0400 Subject: [PATCH 204/413] Catch exceptions in stockpile (un)serialization From #964, protobuf exceptions in loadstock/savestock would either fail by only logging an error to the console (when run from the Lua UI) or by crashing the game entirely (when run from the console). Figuring out what actually causes the exceptions in the first place (possibly a misunderstood structure layout?) would be a better solution than this, but this will at least stop crashes for now. --- plugins/stockpiles/stockpiles.cpp | 32 +++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/plugins/stockpiles/stockpiles.cpp b/plugins/stockpiles/stockpiles.cpp index 3cd2cb31a..ab9d9c8f7 100644 --- a/plugins/stockpiles/stockpiles.cpp +++ b/plugins/stockpiles/stockpiles.cpp @@ -244,11 +244,20 @@ static command_result savestock ( color_ostream &out, vector & paramete cereal.enable_debug ( out ); if ( !is_dfstockfile ( file ) ) file += ".dfstock"; - if ( !cereal.serialize_to_file ( file ) ) + try { - out.printerr ( "could not save to %s\n", file.c_str() ); + if ( !cereal.serialize_to_file ( file ) ) + { + out.printerr ( "could not save to %s\n", file.c_str() ); + return CR_FAILURE; + } + } + catch ( std::exception &e ) + { + out.printerr ( "serialization failed: protobuf exception: %s\n", e.what() ); return CR_FAILURE; } + return CR_OK; } @@ -296,9 +305,17 @@ static command_result loadstock ( color_ostream &out, vector & paramete StockpileSerializer cereal ( sp ); if ( debug ) cereal.enable_debug ( out ); - if ( !cereal.unserialize_from_file ( file ) ) + try { - out.printerr ( "unserialization failed\n" ); + if ( !cereal.unserialize_from_file ( file ) ) + { + out.printerr ( "unserialization failed: %s\n", file.c_str() ); + return CR_FAILURE; + } + } + catch ( std::exception &e ) + { + out.printerr ( "unserialization failed: protobuf exception: %s\n", e.what() ); return CR_FAILURE; } return CR_OK; @@ -508,13 +525,16 @@ static int stockpiles_list_settings ( lua_State *L ) return 1; } +const std::string err_title = "Stockpile Settings Error"; +const std::string err_help = "Does the folder exist?\nCheck the console for more information."; + static void stockpiles_load ( color_ostream &out, std::string filename ) { std::vector params; params.push_back ( filename ); command_result r = loadstock ( out, params ); if ( r != CR_OK ) - show_message_box ( "Stockpile Settings Error", "Couldn't load. Does the folder exist?", true ); + show_message_box ( err_title, "Couldn't load. " + err_help, true ); } @@ -524,7 +544,7 @@ static void stockpiles_save ( color_ostream &out, std::string filename ) params.push_back ( filename ); command_result r = savestock ( out, params ); if ( r != CR_OK ) - show_message_box ( "Stockpile Settings Error", "Couldn't save. Does the folder exist?", true ); + show_message_box ( err_title, "Couldn't save. " + err_help, true ); } DFHACK_PLUGIN_LUA_FUNCTIONS From ea9992239b551f2d7509fe4d269ea0972c451a8c Mon Sep 17 00:00:00 2001 From: Jon Pamala Illo Date: Sat, 29 Oct 2016 13:31:51 +0530 Subject: [PATCH 205/413] Send building items, and send fake item types for boxes and bags. --- plugins/remotefortressreader.cpp | 37 ++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 0ec2056db..0d642e589 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1138,6 +1138,17 @@ static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, mat_def->mutable_mat_pair()->set_mat_type((int)it); mat_def->mutable_mat_pair()->set_mat_index(-1); mat_def->set_id(ENUM_KEY_STR(item_type, it)); + if (it == item_type::BOX) + { + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(0); + mat_def->set_id("BOX_CHEST"); + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(1); + mat_def->set_id("BOX_BAG"); + } int subtypes = Items::getSubtypeCount(it); if (subtypes >= 0) { @@ -1448,17 +1459,17 @@ void CopyBuildings(df::map_block * DfBlock, RemoteFortressReader::MapBlock * Net continue; auto out_bld = NetBlock->add_buildings(); CopyBuilding(i, out_bld); - //df::building_actual* actualBuilding = strict_virtual_cast(bld); - //if (actualBuilding) - //{ - // for (int i = 0; i < actualBuilding->contained_items.size(); i++) - // { - // if (isItemChanged(actualBuilding->contained_items[i]->item->id)) - // { - // CopyItem(NetBlock->add_items(), actualBuilding->contained_items[i]->item); - // } - // } - //} + df::building_actual* actualBuilding = strict_virtual_cast(bld); + if (actualBuilding) + { + for (int i = 0; i < actualBuilding->contained_items.size(); i++) + { + if (isItemChanged(actualBuilding->contained_items[i]->item->id)) + { + CopyItem(NetBlock->add_items(), actualBuilding->contained_items[i]->item); + } + } + } } } @@ -1516,6 +1527,10 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) auto type = NetItem->mutable_type(); type->set_mat_type(DfItem->getType()); type->set_mat_index(DfItem->getSubtype()); + if (DfItem->getType() == item_type::BOX) + { + type->set_mat_index(DfItem->isBag()); + } } void CopyItems(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) From 4e7f2b95796d0d476a19968dd9df84aba63b878d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 29 Oct 2016 19:00:28 -0400 Subject: [PATCH 206/413] win64 ruby 2 --- plugins/ruby/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/ruby/CMakeLists.txt b/plugins/ruby/CMakeLists.txt index bfc41c032..208a851e5 100644 --- a/plugins/ruby/CMakeLists.txt +++ b/plugins/ruby/CMakeLists.txt @@ -33,7 +33,12 @@ ELSE() SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/win${DFHACK_BUILD_ARCH}/libruby.dll) SET(RUBYLIB_INSTALL_NAME "libruby.dll") IF(${DFHACK_BUILD_ARCH} STREQUAL 64) - MESSAGE("No ruby lib for 64-bit Windows yet") + DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win64-libruby200.dll.gz" + "gz" + ${RUBYLIB}.gz + "81db54a8b8b3090c94c6ae2147d30b8f" + ${RUBYLIB} + "8a8564418aebddef3dfee1e96690e713") ELSE() DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-libruby187.dll.gz" "gz" From 9e97ccbb50401dbbb84a33f34bf8a60cf3414868 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 29 Oct 2016 19:08:54 -0400 Subject: [PATCH 207/413] Use system libruby on osx64 (since ruby 1.8 and 2 are supported now) --- plugins/ruby/CMakeLists.txt | 6 ++++-- plugins/ruby/ruby.cpp | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/ruby/CMakeLists.txt b/plugins/ruby/CMakeLists.txt index 208a851e5..6b5e62c66 100644 --- a/plugins/ruby/CMakeLists.txt +++ b/plugins/ruby/CMakeLists.txt @@ -2,7 +2,7 @@ IF (APPLE) SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/osx${DFHACK_BUILD_ARCH}/libruby.dylib) SET(RUBYLIB_INSTALL_NAME "libruby.dylib") IF(${DFHACK_BUILD_ARCH} STREQUAL 64) - MESSAGE("No ruby lib for 64-bit OS X yet") + # MESSAGE("No ruby lib for 64-bit OS X yet") ELSE() DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/osx32-libruby187.dylib.gz" "gz" @@ -73,7 +73,9 @@ ADD_DEPENDENCIES(ruby ruby-autogen-rb) IF(EXISTS ${RUBYLIB}) INSTALL(FILES ${RUBYLIB} DESTINATION ${DFHACK_LIBRARY_DESTINATION} RENAME ${RUBYLIB_INSTALL_NAME}) ELSE() - MESSAGE(WARNING "Ruby library not found at ${RUBYLIB} - will not be installed") + IF(NOT(APPLE AND ${DFHACK_BUILD_ARCH} STREQUAL 64)) + MESSAGE(WARNING "Ruby library not found at ${RUBYLIB} - will not be installed") + ENDIF() ENDIF() INSTALL(DIRECTORY . diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index f9368fdf6..7a21e32eb 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -322,7 +322,11 @@ static int df_loadruby(void) #if defined(WIN32) "./libruby.dll"; #elif defined(__APPLE__) + #ifdef DFHACK64 + "/System/Library/Frameworks/Ruby.framework/Ruby"; + #else "hack/libruby.dylib"; + #endif #else "hack/libruby.so"; #endif From 2e6c7a90be21a0b2e746f3557f5f3716475197c6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 31 Oct 2016 01:58:40 -0400 Subject: [PATCH 208/413] fix whitespace --- docs/Plugins.rst | 4 ++-- plugins/ruby/ruby.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 13ea50661..85b6ba58d 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -883,8 +883,8 @@ and cleaning because these jobs also cannot be easily detected. Lever pulling is always assigned to everyone. Any dwarfs for which there are no jobs will be assigned hauling, lever pulling, and cleaning labors. If you use animal trainers, note that labormanager will misbehave if you -assign specific trainers to specific animals; results are only guaranteed -if you use "any trainer", and animal trainers will probably be +assign specific trainers to specific animals; results are only guaranteed +if you use "any trainer", and animal trainers will probably be overallocated in any case. Labormanager also sometimes assigns extra labors to currently busy diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 7a21e32eb..0470541e1 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -308,7 +308,7 @@ VALUE (*rb_eval_string_protect)(const char*, int*); VALUE (*rb_ary_shift)(VALUE); VALUE (*rb_float_new)(double); double (*rb_num2dbl)(VALUE); -VALUE (*rb_int2inum)(intptr_t); // XXX check on win64 long vs intptr_t +VALUE (*rb_int2inum)(intptr_t); // XXX check on win64 long vs intptr_t VALUE (*rb_uint2inum)(uintptr_t); uintptr_t (*rb_num2ulong)(VALUE); // end of rip(ruby.h) From 45ff1a0353a36e66ecd581c15213337f82ed9fa1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 31 Oct 2016 02:05:46 -0400 Subject: [PATCH 209/413] Add architecture to package names --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cae58c8f..e4911928f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -410,7 +410,7 @@ IF(APPLE) ELSE() set(DFHACK_PACKAGE_PLATFORM_NAME ${CMAKE_SYSTEM_NAME}) ENDIF() -set(CPACK_PACKAGE_FILE_NAME "dfhack-${DFHACK_VERSION}-${DFHACK_PACKAGE_PLATFORM_NAME}${DFHACK_PACKAGE_SUFFIX}") +set(CPACK_PACKAGE_FILE_NAME "dfhack-${DFHACK_VERSION}-${DFHACK_PACKAGE_PLATFORM_NAME}-${DFHACK_BUILD_ARCH}${DFHACK_PACKAGE_SUFFIX}") INCLUDE(CPack) #INCLUDE(FindSphinx.cmake) From 4941c06654b74d0baedc9a0c61a23b325505dd8c Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 31 Oct 2016 02:06:06 -0400 Subject: [PATCH 210/413] Only use TBZ2 generator on OS X --- CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4911928f..61b9dce12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -396,11 +396,7 @@ IF(UNIX) execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) string(STRIP ${GCC_VERSION} GCC_VERSION) SET(DFHACK_PACKAGE_SUFFIX "-gcc-${GCC_VERSION}") - if(APPLE) - SET(CPACK_GENERATOR "ZIP;TBZ2") - else() - SET(CPACK_GENERATOR "TBZ2") - endif() + SET(CPACK_GENERATOR "TBZ2") ELSEIF(WIN32) SET(CPACK_GENERATOR "ZIP") ENDIF() From 335607d1f85a055575f1ad7898a6319569a5594b Mon Sep 17 00:00:00 2001 From: Japa Date: Mon, 31 Oct 2016 17:38:43 +0530 Subject: [PATCH 211/413] Update Stonesense. --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 5db5f9151..0cad9f7b7 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 5db5f9151d4140b53169fcb7bed3383991b33326 +Subproject commit 0cad9f7b7e88a1508aeea0bef848ed5eee39987f From d8f3d7d8f94be8cd3a962e54096fe74ae29e7955 Mon Sep 17 00:00:00 2001 From: Japa Date: Mon, 31 Oct 2016 22:52:17 +0530 Subject: [PATCH 212/413] Send dye color with items in remotefortressreader.cpp --- plugins/proto/RemoteFortressReader.proto | 1 + plugins/remotefortressreader.cpp | 62 ++++++++++++++++++------ 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 6b730d8c2..4e6f5ba3e 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -214,6 +214,7 @@ message Item optional uint32 flags2 = 4; optional MatPair type = 5; optional MatPair material = 6; + optional ColorDefinition dye = 7; } message MapBlock diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 0d642e589..dbafb22d6 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -61,6 +61,10 @@ #include "df/graphic.h" #include "df/historical_figure.h" #include "df/item.h" +#include "df/item_constructed.h" +#include "df/item_threadst.h" +#include "df/itemimprovement.h" +#include "df/itemimprovement_threadst.h" #include "df/itemdef.h" #include "df/job.h" #include "df/job_type.h" @@ -295,6 +299,14 @@ void ConvertDfColor(int16_t in[3], RemoteFortressReader::ColorDefinition * out) ConvertDfColor(index, out); } +void ConvertDFColorDescriptor(int16_t index, RemoteFortressReader::ColorDefinition * out) +{ + df::descriptor_color *color = world->raws.language.colors[index]; + out->set_red(color->red * 255); + out->set_green(color->green * 255); + out->set_blue(color->blue * 255); +} + void CopyBuilding(int buildingIndex, RemoteFortressReader::BuildingInstance * remote_build) { df::building * local_build = df::global::world->buildings.all[buildingIndex]; @@ -1030,10 +1042,7 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage mat_def->set_name(mat.toString()); //find the name at cave temperature; if (raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)] < raws->language.colors.size()) { - df::descriptor_color *color = raws->language.colors[raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)]]; - mat_def->mutable_state_color()->set_red(color->red * 255); - mat_def->mutable_state_color()->set_green(color->green * 255); - mat_def->mutable_state_color()->set_blue(color->blue * 255); + ConvertDFColorDescriptor(raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)], mat_def->mutable_state_color()); } } for (int i = 0; i < 19; i++) @@ -1051,10 +1060,7 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage mat_def->set_name(mat.toString()); //find the name at cave temperature; if (raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])] < raws->language.colors.size()) { - df::descriptor_color *color = raws->language.colors[raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])]]; - mat_def->mutable_state_color()->set_red(color->red * 255); - mat_def->mutable_state_color()->set_green(color->green * 255); - mat_def->mutable_state_color()->set_blue(color->blue * 255); + ConvertDFColorDescriptor(raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])], mat_def->mutable_state_color()); } } } @@ -1071,10 +1077,7 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage mat_def->set_name(mat.toString()); //find the name at cave temperature; if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) { - df::descriptor_color *color = raws->language.colors[creature->material[j]->state_color[GetState(creature->material[j])]]; - mat_def->mutable_state_color()->set_red(color->red * 255); - mat_def->mutable_state_color()->set_green(color->green * 255); - mat_def->mutable_state_color()->set_blue(color->blue * 255); + ConvertDFColorDescriptor(creature->material[j]->state_color[GetState(creature->material[j])], mat_def->mutable_state_color()); } } } @@ -1116,10 +1119,7 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage mat_def->set_name(mat.toString()); //find the name at cave temperature; if (plant->material[j]->state_color[GetState(plant->material[j])] < raws->language.colors.size()) { - df::descriptor_color *color = raws->language.colors[plant->material[j]->state_color[GetState(plant->material[j])]]; - mat_def->mutable_state_color()->set_red(color->red * 255); - mat_def->mutable_state_color()->set_green(color->green * 255); - mat_def->mutable_state_color()->set_blue(color->blue * 255); + ConvertDFColorDescriptor(plant->material[j]->state_color[GetState(plant->material[j])], mat_def->mutable_state_color()); } } } @@ -1531,6 +1531,36 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) { type->set_mat_index(DfItem->isBag()); } + auto constructed_item = virtual_cast(DfItem); + if(constructed_item) + { + for (int i = 0; i < constructed_item->improvements.size(); i++) + { + auto improvement = constructed_item->improvements[i]; + if (!improvement || improvement->getType() != improvement_type::THREAD) + continue; + + auto improvement_thread = virtual_cast(improvement); + if (!improvement_thread || improvement_thread->dye.mat_type < 0) + continue; + + DFHack::MaterialInfo info; + if (!info.decode(improvement_thread->dye.mat_type, improvement_thread->dye.mat_index)) + continue; + + ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); + } + } + else if (DfItem->getType() == item_type::THREAD) + { + auto thread = virtual_cast(DfItem); + if (thread && thread->dye_mat_type >= 0) + { + DFHack::MaterialInfo info; + if (info.decode(thread->dye_mat_type, thread->dye_mat_index)) + ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); + } + } } void CopyItems(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) From a50af3e96cec71329ee1d414b846a02d40d4df2f Mon Sep 17 00:00:00 2001 From: Japa Date: Mon, 31 Oct 2016 22:52:45 +0530 Subject: [PATCH 213/413] Update stonesense --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 0cad9f7b7..642e493ef 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 0cad9f7b7e88a1508aeea0bef848ed5eee39987f +Subproject commit 642e493efcf8e8d803186950cd11eef3982d496e From e769041983176d3cf142b8efccad6b407bc92a14 Mon Sep 17 00:00:00 2001 From: Japa Date: Tue, 1 Nov 2016 23:34:56 +0530 Subject: [PATCH 214/413] Fix crash bug in remotefortressreader, that happened every time the user resumed. --- plugins/remotefortressreader.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index dbafb22d6..4caa8e55f 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1641,7 +1641,7 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in bool itemsChanged = areItemsChanged(&block->items); //bool bldChanged = IsBuildingChanged(pos); RemoteFortressReader::MapBlock *net_block; - if (tileChanged || desChanged || spatterChanged || buildingChanged) + if (tileChanged || desChanged || spatterChanged || buildingChanged || itemsChanged) net_block = out->add_map_blocks(); if (tileChanged) { @@ -1682,20 +1682,6 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in } } } - //for (int yy = in->min_y(); yy < in->max_y(); yy++) - //{ - // for (int xx = in->min_x(); xx < in->max_x(); xx++) - // { - // DFCoord pos = DFCoord(xx, yy, zz); - // df::map_block * block = DFHack::Maps::getBlock(pos); - // if (block == NULL) - // continue; - // { - // RemoteFortressReader::MapBlock *net_block = out->add_map_blocks(); - // CopyBlock(block, net_block, &MC, pos); - // } - // } - //} } MC.trash(); return CR_OK; From 04ad7a0a42fedd3a0a33c4c0b2c9380f1341b900 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 2 Nov 2016 16:23:32 -0400 Subject: [PATCH 215/413] Replace some instances of "cmake -E copy_if_different" with a standalone script @JapaMala reported that CMake < 3.5 doesn't support copy_if_different with multiple source files. https://cmake.org/cmake/help/v3.5/release/3.5.html#command-line --- depends/copy-if-different.pl | 30 ++++++++++++++++++++++++++++++ library/CMakeLists.txt | 2 +- plugins/CMakeLists.txt | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100755 depends/copy-if-different.pl diff --git a/depends/copy-if-different.pl b/depends/copy-if-different.pl new file mode 100755 index 000000000..2ba08a80e --- /dev/null +++ b/depends/copy-if-different.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl + +# A replacement for "cmake -E copy_if_different" that supports multiple files, +# which old cmake versions do not support + +# Usage: copy-if-different.pl src-file [src-file...] dest-dir + +use strict; +use warnings; + +use Digest::SHA; +use File::Basename; +use File::Copy; + +sub sha_file { + my $filename = shift; + my $sha = Digest::SHA->new(256); + $sha->addfile($filename); + return $sha->hexdigest; +} + +my $dest_dir = pop @ARGV or die "no destination dir"; +-d $dest_dir or die "not a directory: $dest_dir"; +my @src_files = @ARGV or die "no source files"; + +foreach my $file (@src_files) { + my $dest = "$dest_dir/" . basename($file); + next if -f $dest && sha_file($file) eq sha_file($dest); + copy($file, $dest); +} diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index ed5bfdcd2..9f8477993 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -239,7 +239,7 @@ ADD_CUSTOM_COMMAND( COMMAND protoc-bin -I=${CMAKE_CURRENT_SOURCE_DIR}/proto/ --cpp_out=dllexport_decl=DFHACK_EXPORT:${CMAKE_CURRENT_SOURCE_DIR}/proto/tmp/ ${PROJECT_PROTOS} - COMMAND ${CMAKE_COMMAND} -E copy_if_different + COMMAND ${PERL_EXECUTABLE} ${CMAKE_SOURCE_DIR}/depends/copy-if-different.pl ${PROJECT_PROTO_TMP_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/proto/ COMMENT "Generating core protobufs" diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 612a49715..8546c6e89 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -64,7 +64,7 @@ ADD_CUSTOM_COMMAND( -I=${CMAKE_CURRENT_SOURCE_DIR}/proto/ --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/proto/tmp/ ${PROJECT_PROTOS} - COMMAND ${CMAKE_COMMAND} -E copy_if_different + COMMAND ${PERL_EXECUTABLE} ${CMAKE_SOURCE_DIR}/depends/copy-if-different.pl ${PROJECT_PROTO_TMP_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/proto/ COMMENT "Generating plugin protobufs" From 99051f176b6584561cd94ea96cd173be1f0aeed7 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Sun, 6 Nov 2016 10:08:28 +0530 Subject: [PATCH 216/413] Add a single bool dfproto message, to pausing and checking pause state --- plugins/proto/RemoteFortressReader.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 4e6f5ba3e..c0ed000c7 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -749,4 +749,9 @@ message DigCommand { optional TileDigDesignation designation = 1; repeated Coord locations = 2; +} + +message SingleBool +{ + optional bool Value = 1; } \ No newline at end of file From 5fb986bde1d5c6600ec5b0d4ac8f1f4677aa31c4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 7 Nov 2016 15:07:27 -0500 Subject: [PATCH 217/413] Warn for GCC versions before 4.8 --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61b9dce12..4a47d0721 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,9 @@ macro(CHECK_GCC COMPILER_PATH) # http://developerblog.redhat.com/2015/02/05/gcc5-and-the-c11-abi/ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) endif() + if(${GCC_VERSION_OUT} VERSION_LESS "4.8") + message(WARNING "You are using GCC < 4.8 (detected version: ${GCC_VERSION_OUT}). Support for GCC versions before 4.8 may be removed in the future.") + endif() endmacro() if(UNIX) From ebc1a6d85e89db03bcf79ae671bedb6dad9b64ca Mon Sep 17 00:00:00 2001 From: Japa Date: Tue, 8 Nov 2016 13:40:08 +0530 Subject: [PATCH 218/413] Add functions to get and set the pause state in DF --- plugins/remotefortressreader.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 4caa8e55f..d1803dc0b 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -145,6 +145,8 @@ static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in static command_result CopyScreen(color_ostream &stream, const EmptyMessage *in, ScreenCapture *out); static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEvent *in); static command_result SendDigCommand(color_ostream &stream, const DigCommand *in); +static command_result SetPauseState(color_ostream & stream, const SingleBool * in); +static command_result GetPauseState(color_ostream & stream, const EmptyMessage * in, SingleBool * out); void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); @@ -250,6 +252,8 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("CopyScreen", CopyScreen); svc->addFunction("PassKeyboardEvent", PassKeyboardEvent); svc->addFunction("SendDigCommand", SendDigCommand); + svc->addFunction("SetPauseState", SetPauseState); + svc->addFunction("GetPauseState", GetPauseState); return svc; } @@ -3008,3 +3012,15 @@ static command_result SendDigCommand(color_ostream &stream, const DigCommand *in mc.WriteAll(); return CR_OK; } + +static command_result SetPauseState(color_ostream &stream, const SingleBool *in) +{ + DFHack::World::SetPauseState(in->value()); + return CR_OK; +} + +static command_result GetPauseState(color_ostream &stream, const EmptyMessage *in, SingleBool *out) +{ + out->set_value(World::ReadPauseState()); + return CR_OK; +} \ No newline at end of file From 2935032a1e13b59b069ad8ee94b4db391e85e7ce Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Tue, 8 Nov 2016 15:10:01 +0530 Subject: [PATCH 219/413] Add .proto files to plugin sources when used, to make it conventient to open it from the IDE. --- plugins/Plugins.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/Plugins.cmake b/plugins/Plugins.cmake index 4871c1f0c..fe167ccb3 100644 --- a/plugins/Plugins.cmake +++ b/plugins/Plugins.cmake @@ -76,6 +76,7 @@ MACRO(DFHACK_PLUGIN) SET(PLUGIN_PROTOCPP) FOREACH(pbuf ${PLUGIN_PROTOBUFS}) SET(PLUGIN_SOURCES ${PLUGIN_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/proto/${pbuf}.pb.cc) + SET(PLUGIN_SOURCES ${PLUGIN_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/proto/${pbuf}.proto) SET(PLUGIN_PROTOCPP ${PLUGIN_PROTOCPP} ${CMAKE_CURRENT_SOURCE_DIR}/proto/${pbuf}.pb.cc) ENDFOREACH() From fbaf2697cb10c7ae20b575ac87c533baba00b490 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Tue, 8 Nov 2016 15:10:43 +0530 Subject: [PATCH 220/413] fixed MD5 hash of win64 ruby lib. --- plugins/ruby/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ruby/CMakeLists.txt b/plugins/ruby/CMakeLists.txt index 6b5e62c66..f7d35433a 100644 --- a/plugins/ruby/CMakeLists.txt +++ b/plugins/ruby/CMakeLists.txt @@ -38,7 +38,7 @@ ELSE() ${RUBYLIB}.gz "81db54a8b8b3090c94c6ae2147d30b8f" ${RUBYLIB} - "8a8564418aebddef3dfee1e96690e713") + "8568db86a202b803ad7616c53b25bf75") ELSE() DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-libruby187.dll.gz" "gz" From 20b9aab8dbf4577e7d7d489aaacaf2b338512c13 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Tue, 8 Nov 2016 15:11:27 +0530 Subject: [PATCH 221/413] moved remotefortressreader.cpp to its own directory. --- plugins/CMakeLists.txt | 2 +- plugins/remotefortressreader/CMakeLists.txt | 36 +++++++++++++++++++ .../remotefortressreader.cpp | 0 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 plugins/remotefortressreader/CMakeLists.txt rename plugins/{ => remotefortressreader}/remotefortressreader.cpp (100%) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 8546c6e89..0e4c8f999 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -141,7 +141,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(prospector prospector.cpp) DFHACK_PLUGIN(power-meter power-meter.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(regrass regrass.cpp) - DFHACK_PLUGIN(RemoteFortressReader remotefortressreader.cpp proto/RemoteFortressReader.proto PROTOBUFS RemoteFortressReader) + add_subdirectory(remotefortressreader) DFHACK_PLUGIN(rename rename.cpp LINK_LIBRARIES lua PROTOBUFS rename) add_subdirectory(rendermax) DFHACK_PLUGIN(resume resume.cpp) diff --git a/plugins/remotefortressreader/CMakeLists.txt b/plugins/remotefortressreader/CMakeLists.txt new file mode 100644 index 000000000..be03e604f --- /dev/null +++ b/plugins/remotefortressreader/CMakeLists.txt @@ -0,0 +1,36 @@ +PROJECT (remotefortressreader) +# A list of source files +SET(PROJECT_SRCS + remotefortressreader.cpp +) +# A list of headers +SET(PROJECT_HDRS + +) +#proto files to include. +SET(PROJECT_PROTO + ../../proto/RemoteFortressReader +) + +SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE) + +# mash them together (headers are marked as headers and nothing will try to compile them) +LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS}) + +#linux +IF(UNIX) + add_definitions(-DLINUX_BUILD) + SET(PROJECT_LIBS + # add any extra linux libs here + ${PROJECT_LIBS} + ) +# windows +ELSE(UNIX) + SET(PROJECT_LIBS + # add any extra windows libs here + ${PROJECT_LIBS} + $(NOINHERIT) + ) +ENDIF(UNIX) +# this makes sure all the stuff is put in proper places and linked to dfhack +DFHACK_PLUGIN(RemoteFortressReader ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS} PROTOBUFS ${PROJECT_PROTO} ) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp similarity index 100% rename from plugins/remotefortressreader.cpp rename to plugins/remotefortressreader/remotefortressreader.cpp From 5e204069ce0ffbd6717cf2d91c980d45fb56e773 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Tue, 8 Nov 2016 15:13:06 +0530 Subject: [PATCH 222/413] update stonesense --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 642e493ef..416bc28f2 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 642e493efcf8e8d803186950cd11eef3982d496e +Subproject commit 416bc28f2e25d06e7da28a5643b8a849aefddbf5 From 6895f3fbedeaec90a9492e0de786e7f88344cf13 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Tue, 8 Nov 2016 15:13:43 +0530 Subject: [PATCH 223/413] remove tabs --- plugins/remotefortressreader/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/remotefortressreader/CMakeLists.txt b/plugins/remotefortressreader/CMakeLists.txt index be03e604f..0b84d8905 100644 --- a/plugins/remotefortressreader/CMakeLists.txt +++ b/plugins/remotefortressreader/CMakeLists.txt @@ -9,7 +9,7 @@ SET(PROJECT_HDRS ) #proto files to include. SET(PROJECT_PROTO - ../../proto/RemoteFortressReader + ../../proto/RemoteFortressReader ) SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE) From 8fec45696d9f09c5ef060a0c4ac9450e89fedce0 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 8 Nov 2016 12:01:24 -0600 Subject: [PATCH 224/413] Better job assignment algorithm for labormanager. --- plugins/labormanager.cpp | 266 ++++++++++++++++++++++----------------- 1 file changed, 149 insertions(+), 117 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 5a2774cd2..298568a41 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -414,23 +414,23 @@ struct labor_default static std::vector labor_infos; static const struct labor_default default_labor_infos[] = { - /* MINEa */ {200, 0, TOOL_PICK}, + /* MINE */ {100, 0, TOOL_PICK}, /* HAUL_STONE */ {100, 0, TOOL_NONE}, /* HAUL_WOOD */ {100, 0, TOOL_NONE}, - /* HAUL_BODY */ {200, 0, TOOL_NONE}, - /* HAUL_FOOD */ {300, 0, TOOL_NONE}, - /* HAUL_REFUSE */ {100, 0, TOOL_NONE}, + /* HAUL_BODY */ {1000, 0, TOOL_NONE}, + /* HAUL_FOOD */ {500, 0, TOOL_NONE}, + /* HAUL_REFUSE */ {200, 0, TOOL_NONE}, /* HAUL_ITEM */ {100, 0, TOOL_NONE}, /* HAUL_FURNITURE */ {100, 0, TOOL_NONE}, /* HAUL_ANIMAL */ {100, 0, TOOL_NONE}, - /* CLEAN */ {200, 0, TOOL_NONE}, - /* CUTWOOD */ {200, 0, TOOL_AXE}, - /* CARPENTER */ {200, 0, TOOL_NONE}, - /* DETAIL */ {200, 0, TOOL_NONE}, - /* MASON */ {200, 0, TOOL_NONE}, - /* ARCHITECT */ {400, 0, TOOL_NONE}, - /* ANIMALTRAIN */ {200, 0, TOOL_NONE}, - /* ANIMALCARE */ {200, 0, TOOL_NONE}, + /* CLEAN */ {100, 0, TOOL_NONE}, + /* CUTWOOD */ {100, 0, TOOL_AXE}, + /* CARPENTER */ {100, 0, TOOL_NONE}, + /* DETAIL */ {100, 0, TOOL_NONE}, + /* MASON */ {100, 0, TOOL_NONE}, + /* ARCHITECT */ {100, 0, TOOL_NONE}, + /* ANIMALTRAIN */ {100, 0, TOOL_NONE}, + /* ANIMALCARE */ {100, 0, TOOL_NONE}, /* DIAGNOSE */ {1000, 0, TOOL_NONE}, /* SURGERY */ {1000, 0, TOOL_NONE}, /* BONE_SETTING */ {1000, 0, TOOL_NONE}, @@ -438,65 +438,65 @@ static const struct labor_default default_labor_infos[] = { /* DRESSING_WOUNDS */ {1000, 0, TOOL_NONE}, /* FEED_WATER_CIVILIANS */ {1000, 0, TOOL_NONE}, /* RECOVER_WOUNDED */ {200, 0, TOOL_NONE}, - /* BUTCHER */ {200, 0, TOOL_NONE}, - /* TRAPPER */ {200, 0, TOOL_NONE}, - /* DISSECT_VERMIN */ {200, 0, TOOL_NONE}, - /* LEATHER */ {200, 0, TOOL_NONE}, - /* TANNER */ {200, 0, TOOL_NONE}, - /* BREWER */ {200, 0, TOOL_NONE}, - /* ALCHEMIST */ {200, 0, TOOL_NONE}, - /* SOAP_MAKER */ {200, 0, TOOL_NONE}, - /* WEAVER */ {200, 0, TOOL_NONE}, - /* CLOTHESMAKER */ {200, 0, TOOL_NONE}, - /* MILLER */ {200, 0, TOOL_NONE}, - /* PROCESS_PLANT */ {200, 0, TOOL_NONE}, - /* MAKE_CHEESE */ {200, 0, TOOL_NONE}, - /* MILK */ {200, 0, TOOL_NONE}, - /* COOK */ {200, 0, TOOL_NONE}, - /* PLANT */ {200, 0, TOOL_NONE}, - /* HERBALIST */ {200, 0, TOOL_NONE}, + /* BUTCHER */ {500, 0, TOOL_NONE}, + /* TRAPPER */ {100, 0, TOOL_NONE}, + /* DISSECT_VERMIN */ {100, 0, TOOL_NONE}, + /* LEATHER */ {100, 0, TOOL_NONE}, + /* TANNER */ {100, 0, TOOL_NONE}, + /* BREWER */ {100, 0, TOOL_NONE}, + /* ALCHEMIST */ {100, 0, TOOL_NONE}, + /* SOAP_MAKER */ {100, 0, TOOL_NONE}, + /* WEAVER */ {100, 0, TOOL_NONE}, + /* CLOTHESMAKER */ {100, 0, TOOL_NONE}, + /* MILLER */ {100, 0, TOOL_NONE}, + /* PROCESS_PLANT */ {100, 0, TOOL_NONE}, + /* MAKE_CHEESE */ {100, 0, TOOL_NONE}, + /* MILK */ {100, 0, TOOL_NONE}, + /* COOK */ {100, 0, TOOL_NONE}, + /* PLANT */ {100, 0, TOOL_NONE}, + /* HERBALIST */ {100, 0, TOOL_NONE}, /* FISH */ {100, 0, TOOL_NONE}, - /* CLEAN_FISH */ {200, 0, TOOL_NONE}, - /* DISSECT_FISH */ {200, 0, TOOL_NONE}, + /* CLEAN_FISH */ {100, 0, TOOL_NONE}, + /* DISSECT_FISH */ {100, 0, TOOL_NONE}, /* HUNT */ {100, 0, TOOL_CROSSBOW}, - /* SMELT */ {200, 0, TOOL_NONE}, - /* FORGE_WEAPON */ {200, 0, TOOL_NONE}, - /* FORGE_ARMOR */ {200, 0, TOOL_NONE}, - /* FORGE_FURNITURE */ {200, 0, TOOL_NONE}, - /* METAL_CRAFT */ {200, 0, TOOL_NONE}, - /* CUT_GEM */ {200, 0, TOOL_NONE}, - /* ENCRUST_GEM */ {200, 0, TOOL_NONE}, - /* WOOD_CRAFT */ {200, 0, TOOL_NONE}, - /* STONE_CRAFT */ {200, 0, TOOL_NONE}, - /* BONE_CARVE */ {200, 0, TOOL_NONE}, - /* GLASSMAKER */ {200, 0, TOOL_NONE}, - /* EXTRACT_STRAND */ {200, 0, TOOL_NONE}, - /* SIEGECRAFT */ {200, 0, TOOL_NONE}, - /* SIEGEOPERATE */ {200, 0, TOOL_NONE}, - /* BOWYER */ {200, 0, TOOL_NONE}, - /* MECHANIC */ {200, 0, TOOL_NONE}, - /* POTASH_MAKING */ {200, 0, TOOL_NONE}, - /* LYE_MAKING */ {200, 0, TOOL_NONE}, - /* DYER */ {200, 0, TOOL_NONE}, - /* BURN_WOOD */ {200, 0, TOOL_NONE}, - /* OPERATE_PUMP */ {200, 0, TOOL_NONE}, - /* SHEARER */ {200, 0, TOOL_NONE}, - /* SPINNER */ {200, 0, TOOL_NONE}, - /* POTTERY */ {200, 0, TOOL_NONE}, - /* GLAZING */ {200, 0, TOOL_NONE}, - /* PRESSING */ {200, 0, TOOL_NONE}, - /* BEEKEEPING */ {200, 0, TOOL_NONE}, - /* WAX_WORKING */ {200, 0, TOOL_NONE}, - /* PUSH_HAUL_VEHICLES */ {200, 0, TOOL_NONE}, - /* HAUL_TRADE */ {200, 0, TOOL_NONE}, - /* PULL_LEVER */ {200, 0, TOOL_NONE}, - /* REMOVE_CONSTRUCTION */ {200, 0, TOOL_NONE}, - /* HAUL_WATER */ {200, 0, TOOL_NONE}, - /* GELD */ {200, 0, TOOL_NONE}, - /* BUILD_ROAD */ {200, 0, TOOL_NONE}, - /* BUILD_CONSTRUCTION */ {200, 0, TOOL_NONE}, - /* PAPERMAKING */ {200, 0, TOOL_NONE}, - /* BOOKBINDING */ {200, 0, TOOL_NONE} + /* SMELT */ {100, 0, TOOL_NONE}, + /* FORGE_WEAPON */ {100, 0, TOOL_NONE}, + /* FORGE_ARMOR */ {100, 0, TOOL_NONE}, + /* FORGE_FURNITURE */ {100, 0, TOOL_NONE}, + /* METAL_CRAFT */ {100, 0, TOOL_NONE}, + /* CUT_GEM */ {100, 0, TOOL_NONE}, + /* ENCRUST_GEM */ {100, 0, TOOL_NONE}, + /* WOOD_CRAFT */ {100, 0, TOOL_NONE}, + /* STONE_CRAFT */ {100, 0, TOOL_NONE}, + /* BONE_CARVE */ {100, 0, TOOL_NONE}, + /* GLASSMAKER */ {100, 0, TOOL_NONE}, + /* EXTRACT_STRAND */ {100, 0, TOOL_NONE}, + /* SIEGECRAFT */ {100, 0, TOOL_NONE}, + /* SIEGEOPERATE */ {100, 0, TOOL_NONE}, + /* BOWYER */ {100, 0, TOOL_NONE}, + /* MECHANIC */ {100, 0, TOOL_NONE}, + /* POTASH_MAKING */ {100, 0, TOOL_NONE}, + /* LYE_MAKING */ {100, 0, TOOL_NONE}, + /* DYER */ {100, 0, TOOL_NONE}, + /* BURN_WOOD */ {100, 0, TOOL_NONE}, + /* OPERATE_PUMP */ {100, 0, TOOL_NONE}, + /* SHEARER */ {100, 0, TOOL_NONE}, + /* SPINNER */ {100, 0, TOOL_NONE}, + /* POTTERY */ {100, 0, TOOL_NONE}, + /* GLAZING */ {100, 0, TOOL_NONE}, + /* PRESSING */ {100, 0, TOOL_NONE}, + /* BEEKEEPING */ {100, 0, TOOL_NONE}, + /* WAX_WORKING */ {100, 0, TOOL_NONE}, + /* PUSH_HAUL_VEHICLES */ {100, 0, TOOL_NONE}, + /* HAUL_TRADE */ {1000, 0, TOOL_NONE}, + /* PULL_LEVER */ {1000, 0, TOOL_NONE}, + /* REMOVE_CONSTRUCTION */ {100, 0, TOOL_NONE}, + /* HAUL_WATER */ {100, 0, TOOL_NONE}, + /* GELD */ {100, 0, TOOL_NONE}, + /* BUILD_ROAD */ {100, 0, TOOL_NONE}, + /* BUILD_CONSTRUCTION */ {100, 0, TOOL_NONE}, + /* PAPERMAKING */ {100, 0, TOOL_NONE}, + /* BOOKBINDING */ {100, 0, TOOL_NONE} }; void debug (char* fmt, ...); @@ -852,12 +852,13 @@ private: return df::unit_labor::TRAPPER; case df::building_type::Civzone: case df::building_type::Nest: - case df::building_type::RoadDirt: case df::building_type::Stockpile: case df::building_type::Weapon: return df::unit_labor::NONE; case df::building_type::SiegeEngine: return df::unit_labor::SIEGECRAFT; + case df::building_type::RoadDirt: + return df::unit_labor::BUILD_ROAD; } debug ("LABORMANAGER: Cannot deduce labor for construct building job of type %s\n", @@ -1167,13 +1168,13 @@ public: job_to_labor_table[df::job_type::CheckChest] = jlf_no_labor; job_to_labor_table[df::job_type::StoreOwnedItem] = jlf_no_labor; job_to_labor_table[df::job_type::PlaceItemInTomb] = jlf_const(df::unit_labor::HAUL_BODY); - job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list - job_to_labor_table[df::job_type::StoreItemInBag] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list + job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_hauling; + job_to_labor_table[df::job_type::StoreItemInBag] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInHospital] = jlf_hauling; job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling; job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list - job_to_labor_table[df::job_type::StoreItemInBin] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list + job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling; + job_to_labor_table[df::job_type::StoreItemInBin] = jlf_hauling; job_to_labor_table[df::job_type::SeekArtifact] = jlf_no_labor; job_to_labor_table[df::job_type::SeekInfant] = jlf_no_labor; job_to_labor_table[df::job_type::AttendParty] = jlf_no_labor; @@ -1676,20 +1677,24 @@ private: if (bld != -1) { df::building* b = binsearch_in_vector(world->buildings.all, bld); - int fjid = -1; - for (int jn = 0; jn < b->jobs.size(); jn++) - { - if (b->jobs[jn]->flags.bits.suspend) - continue; - fjid = b->jobs[jn]->id; - break; - } + // check if this job is the first nonsuspended job on this building; if not, ignore it // (except for farms and trade depots) - if (fjid != j->id && - b->getType() != df::building_type::FarmPlot && - b->getType() != df::building_type::TradeDepot) - return; + + if (b->getType() != df::building_type::FarmPlot && + b->getType() != df::building_type::TradeDepot) + { + int fjid = -1; + for (int jn = 0; jn < b->jobs.size(); jn++) + { + if (b->jobs[jn]->flags.bits.suspend) + continue; + fjid = b->jobs[jn]->id; + break; + } + if (fjid != j->id) + return; + } } df::unit_labor labor = labor_mapper->find_job_labor (j); @@ -2056,7 +2061,8 @@ private: out.print("Dwarf \"%s\": state %s %d\n", dwarf->dwarf->name.first_name.c_str(), state_names[dwarf->state], dwarf->clear_all); // determine if dwarf has medical needs - if (dwarf->dwarf->health) + // babies cannot currently receive health care even if they need it + if (dwarf->dwarf->profession != profession::BABY && dwarf->dwarf->health) { if (dwarf->dwarf->health->flags.bits.needs_recovery) cnt_recover_wounded++; @@ -2160,13 +2166,10 @@ private: if (labor == df::unit_labor::OPERATE_PUMP) score += 50000; else - score += 1000; + score += 25000; if (default_labor_infos[labor].tool != TOOL_NONE && d->has_tool[default_labor_infos[labor].tool]) - score += 30000; - if (default_labor_infos[labor].tool != TOOL_NONE && - !d->has_tool[default_labor_infos[labor].tool]) - score -= 30000; + score += 10000000; if (d->has_children && labor_outside[labor]) score -= 15000; if (d->armed && labor_outside[labor]) @@ -2361,8 +2364,6 @@ public: } - labor_needed[df::unit_labor::CLEAN] = 1; - if (print_debug) { for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) @@ -2372,7 +2373,9 @@ public: } } + std::map base_priority; priority_queue> pq; + priority_queue> pq2; for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) { @@ -2383,15 +2386,16 @@ public: if (labor_infos[l].maximum_dwarfs() > 0 && i->second > labor_infos[l].maximum_dwarfs()) i->second = labor_infos[l].maximum_dwarfs(); - if (i->second > 0) - { - int priority = labor_infos[l].priority(); - if (l < df::unit_labor::HAUL_STONE || l > df::unit_labor::HAUL_ANIMALS) - priority += labor_infos[l].time_since_last_assigned()/12; + int priority = labor_infos[l].priority(); + + priority += labor_infos[l].time_since_last_assigned()/12; + priority -= labor_infos[l].busy_dwarfs; + + base_priority[l] = priority; - for (int n = 0; n < labor_infos[l].busy_dwarfs; n++) - priority /= 2; + if (i->second > 0) + { pq.push(make_pair(priority, l)); } } @@ -2418,9 +2422,22 @@ public: if (--labor_needed[labor] > 0) { - priority /= 2; - pq.push(make_pair(priority, labor)); + priority-=10; + pq2.push(make_pair(priority, labor)); } + + if (pq.empty()) + while(!pq2.empty()) + { + pq.push(pq2.top()); + pq2.pop(); + } + } + + while (!pq2.empty()) + { + pq.push(pq2.top()); + pq2.pop(); } int canary = (1 << df::unit_labor::HAUL_STONE) | @@ -2475,7 +2492,7 @@ public: if (l == best_labor && ( t == TOOL_NONE || tool_in_use[t] < tool_count[t]) ) { set_labor(*bestdwarf, l, true); - if (t != TOOL_NONE && (*bestdwarf)->has_tool[t]) + if (t != TOOL_NONE && !((*bestdwarf)->has_tool[t])) { df::job_type j; j = df::job_type::NONE; @@ -2526,8 +2543,7 @@ public: continue; int score = score_labor (*d, l); - if (l < df::unit_labor::HAUL_STONE || l > df::unit_labor::HAUL_ANIMALS) - score += labor_infos[l].time_since_last_assigned()/12; + if (l == df::unit_labor::HAUL_FOOD && priority_food > 0) score += 1000000; @@ -2538,7 +2554,9 @@ public: { set_labor(*d, l, true); } - if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000 && default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) + if ((*d)->using_labor != df::unit_labor::NONE && + (score > current_score + 5000 || base_priority[(*d)->using_labor] < base_priority[l]) && + default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) set_labor(*d, (*d)->using_labor, false); } } @@ -2579,18 +2597,23 @@ public: /* Assign any leftover dwarfs to "standard" labors */ + if (print_debug) + out.print ("After assignment, %d dwarfs left over\n", available_dwarfs.size()); + for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); d++) { FOR_ENUM_ITEMS (unit_labor, l) { - if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && - canary & (1 << l)) - set_labor(*d, l, true); - else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION || l == df::unit_labor::PULL_LEVER) - set_labor(*d, l, true); - else - set_labor(*d, l, false); - } + if (l == df::unit_labor::NONE) + continue; + + set_labor(*d, l, + (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS) || + l == df::unit_labor::CLEAN || + l == df::unit_labor::REMOVE_CONSTRUCTION || + l == df::unit_labor::PULL_LEVER || + l == df::unit_labor::HAUL_TRADE); + } } /* check for dwarfs assigned no labors and assign them the bucket list if there are */ @@ -2648,7 +2671,8 @@ public: bool has_tool = (*d)->has_tool[t]; bool needs_tool = (*d)->dwarf->status.labors[l]; - if (has_tool != needs_tool) + if ((needs_tool && !has_tool) || + (has_tool && !needs_tool && tool_in_use[t] >= tool_count[t])) { df::job_type j = df::job_type::NONE; @@ -2675,6 +2699,10 @@ public: *df::global::process_jobs = true; } + if (print_debug) { + *df::global::pause_state = true; + } + print_debug = 0; } @@ -2709,8 +2737,12 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) return CR_OK; } - if (++step_count < 60) +// if (++step_count < 60) +// return CR_OK; + + if (*df::global::process_jobs) return CR_OK; + step_count = 0; debug_stream = &out; From ae59b4f5ad91000995bdc5dc0b5b480e1e18b892 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 10 Nov 2016 14:25:05 -0500 Subject: [PATCH 225/413] Update xml, scripts --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 81e2cf023..84f6e968a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 81e2cf023422ad6f01061db12586a0589ef6eac5 +Subproject commit 84f6e968a9ec5515f9dbef96b445e3fc83f83e8b diff --git a/scripts b/scripts index b285334a8..bcd7ed20d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit b285334a8a91c0b43bac9d3e362b95fcbfa472c7 +Subproject commit bcd7ed20d5c096beabd58b0c7ec3f90ce08a67f4 From 8d9b888410ac49d34395f2004ea76c286ae7878e Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 14 Nov 2016 14:16:43 -0500 Subject: [PATCH 226/413] Revert "fixed MD5 hash of win64 ruby lib." Unable to get anything other than 8a856 for the extracted library on my end This reverts commit fbaf2697cb10c7ae20b575ac87c533baba00b490. --- plugins/ruby/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ruby/CMakeLists.txt b/plugins/ruby/CMakeLists.txt index f7d35433a..6b5e62c66 100644 --- a/plugins/ruby/CMakeLists.txt +++ b/plugins/ruby/CMakeLists.txt @@ -38,7 +38,7 @@ ELSE() ${RUBYLIB}.gz "81db54a8b8b3090c94c6ae2147d30b8f" ${RUBYLIB} - "8568db86a202b803ad7616c53b25bf75") + "8a8564418aebddef3dfee1e96690e713") ELSE() DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-libruby187.dll.gz" "gz" From c05f3d7d30d16a80666bfbe71354133a97b962c1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 14 Nov 2016 14:18:34 -0500 Subject: [PATCH 227/413] Update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index bcd7ed20d..8dc528f1b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit bcd7ed20d5c096beabd58b0c7ec3f90ce08a67f4 +Subproject commit 8dc528f1b02b14afd3ad6267d9e350b6840def6b From 1e41cdc7f60d5c415b3554073456a07a9c1e2b20 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 16 Nov 2016 15:20:22 -0500 Subject: [PATCH 228/413] Fix labormanager docs --- docs/Plugins.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 85b6ba58d..fac50d254 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -860,9 +860,11 @@ any particular type of job. Simple usage: :enable labormanager: Enables the plugin with default settings. -(Persistent per fortress) :disable labormanager: Disables the plugin. + (Persistent per fortress) -Anything beyond this is optional - autolabor works fairly well on the +:disable labormanager: Disables the plugin. + +Anything beyond this is optional - labormanager works fairly well on the default settings. The default priorities for each labor vary (some labors are higher @@ -924,7 +926,7 @@ the dfhack console, followed by the message "LABORMANAGER: Game paused so you can investigate the above message.". If this happens, please open an issue on github, reporting the lines that immediately preceded this message. You can tell labormanager to ignore this error and carry on by -typing "autolabor pause-on-error no", but be warned that some job may go +typing ``labormanager pause-on-error no``, but be warned that some job may go undone in this situation. Advanced usage: From dce00a5034e04f0606eac006f19e6e839e2930d3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 16 Nov 2016 15:21:13 -0500 Subject: [PATCH 229/413] Partial compilation fixes for advtools, misery --- plugins/advtools.cpp | 11 ++++++----- plugins/misery.cpp | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp index 77cc02934..50868560d 100644 --- a/plugins/advtools.cpp +++ b/plugins/advtools.cpp @@ -17,6 +17,7 @@ #include "df/item.h" #include "df/unit.h" #include "df/unit_inventory_item.h" +#include "df/unit_relationship_type.h" #include "df/map_block.h" #include "df/nemesis_record.h" #include "df/historical_figure.h" @@ -139,7 +140,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) switch (ui_advmode->menu) { case Travel: - case Sleep: + // was also Sleep, now equivalent revert = true; break; default: @@ -218,7 +219,7 @@ df::nemesis_record *getPlayerNemesis(color_ostream &out, bool restore_swap) out.print("Returned into the body of %s.\n", name.c_str()); } - real_nemesis->unit->relations.group_leader_id = -1; + real_nemesis->unit->relationship_ids[df::unit_relationship_type::GroupLeader] = -1; in_transient_swap = false; } @@ -237,7 +238,7 @@ void changeGroupLeader(df::nemesis_record *new_nemesis, df::nemesis_record *old_ // Update follow new_nemesis->group_leader_id = -1; - new_nemesis->unit->relations.group_leader_id = -1; + new_nemesis->unit->relationship_ids[df::unit_relationship_type::GroupLeader] = -1; for (unsigned i = 0; i < cvec.size(); i++) { @@ -247,7 +248,7 @@ void changeGroupLeader(df::nemesis_record *new_nemesis, df::nemesis_record *old_ nm->group_leader_id = new_nemesis->id; if (nm->unit) - nm->unit->relations.group_leader_id = new_nemesis->unit_id; + nm->unit->relationship_ids[df::unit_relationship_type::GroupLeader] = new_nemesis->unit_id; } } @@ -721,7 +722,7 @@ command_result adv_bodyswap (color_ostream &out, std::vector & par // Make the player unit follow around to avoid bad consequences // if it is unloaded before the transient swap is reverted. - real_nemesis->unit->relations.group_leader_id = new_nemesis->unit_id; + real_nemesis->unit->relationship_ids[df::unit_relationship_type::GroupLeader] = new_nemesis->unit_id; } return CR_OK; diff --git a/plugins/misery.cpp b/plugins/misery.cpp index a4468079c..59b745871 100644 --- a/plugins/misery.cpp +++ b/plugins/misery.cpp @@ -5,7 +5,6 @@ #include "df/world.h" #include "df/ui.h" #include "df/unit.h" -#include "df/unit_thought.h" #include "df/unit_thought_type.h" #include From df9b5bca7311489748ab100dfc51080841c3f196 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 17 Nov 2016 10:31:48 -0500 Subject: [PATCH 230/413] Allow ruby plugin to try more than one library path, including libruby.so on Linux --- plugins/ruby/ruby.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 0470541e1..5aa04da04 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -318,22 +318,28 @@ DFHack::DFLibrary *libruby_handle; // load the ruby library, initialize function pointers static int df_loadruby(void) { - const char *libpath = + const char *libpaths[] = { #if defined(WIN32) - "./libruby.dll"; + "./libruby.dll", #elif defined(__APPLE__) - #ifdef DFHACK64 - "/System/Library/Frameworks/Ruby.framework/Ruby"; - #else - "hack/libruby.dylib"; - #endif + "hack/libruby.dylib", + "/System/Library/Frameworks/Ruby.framework/Ruby", #else - "hack/libruby.so"; + "hack/libruby.so", + "libruby.so", #endif + NULL + }; + + for (const char **path = libpaths; *path; path++) { + if ((libruby_handle = OpenPlugin(*path))) + break; + else + fprintf(stderr, "ruby: warning: Failed to load %s\n", *path); + } - libruby_handle = OpenPlugin(libpath); if (!libruby_handle) { - fprintf(stderr, "Cannot initialize ruby plugin: failed to load %s\n", libpath); + Core::printerr("Cannot initialize ruby plugin: failed to load ruby library\n"); return 0; } From 74f5df99db12bd111785fd6e3cfc49ca5b460ab9 Mon Sep 17 00:00:00 2001 From: Stephen Baynham Date: Thu, 17 Nov 2016 00:11:15 -0800 Subject: [PATCH 231/413] Add job remove method Job remove eliminates a job's worker & holder references, if any, puts the worker on cd, if appropriate, removes the job's postings, eliminates the job from the global linked list, and then finally deletes it. This code was tested by incorporating it into autochop and it does make the plugin work. However, chop jobs don't have holder building references, and anyway, with DF being 90% edge case by volume, this could use a heck of a lot more testing. I saw elsewhere code that prevented worker removal if the job was a special job, and that made me feel funny so I made the job remove method not work if the job is a special job. --- library/include/modules/Job.h | 5 +++ library/modules/Job.cpp | 65 ++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/library/include/modules/Job.h b/library/include/modules/Job.h index fbbed9ff3..78a694b6f 100644 --- a/library/include/modules/Job.h +++ b/library/include/modules/Job.h @@ -66,6 +66,11 @@ namespace DFHack DFHACK_EXPORT void setJobCooldown(df::building *workshop, df::unit *worker, int cooldown = 100); DFHACK_EXPORT bool removeWorker(df::job *job, int cooldown = 100); + // Delete a job & remove all refs from everywhere. + // This method DELETES the job object! Everything related to it will be wiped + // clean from the earth, so make sure you pull what you need out before calling this! + DFHACK_EXPORT void removeJob(df::job *job); + // Instruct the game to check and assign workers DFHACK_EXPORT void checkBuildingsNow(); DFHACK_EXPORT void checkDesignationsNow(); diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index 2678eadba..d187989a0 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -212,7 +212,7 @@ void DFHack::Job::printJobDetails(color_ostream &out, df::job *job) out.color(job->flags.bits.suspend ? COLOR_DARKGREY : COLOR_GREY); out << "Job " << job->id << ": " << ENUM_KEY_STR(job_type,job->job_type); if (job->flags.whole) - out << " (" << bitfield_to_string(job->flags) << ")"; + out << " (" << bitfield_to_string(job->flags) << ")"; out << endl; out.reset_color(); @@ -304,6 +304,68 @@ void DFHack::Job::setJobCooldown(df::building *workshop, df::unit *worker, int c } } +void DFHack::Job::removeJob(df::job *job) { + using df::global::world; + CHECK_NULL_POINTER(job); + + if (job->flags.bits.special) //I don't think you can cancel these, because DF wasn't build to expect it? + return; + + //As far as I know there are only two general refs jobs have, the unit assigned to work it (if any) + //and the workshop it was created at (if any). It's possible there are others, so we go ahead and wipe all + //refs, but these two are the only ones that we really handle with any intelligence. If other refs + //exist that might have return-references that need to be cleared, that needs to be implemented!!!! + auto holderRef = getGeneralRef(job, general_ref_type::BUILDING_HOLDER); + auto workerRef = getGeneralRef(job, general_ref_type::UNIT_WORKER); + df::building *holder = NULL; + df::unit *worker = NULL; + + if (holderRef) holder = holderRef->getBuilding(); + if (workerRef) worker = workerRef->getUnit(); + + //removeWorker() adds a job cd about right now, but I chose not to do that because I'm pretty sure + //that's only to stop removed workers from immediately reclaiming the job before doing something + //else, and this job is gonna be dead in a second. + + //Remove return-refs from the holder & worker + if (holder) { + int jobIndex = linear_index(holder->jobs, job); + if (jobIndex >= 0) + vector_erase_at(holder->jobs, jobIndex); + } + + if (worker) { + if (worker->job.current_job == job) + worker->job.current_job = NULL; + } + + //Wipe all refs out + while (job->general_refs.size() > 0) { + auto ref = job->general_refs[0]; + vector_erase_at(job->general_refs, 0); + delete ref; + } + + //Remove job from job board + Job::removePostings(job, true); + + //Remove job from global list + if (job->list_link) { + auto prev = job->list_link->prev; + auto next = job->list_link->next; + + if (prev) + prev->next = next; + + if (next) + next->prev = prev; + + delete job->list_link; + } + + delete job; +} + bool DFHack::Job::removeWorker(df::job *job, int cooldown) { CHECK_NULL_POINTER(job); @@ -397,6 +459,7 @@ bool DFHack::Job::removePostings(df::job *job, bool remove_all) { if ((**it).job == job) { + (**it).job = NULL; (**it).flags.bits.dead = true; removed = true; } From 67af9f5e82ff0c45043aa2508f8346b17e77d5a9 Mon Sep 17 00:00:00 2001 From: Stephen Baynham Date: Thu, 17 Nov 2016 23:04:48 -0800 Subject: [PATCH 232/413] Add lua bindings for removeJob --- library/LuaApi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 712ccb541..4416a9066 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1469,6 +1469,7 @@ static const LuaWrapper::FunctionReg dfhack_job_module[] = { WRAPM(Job,getName), WRAPM(Job,linkIntoWorld), WRAPM(Job,removePostings), + WRAPM(Job,removeJob), WRAPN(is_equal, jobEqual), WRAPN(is_item_equal, jobItemEqual), { NULL, NULL } From fba32f2e2fb2256037a358e2d0170c0607b65f6c Mon Sep 17 00:00:00 2001 From: Stephen Baynham Date: Thu, 17 Nov 2016 23:25:48 -0800 Subject: [PATCH 233/413] Also disconnect the job from its items. --- library/modules/Job.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index d187989a0..f8bf00240 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -346,6 +346,33 @@ void DFHack::Job::removeJob(df::job *job) { delete ref; } + //Detach all items from the job + while (job->items.size() > 0) { + auto itemRef = job->items[0]; + df::item *item = NULL; + + if (itemRef) { + item = itemRef->item; + + if (item) { + item->flags.bits.in_job = false; + + //Work backward through the specific refs & remove/delete all specific refs to this job + int refCount = item->specific_refs.size(); + for(int refIndex = refCount-1; refIndex >= 0; refIndex--) { + auto ref = item->specific_refs[refIndex]; + if (ref->type == df::specific_ref_type::JOB && ref->job == job) { + vector_erase_at(item->specific_refs, refIndex); + delete ref; + } + } + } + + delete itemRef; + } + vector_erase_at(job->items, 0); + } + //Remove job from job board Job::removePostings(job, true); From 8b964ca2dcdd7bbf33d099d4916a185fde8dd8ca Mon Sep 17 00:00:00 2001 From: Stephen Baynham Date: Mon, 21 Nov 2016 06:51:21 -0800 Subject: [PATCH 234/413] Wipe job_items vector --- library/modules/Job.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index f8bf00240..0ee17ddd1 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -376,6 +376,15 @@ void DFHack::Job::removeJob(df::job *job) { //Remove job from job board Job::removePostings(job, true); + //Clean up job_items + while (job->job_items.size() > 0) { + auto jobItem = job->job_items[0]; + vector_erase_at(job->job_items, 0); + if (jobItem) { + delete jobItem; + } + } + //Remove job from global list if (job->list_link) { auto prev = job->list_link->prev; From 80e0a91670f09a84b5e15d0ac6ec2d9befd680f2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Nov 2016 16:54:50 -0500 Subject: [PATCH 235/413] Update .travis.yml for 0.43.05 --- .travis.yml | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5e60a1461..59faf012d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,13 +9,6 @@ addons: - zlib1g-dev:i386 matrix: include: - - env: GCC_VERSION=4.5 - addons: - apt: - packages: - - *default_packages - - gcc-4.5-multilib - - g++-4.5-multilib - env: GCC_VERSION=4.8 addons: apt: @@ -41,10 +34,10 @@ script: - cd build-travis - cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DBUILD_DOCS:BOOL=ON - make -j3 -notifications: - email: false - irc: - channels: - - "chat.freenode.net#dfhack" - on_success: change - on_failure: always +# notifications: +# email: false +# irc: +# channels: +# - "chat.freenode.net#dfhack" +# on_success: change +# on_failure: always From 647ef4d556b295ebbb14c80eb2ce72b013f7704b Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Nov 2016 17:17:56 -0500 Subject: [PATCH 236/413] Fix labormanager whitespace --- plugins/labormanager.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index ede083488..35454e6cb 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1683,7 +1683,7 @@ private: // (except for farms and trade depots) if (b->getType() != df::building_type::FarmPlot && - b->getType() != df::building_type::TradeDepot) + b->getType() != df::building_type::TradeDepot) { int fjid = -1; for (int jn = 0; jn < b->jobs.size(); jn++) @@ -2389,10 +2389,10 @@ public: i->second = labor_infos[l].maximum_dwarfs(); int priority = labor_infos[l].priority(); - + priority += labor_infos[l].time_since_last_assigned()/12; priority -= labor_infos[l].busy_dwarfs; - + base_priority[l] = priority; if (i->second > 0) @@ -2427,8 +2427,8 @@ public: pq2.push(make_pair(priority, labor)); } - if (pq.empty()) - while(!pq2.empty()) + if (pq.empty()) + while(!pq2.empty()) { pq.push(pq2.top()); pq2.pop(); @@ -2555,8 +2555,8 @@ public: { set_labor(*d, l, true); } - if ((*d)->using_labor != df::unit_labor::NONE && - (score > current_score + 5000 || base_priority[(*d)->using_labor] < base_priority[l]) && + if ((*d)->using_labor != df::unit_labor::NONE && + (score > current_score + 5000 || base_priority[(*d)->using_labor] < base_priority[l]) && default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) set_labor(*d, (*d)->using_labor, false); } @@ -2608,10 +2608,10 @@ public: if (l == df::unit_labor::NONE) continue; - set_labor(*d, l, - (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS) || - l == df::unit_labor::CLEAN || - l == df::unit_labor::REMOVE_CONSTRUCTION || + set_labor(*d, l, + (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS) || + l == df::unit_labor::CLEAN || + l == df::unit_labor::REMOVE_CONSTRUCTION || l == df::unit_labor::PULL_LEVER || l == df::unit_labor::HAUL_TRADE); } @@ -2741,7 +2741,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) // if (++step_count < 60) // return CR_OK; - if (*df::global::process_jobs) + if (*df::global::process_jobs) return CR_OK; step_count = 0; From c7a35d7ecec4d75888359a2ade1a67d05edca4db Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Nov 2016 17:24:36 -0500 Subject: [PATCH 237/413] fix remotefortressreader protobuf error in clean builds --- plugins/remotefortressreader/proto/readme.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 plugins/remotefortressreader/proto/readme.txt diff --git a/plugins/remotefortressreader/proto/readme.txt b/plugins/remotefortressreader/proto/readme.txt new file mode 100644 index 000000000..8cd56aefd --- /dev/null +++ b/plugins/remotefortressreader/proto/readme.txt @@ -0,0 +1 @@ +placeholder to fix protobufs in plugins/remotefortressreader/CMakeLists.txt From 206e9ef993dbd7602d12655662b1ccff3b32e313 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Nov 2016 17:31:36 -0500 Subject: [PATCH 238/413] Re-enable Travis IRC notifications --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 59faf012d..22fe49e2d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,10 +34,10 @@ script: - cd build-travis - cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DBUILD_DOCS:BOOL=ON - make -j3 -# notifications: -# email: false -# irc: -# channels: -# - "chat.freenode.net#dfhack" -# on_success: change -# on_failure: always +notifications: + email: false + irc: + channels: + - "chat.freenode.net#dfhack" + on_success: change + on_failure: always From b41ace2f8fa1709463709545b89d2c44829ae3fe Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Nov 2016 20:49:38 -0500 Subject: [PATCH 239/413] Update scripts (travis) --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 8dc528f1b..25f85f8c7 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 8dc528f1b02b14afd3ad6267d9e350b6840def6b +Subproject commit 25f85f8c7b7a2f0b5a635a237985952337dcfef7 From 13eb5e702beb6d8e40c0e17be64cda9a8d9d1efb Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Nov 2016 20:50:19 -0500 Subject: [PATCH 240/413] bump to alpha2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a47d0721..654553f6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,7 +140,7 @@ endif() # set up versioning. set(DF_VERSION "0.43.05") -SET(DFHACK_RELEASE "alpha1") +SET(DFHACK_RELEASE "alpha2") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From dd28079f30e671f32a2341f7d5de2fcc4e50a411 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Nov 2016 22:43:48 -0500 Subject: [PATCH 241/413] Fix ruby.cpp compilation on win64 --- plugins/ruby/ruby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 5aa04da04..006d63402 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -596,7 +596,7 @@ static VALUE rb_dfget_rtti_classname(VALUE self, VALUE vptr) #if defined(_WIN64) // win64 char *rtti = *(char**)(ptr - 0x8); - char *typeinfo = Core::getInstance().p->getBase() + *(uint32_t*)(rtti + 0xC); + char *typeinfo = (char*)Core::getInstance().p->getBase() + *(uint32_t*)(rtti + 0xC); // skip the .?AV, trim @@ from end return rb_str_new(typeinfo+0x14, strlen(typeinfo+0x14)-2); #elif defined(WIN32) From 08840ccabf60f8e7295cb9f1bfc524a8f7824942 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 23 Nov 2016 19:20:20 -0500 Subject: [PATCH 242/413] Add abbradar to Authors.rst (da3c6404f) --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 195b90c44..242f6a7d3 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -72,6 +72,7 @@ mizipzor mizipzor moversti moversti Neil Little nmlittle Nick Rart nickrart comestible +Nikolay Amiantov abbradar Omniclasm PeridexisErrant PeridexisErrant Petr Mrázek peterix From e490afdf0058da782f6d9b8c1c09f559fcd2c81f Mon Sep 17 00:00:00 2001 From: Stephen Baynham Date: Thu, 24 Nov 2016 22:36:11 -0800 Subject: [PATCH 243/413] Rebuilt slightly to offer bool return val We fail on unknown general ref types now, without modifying the job at all yet --- library/LuaApi.cpp | 2 + library/include/modules/Job.h | 12 +++- library/modules/Job.cpp | 126 ++++++++++++++++++++-------------- 3 files changed, 89 insertions(+), 51 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 4416a9066..7f0e629a7 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1469,6 +1469,8 @@ static const LuaWrapper::FunctionReg dfhack_job_module[] = { WRAPM(Job,getName), WRAPM(Job,linkIntoWorld), WRAPM(Job,removePostings), + WRAPM(Job,disconnectJobItem), + WRAPM(Job,disconnectJobGeneralRef), WRAPM(Job,removeJob), WRAPN(is_equal, jobEqual), WRAPN(is_item_equal, jobItemEqual), diff --git a/library/include/modules/Job.h b/library/include/modules/Job.h index 78a694b6f..1448b6656 100644 --- a/library/include/modules/Job.h +++ b/library/include/modules/Job.h @@ -66,10 +66,20 @@ namespace DFHack DFHACK_EXPORT void setJobCooldown(df::building *workshop, df::unit *worker, int cooldown = 100); DFHACK_EXPORT bool removeWorker(df::job *job, int cooldown = 100); + // This helpful method only removes the backref from the item to the job, but it doesn't + // remove the item ref from the job's vector, or delete it or anything. Think of it as a method + // that does all the needful to make an item ref ready to delete. + DFHACK_EXPORT void disconnectJobItem(df::job_item_ref *item, df::job *job); + // This helpful method only removes the backref from whatever the general_ref points to, + // it doesn't remove the general_ref from the job's vector, or delete it or anything. + // Think of it as a method that does all the needful to make a ref ready to delete. + // If it returns false, you've found a ref that the method doesn't know how to handle. Congratulations! + // You should report that and/or check in a fix. + DFHACK_EXPORT bool disconnectJobGeneralRef(df::general_ref *ref, df::job *job); // Delete a job & remove all refs from everywhere. // This method DELETES the job object! Everything related to it will be wiped // clean from the earth, so make sure you pull what you need out before calling this! - DFHACK_EXPORT void removeJob(df::job *job); + DFHACK_EXPORT bool removeJob(df::job *job); // Instruct the game to check and assign workers DFHACK_EXPORT void checkBuildingsNow(); diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index 0ee17ddd1..b1f262f09 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -304,73 +304,98 @@ void DFHack::Job::setJobCooldown(df::building *workshop, df::unit *worker, int c } } -void DFHack::Job::removeJob(df::job *job) { +void DFHack::Job::disconnectJobItem(df::job_item_ref *ref, df::job *job) { + if (!ref) return; + + auto item = ref->item; + if (!item) return; + + //Work backward through the specific refs & remove/delete all specific refs to this job + int refCount = item->specific_refs.size(); + bool stillHasJobs = false; + for(int refIndex = refCount-1; refIndex >= 0; refIndex--) { + auto ref = item->specific_refs[refIndex]; + + if (ref->type == df::specific_ref_type::JOB) { + if (ref->job == job) { + vector_erase_at(item->specific_refs, refIndex); + delete ref; + } else { + stillHasJobs = true; + } + } + } + + if (!stillHasJobs) item->flags.bits.in_job = false; +} + +bool DFHack::Job::disconnectJobGeneralRef(df::general_ref *ref, df::job *job) { + if (ref == NULL) return true; + + switch (ref->getType()) { + case general_ref_type::BUILDING_HOLDER: + auto building = ref->getBuilding(); + + if (building != NULL) { + int jobIndex = linear_index(building->jobs, job); + if (jobIndex >= 0) { + vector_erase_at(building->jobs, jobIndex); + } + } + break; + case general_ref_type::UNIT_WORKER: + auto unit = ref->getUnit(); + + if (unit != NULL) { + if (unit->job.current_job == job) { + unit->job.current_job = NULL; + } + } + break; + default: + return false; + } + + return true; +} + +bool DFHack::Job::removeJob(df::job *job) { using df::global::world; CHECK_NULL_POINTER(job); if (job->flags.bits.special) //I don't think you can cancel these, because DF wasn't build to expect it? - return; + return false; - //As far as I know there are only two general refs jobs have, the unit assigned to work it (if any) - //and the workshop it was created at (if any). It's possible there are others, so we go ahead and wipe all - //refs, but these two are the only ones that we really handle with any intelligence. If other refs - //exist that might have return-references that need to be cleared, that needs to be implemented!!!! - auto holderRef = getGeneralRef(job, general_ref_type::BUILDING_HOLDER); - auto workerRef = getGeneralRef(job, general_ref_type::UNIT_WORKER); - df::building *holder = NULL; - df::unit *worker = NULL; - - if (holderRef) holder = holderRef->getBuilding(); - if (workerRef) worker = workerRef->getUnit(); - - //removeWorker() adds a job cd about right now, but I chose not to do that because I'm pretty sure - //that's only to stop removed workers from immediately reclaiming the job before doing something - //else, and this job is gonna be dead in a second. - - //Remove return-refs from the holder & worker - if (holder) { - int jobIndex = linear_index(holder->jobs, job); - if (jobIndex >= 0) - vector_erase_at(holder->jobs, jobIndex); - } + //We actually only know how to handle BUILDING_HOLDER and UNIT_WORKER refs- there's probably a great + //way to handle them, but until we have a good example, we'll just fail to remove jobs that have other sorts + //of refs, or any specific refs + if (job->specific_refs.size() > 0) + return false; - if (worker) { - if (worker->job.current_job == job) - worker->job.current_job = NULL; + for (auto genRefItr = job->general_refs.begin(); genRefItr != job->general_refs.end(); ++genRefItr) { + auto ref = *genRefItr; + if (ref != NULL && (ref->getType() != general_ref_type::BUILDING_HOLDER && ref->getType() != general_ref_type::UNIT_WORKER)) + return false; } - //Wipe all refs out + //Disconnect, delete, and wipe all general refs while (job->general_refs.size() > 0) { auto ref = job->general_refs[0]; + + //Our code above should have ensured that this won't return false- if it does, there's not + //a great way of recovering since we can't properly destroy the job & we can't leave it + //around. Better to know the moment that becomes a problem. + assert(disconnectJobGeneralRef(ref, job)); vector_erase_at(job->general_refs, 0); - delete ref; + if (ref != NULL) delete ref; } //Detach all items from the job while (job->items.size() > 0) { auto itemRef = job->items[0]; - df::item *item = NULL; - - if (itemRef) { - item = itemRef->item; - - if (item) { - item->flags.bits.in_job = false; - - //Work backward through the specific refs & remove/delete all specific refs to this job - int refCount = item->specific_refs.size(); - for(int refIndex = refCount-1; refIndex >= 0; refIndex--) { - auto ref = item->specific_refs[refIndex]; - if (ref->type == df::specific_ref_type::JOB && ref->job == job) { - vector_erase_at(item->specific_refs, refIndex); - delete ref; - } - } - } - - delete itemRef; - } + disconnectJobItem(itemRef, job); vector_erase_at(job->items, 0); + if (itemRef != NULL) delete itemRef; } //Remove job from job board @@ -400,6 +425,7 @@ void DFHack::Job::removeJob(df::job *job) { } delete job; + return true; } bool DFHack::Job::removeWorker(df::job *job, int cooldown) From de0e211e07dbc0e044096efbaf783d31d9759046 Mon Sep 17 00:00:00 2001 From: Stephen Baynham Date: Thu, 24 Nov 2016 23:35:03 -0800 Subject: [PATCH 244/413] Figured I could like test my code. --- library/modules/Job.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index b1f262f09..531c85773 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -332,9 +332,12 @@ void DFHack::Job::disconnectJobItem(df::job_item_ref *ref, df::job *job) { bool DFHack::Job::disconnectJobGeneralRef(df::general_ref *ref, df::job *job) { if (ref == NULL) return true; + df::building *building = NULL; + df::unit *unit = NULL; + switch (ref->getType()) { case general_ref_type::BUILDING_HOLDER: - auto building = ref->getBuilding(); + building = ref->getBuilding(); if (building != NULL) { int jobIndex = linear_index(building->jobs, job); @@ -344,7 +347,7 @@ bool DFHack::Job::disconnectJobGeneralRef(df::general_ref *ref, df::job *job) { } break; case general_ref_type::UNIT_WORKER: - auto unit = ref->getUnit(); + unit = ref->getUnit(); if (unit != NULL) { if (unit->job.current_job == job) { @@ -385,7 +388,9 @@ bool DFHack::Job::removeJob(df::job *job) { //Our code above should have ensured that this won't return false- if it does, there's not //a great way of recovering since we can't properly destroy the job & we can't leave it //around. Better to know the moment that becomes a problem. - assert(disconnectJobGeneralRef(ref, job)); + bool success = disconnectJobGeneralRef(ref, job); + assert(success); + vector_erase_at(job->general_refs, 0); if (ref != NULL) delete ref; } From 7920f71517622ef2f28cdd1cab6be2d0ec25d191 Mon Sep 17 00:00:00 2001 From: Stephen Baynham Date: Fri, 25 Nov 2016 00:25:18 -0800 Subject: [PATCH 245/413] Bad formatting --- library/include/modules/Job.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/include/modules/Job.h b/library/include/modules/Job.h index 1448b6656..439a4484d 100644 --- a/library/include/modules/Job.h +++ b/library/include/modules/Job.h @@ -68,16 +68,16 @@ namespace DFHack // This helpful method only removes the backref from the item to the job, but it doesn't // remove the item ref from the job's vector, or delete it or anything. Think of it as a method - // that does all the needful to make an item ref ready to delete. + // that does all the needful to make an item ref ready to delete. DFHACK_EXPORT void disconnectJobItem(df::job_item_ref *item, df::job *job); // This helpful method only removes the backref from whatever the general_ref points to, // it doesn't remove the general_ref from the job's vector, or delete it or anything. - // Think of it as a method that does all the needful to make a ref ready to delete. + // Think of it as a method that does all the needful to make a ref ready to delete. // If it returns false, you've found a ref that the method doesn't know how to handle. Congratulations! // You should report that and/or check in a fix. DFHACK_EXPORT bool disconnectJobGeneralRef(df::general_ref *ref, df::job *job); // Delete a job & remove all refs from everywhere. - // This method DELETES the job object! Everything related to it will be wiped + // This method DELETES the job object! Everything related to it will be wiped // clean from the earth, so make sure you pull what you need out before calling this! DFHACK_EXPORT bool removeJob(df::job *job); From f71d19578c43e605bbcb00417b01ab4e08e62520 Mon Sep 17 00:00:00 2001 From: nocico Date: Sat, 26 Nov 2016 13:34:56 +0200 Subject: [PATCH 246/413] make labormanager know building instruments is furniture hauling --- plugins/labormanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 35454e6cb..7e2bf9584 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -842,6 +842,7 @@ private: case df::building_type::BarsVertical: case df::building_type::GrateWall: case df::building_type::Bookcase: + case df::building_type::Instrument: return df::unit_labor::HAUL_FURNITURE; case df::building_type::Trap: case df::building_type::GearAssembly: From b723378a627d8e344f70f793fe47808663a412e0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 26 Nov 2016 14:06:31 -0500 Subject: [PATCH 247/413] Add nocico to Authors.rst (f71d195) --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 242f6a7d3..c606fbe38 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -73,6 +73,7 @@ moversti moversti Neil Little nmlittle Nick Rart nickrart comestible Nikolay Amiantov abbradar +nocico nocico Omniclasm PeridexisErrant PeridexisErrant Petr Mrázek peterix From 8eb4f17b239ed6ccc4c6162df1eb9bc2d48bb351 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 26 Nov 2016 17:37:26 -0600 Subject: [PATCH 248/413] Use attributes in calculating assignment weight --- plugins/labormanager.cpp | 156 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 2 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index ede083488..ed3390868 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1505,9 +1505,152 @@ static void generate_labor_to_skill_map() labor_to_skill[labor] = skill; } } - } +struct skill_attr_weight { + int phys_attr_weights [6]; + int mental_attr_weights [13]; +}; + +static struct skill_attr_weight skill_attr_weights[ENUM_LAST_ITEM(job_skill) + 1] = +{ + // S A T E R D AA F W C I P M LA SS M KS E SA + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MINING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WOODCUTTING */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CARPENTRY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DETAILSTONE */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MASONRY */, + { { 0, 1, 1, 1, 0, 0 }, { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 } } /* ANIMALTRAIN */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 } } /* ANIMALCARE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISSECT_FISH */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISSECT_VERMIN */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROCESSFISH */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BUTCHER */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* TRAPPING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* TANNER */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WEAVING */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BREWING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ALCHEMY */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CLOTHESMAKING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILLING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROCESSPLANTS */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CHEESEMAKING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILK */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* COOK */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLANT */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* HERBALISM */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } } /* FISH */, + { { 1, 0, 1, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SMELT */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* EXTRACT_STRAND */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_WEAPON */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_ARMOR */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_FURNITURE */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CUTGEM */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ENCRUSTGEM */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WOODCRAFT */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* STONECRAFT */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* METALCRAFT */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GLASSMAKER */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* LEATHERWORK */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BONECARVE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* AXE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SWORD */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DAGGER */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MACE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* HAMMER */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SPEAR */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CROSSBOW */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SHIELD */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* ARMOR */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SIEGECRAFT */, + { { 1, 0, 1, 1, 0, 0 }, { 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SIEGEOPERATE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BOWYER */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* PIKE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WHIP */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BOW */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BLOWGUN */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* THROW */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MECHANICS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MAGIC_NATURE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SNEAK */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DESIGNBUILDING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0 } } /* DRESS_WOUNDS */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 } } /* DIAGNOSE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SURGERY */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SET_BONE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SUTURE */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CRUTCH_WALK */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* WOOD_BURNING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* LYE_MAKING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SOAP_MAKING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* POTASH_MAKING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DYER */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* OPERATE_PUMP */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SWIMMING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* PERSUASION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* NEGOTIATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1 } } /* JUDGING_INTENT */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 } } /* APPRAISAL */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 } } /* ORGANIZATION */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* RECORD_KEEPING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 } } /* LYING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 } } /* INTIMIDATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* CONVERSATION */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 } } /* COMEDY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* FLATTERY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0 } } /* CONSOLE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* PACIFY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* TRACKING */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* KNOWLEDGE_ACQUISITION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } } /* CONCENTRATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISCIPLINE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SITUATIONAL_AWARENESS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* WRITING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROSE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* POETRY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* READING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SPEAKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* COORDINATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BALANCE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* LEADERSHIP */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* TEACHING */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MELEE_COMBAT */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* RANGED_COMBAT */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WRESTLING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BITE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GRASP_STRIKE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* STANCE_STRIKE */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DODGING */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MISC_WEAPON */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* KNAPPING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILITARY_TACTICS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SHEARING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SPINNING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* POTTERY */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GLAZING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PRESSING */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BEEKEEPING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WAX_WORKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CLIMBING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* GELD */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DANCE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MAKE_MUSIC */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SING_MUSIC */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_KEYBOARD_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_STRINGED_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_WIND_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_PERCUSSION_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CRITICAL_THINKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* LOGIC */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MATHEMATICS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ASTRONOMY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CHEMISTRY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* GEOGRAPHY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* OPTICS_ENGINEER */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FLUID_ENGINEER */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PAPERMAKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BOOKBINDING */ +}; static void enable_plugin(color_ostream &out) { @@ -2148,6 +2291,7 @@ private: { int skill_level = 0; int xp = 0; + int attr_weight = 0; if (labor != df::unit_labor::NONE) { @@ -2156,10 +2300,16 @@ private: { skill_level = Units::getEffectiveSkill(d->dwarf, skill); xp = Units::getExperience(d->dwarf, skill, false); + + for (int pa = 0; pa < 6; pa++) + attr_weight += (skill_attr_weights[skill].phys_attr_weights[pa]) * (d->dwarf->body.physical_attrs[pa].value - 1000); + + for (int ma = 0; ma < 13; ma++) + attr_weight += (skill_attr_weights[skill].mental_attr_weights[ma]) * (d->dwarf->status.current_soul->mental_attrs[ma].value - 1000); } } - int score = skill_level * 1000 - (d->high_skill - skill_level) * 2000 + (xp / (skill_level + 5) * 10); + int score = skill_level * 1000 - (d->high_skill - skill_level) * 2000 + (xp / (skill_level + 5) * 10) + attr_weight; if (labor != df::unit_labor::NONE) { @@ -2177,6 +2327,8 @@ private: score += 5000; } + score -= Units::computeMovementSpeed(d->dwarf); + return score; } From fe1dd01535bf6f7ee0ad384780906886a6034206 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 8 Nov 2016 12:01:24 -0600 Subject: [PATCH 249/413] Better job assignment algorithm for labormanager. --- plugins/devel/labormanager.cpp | 266 ++++++++++++++++++--------------- 1 file changed, 149 insertions(+), 117 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index 7d41c7814..ae1f2c17c 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -414,23 +414,23 @@ struct labor_default static std::vector labor_infos; static const struct labor_default default_labor_infos[] = { - /* MINEa */ {200, 0, TOOL_PICK}, + /* MINE */ {100, 0, TOOL_PICK}, /* HAUL_STONE */ {100, 0, TOOL_NONE}, /* HAUL_WOOD */ {100, 0, TOOL_NONE}, - /* HAUL_BODY */ {200, 0, TOOL_NONE}, - /* HAUL_FOOD */ {300, 0, TOOL_NONE}, - /* HAUL_REFUSE */ {100, 0, TOOL_NONE}, + /* HAUL_BODY */ {1000, 0, TOOL_NONE}, + /* HAUL_FOOD */ {500, 0, TOOL_NONE}, + /* HAUL_REFUSE */ {200, 0, TOOL_NONE}, /* HAUL_ITEM */ {100, 0, TOOL_NONE}, /* HAUL_FURNITURE */ {100, 0, TOOL_NONE}, /* HAUL_ANIMAL */ {100, 0, TOOL_NONE}, - /* CLEAN */ {200, 0, TOOL_NONE}, - /* CUTWOOD */ {200, 0, TOOL_AXE}, - /* CARPENTER */ {200, 0, TOOL_NONE}, - /* DETAIL */ {200, 0, TOOL_NONE}, - /* MASON */ {200, 0, TOOL_NONE}, - /* ARCHITECT */ {400, 0, TOOL_NONE}, - /* ANIMALTRAIN */ {200, 0, TOOL_NONE}, - /* ANIMALCARE */ {200, 0, TOOL_NONE}, + /* CLEAN */ {100, 0, TOOL_NONE}, + /* CUTWOOD */ {100, 0, TOOL_AXE}, + /* CARPENTER */ {100, 0, TOOL_NONE}, + /* DETAIL */ {100, 0, TOOL_NONE}, + /* MASON */ {100, 0, TOOL_NONE}, + /* ARCHITECT */ {100, 0, TOOL_NONE}, + /* ANIMALTRAIN */ {100, 0, TOOL_NONE}, + /* ANIMALCARE */ {100, 0, TOOL_NONE}, /* DIAGNOSE */ {1000, 0, TOOL_NONE}, /* SURGERY */ {1000, 0, TOOL_NONE}, /* BONE_SETTING */ {1000, 0, TOOL_NONE}, @@ -438,65 +438,65 @@ static const struct labor_default default_labor_infos[] = { /* DRESSING_WOUNDS */ {1000, 0, TOOL_NONE}, /* FEED_WATER_CIVILIANS */ {1000, 0, TOOL_NONE}, /* RECOVER_WOUNDED */ {200, 0, TOOL_NONE}, - /* BUTCHER */ {200, 0, TOOL_NONE}, - /* TRAPPER */ {200, 0, TOOL_NONE}, - /* DISSECT_VERMIN */ {200, 0, TOOL_NONE}, - /* LEATHER */ {200, 0, TOOL_NONE}, - /* TANNER */ {200, 0, TOOL_NONE}, - /* BREWER */ {200, 0, TOOL_NONE}, - /* ALCHEMIST */ {200, 0, TOOL_NONE}, - /* SOAP_MAKER */ {200, 0, TOOL_NONE}, - /* WEAVER */ {200, 0, TOOL_NONE}, - /* CLOTHESMAKER */ {200, 0, TOOL_NONE}, - /* MILLER */ {200, 0, TOOL_NONE}, - /* PROCESS_PLANT */ {200, 0, TOOL_NONE}, - /* MAKE_CHEESE */ {200, 0, TOOL_NONE}, - /* MILK */ {200, 0, TOOL_NONE}, - /* COOK */ {200, 0, TOOL_NONE}, - /* PLANT */ {200, 0, TOOL_NONE}, - /* HERBALIST */ {200, 0, TOOL_NONE}, + /* BUTCHER */ {500, 0, TOOL_NONE}, + /* TRAPPER */ {100, 0, TOOL_NONE}, + /* DISSECT_VERMIN */ {100, 0, TOOL_NONE}, + /* LEATHER */ {100, 0, TOOL_NONE}, + /* TANNER */ {100, 0, TOOL_NONE}, + /* BREWER */ {100, 0, TOOL_NONE}, + /* ALCHEMIST */ {100, 0, TOOL_NONE}, + /* SOAP_MAKER */ {100, 0, TOOL_NONE}, + /* WEAVER */ {100, 0, TOOL_NONE}, + /* CLOTHESMAKER */ {100, 0, TOOL_NONE}, + /* MILLER */ {100, 0, TOOL_NONE}, + /* PROCESS_PLANT */ {100, 0, TOOL_NONE}, + /* MAKE_CHEESE */ {100, 0, TOOL_NONE}, + /* MILK */ {100, 0, TOOL_NONE}, + /* COOK */ {100, 0, TOOL_NONE}, + /* PLANT */ {100, 0, TOOL_NONE}, + /* HERBALIST */ {100, 0, TOOL_NONE}, /* FISH */ {100, 0, TOOL_NONE}, - /* CLEAN_FISH */ {200, 0, TOOL_NONE}, - /* DISSECT_FISH */ {200, 0, TOOL_NONE}, + /* CLEAN_FISH */ {100, 0, TOOL_NONE}, + /* DISSECT_FISH */ {100, 0, TOOL_NONE}, /* HUNT */ {100, 0, TOOL_CROSSBOW}, - /* SMELT */ {200, 0, TOOL_NONE}, - /* FORGE_WEAPON */ {200, 0, TOOL_NONE}, - /* FORGE_ARMOR */ {200, 0, TOOL_NONE}, - /* FORGE_FURNITURE */ {200, 0, TOOL_NONE}, - /* METAL_CRAFT */ {200, 0, TOOL_NONE}, - /* CUT_GEM */ {200, 0, TOOL_NONE}, - /* ENCRUST_GEM */ {200, 0, TOOL_NONE}, - /* WOOD_CRAFT */ {200, 0, TOOL_NONE}, - /* STONE_CRAFT */ {200, 0, TOOL_NONE}, - /* BONE_CARVE */ {200, 0, TOOL_NONE}, - /* GLASSMAKER */ {200, 0, TOOL_NONE}, - /* EXTRACT_STRAND */ {200, 0, TOOL_NONE}, - /* SIEGECRAFT */ {200, 0, TOOL_NONE}, - /* SIEGEOPERATE */ {200, 0, TOOL_NONE}, - /* BOWYER */ {200, 0, TOOL_NONE}, - /* MECHANIC */ {200, 0, TOOL_NONE}, - /* POTASH_MAKING */ {200, 0, TOOL_NONE}, - /* LYE_MAKING */ {200, 0, TOOL_NONE}, - /* DYER */ {200, 0, TOOL_NONE}, - /* BURN_WOOD */ {200, 0, TOOL_NONE}, - /* OPERATE_PUMP */ {200, 0, TOOL_NONE}, - /* SHEARER */ {200, 0, TOOL_NONE}, - /* SPINNER */ {200, 0, TOOL_NONE}, - /* POTTERY */ {200, 0, TOOL_NONE}, - /* GLAZING */ {200, 0, TOOL_NONE}, - /* PRESSING */ {200, 0, TOOL_NONE}, - /* BEEKEEPING */ {200, 0, TOOL_NONE}, - /* WAX_WORKING */ {200, 0, TOOL_NONE}, - /* PUSH_HAUL_VEHICLES */ {200, 0, TOOL_NONE}, - /* HAUL_TRADE */ {200, 0, TOOL_NONE}, - /* PULL_LEVER */ {200, 0, TOOL_NONE}, - /* REMOVE_CONSTRUCTION */ {200, 0, TOOL_NONE}, - /* HAUL_WATER */ {200, 0, TOOL_NONE}, - /* GELD */ {200, 0, TOOL_NONE}, - /* BUILD_ROAD */ {200, 0, TOOL_NONE}, - /* BUILD_CONSTRUCTION */ {200, 0, TOOL_NONE}, - /* PAPERMAKING */ {200, 0, TOOL_NONE}, - /* BOOKBINDING */ {200, 0, TOOL_NONE} + /* SMELT */ {100, 0, TOOL_NONE}, + /* FORGE_WEAPON */ {100, 0, TOOL_NONE}, + /* FORGE_ARMOR */ {100, 0, TOOL_NONE}, + /* FORGE_FURNITURE */ {100, 0, TOOL_NONE}, + /* METAL_CRAFT */ {100, 0, TOOL_NONE}, + /* CUT_GEM */ {100, 0, TOOL_NONE}, + /* ENCRUST_GEM */ {100, 0, TOOL_NONE}, + /* WOOD_CRAFT */ {100, 0, TOOL_NONE}, + /* STONE_CRAFT */ {100, 0, TOOL_NONE}, + /* BONE_CARVE */ {100, 0, TOOL_NONE}, + /* GLASSMAKER */ {100, 0, TOOL_NONE}, + /* EXTRACT_STRAND */ {100, 0, TOOL_NONE}, + /* SIEGECRAFT */ {100, 0, TOOL_NONE}, + /* SIEGEOPERATE */ {100, 0, TOOL_NONE}, + /* BOWYER */ {100, 0, TOOL_NONE}, + /* MECHANIC */ {100, 0, TOOL_NONE}, + /* POTASH_MAKING */ {100, 0, TOOL_NONE}, + /* LYE_MAKING */ {100, 0, TOOL_NONE}, + /* DYER */ {100, 0, TOOL_NONE}, + /* BURN_WOOD */ {100, 0, TOOL_NONE}, + /* OPERATE_PUMP */ {100, 0, TOOL_NONE}, + /* SHEARER */ {100, 0, TOOL_NONE}, + /* SPINNER */ {100, 0, TOOL_NONE}, + /* POTTERY */ {100, 0, TOOL_NONE}, + /* GLAZING */ {100, 0, TOOL_NONE}, + /* PRESSING */ {100, 0, TOOL_NONE}, + /* BEEKEEPING */ {100, 0, TOOL_NONE}, + /* WAX_WORKING */ {100, 0, TOOL_NONE}, + /* PUSH_HAUL_VEHICLES */ {100, 0, TOOL_NONE}, + /* HAUL_TRADE */ {1000, 0, TOOL_NONE}, + /* PULL_LEVER */ {1000, 0, TOOL_NONE}, + /* REMOVE_CONSTRUCTION */ {100, 0, TOOL_NONE}, + /* HAUL_WATER */ {100, 0, TOOL_NONE}, + /* GELD */ {100, 0, TOOL_NONE}, + /* BUILD_ROAD */ {100, 0, TOOL_NONE}, + /* BUILD_CONSTRUCTION */ {100, 0, TOOL_NONE}, + /* PAPERMAKING */ {100, 0, TOOL_NONE}, + /* BOOKBINDING */ {100, 0, TOOL_NONE} }; void debug (char* fmt, ...); @@ -852,12 +852,13 @@ private: return df::unit_labor::TRAPPER; case df::building_type::Civzone: case df::building_type::Nest: - case df::building_type::RoadDirt: case df::building_type::Stockpile: case df::building_type::Weapon: return df::unit_labor::NONE; case df::building_type::SiegeEngine: return df::unit_labor::SIEGECRAFT; + case df::building_type::RoadDirt: + return df::unit_labor::BUILD_ROAD; } debug ("LABORMANAGER: Cannot deduce labor for construct building job of type %s\n", @@ -1165,13 +1166,13 @@ public: job_to_labor_table[df::job_type::CheckChest] = jlf_no_labor; job_to_labor_table[df::job_type::StoreOwnedItem] = jlf_no_labor; job_to_labor_table[df::job_type::PlaceItemInTomb] = jlf_const(df::unit_labor::HAUL_BODY); - job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list - job_to_labor_table[df::job_type::StoreItemInBag] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list + job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_hauling; + job_to_labor_table[df::job_type::StoreItemInBag] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInHospital] = jlf_hauling; job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling; job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list - job_to_labor_table[df::job_type::StoreItemInBin] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list + job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling; + job_to_labor_table[df::job_type::StoreItemInBin] = jlf_hauling; job_to_labor_table[df::job_type::SeekArtifact] = jlf_no_labor; job_to_labor_table[df::job_type::SeekInfant] = jlf_no_labor; job_to_labor_table[df::job_type::AttendParty] = jlf_no_labor; @@ -1674,20 +1675,24 @@ private: if (bld != -1) { df::building* b = binsearch_in_vector(world->buildings.all, bld); - int fjid = -1; - for (int jn = 0; jn < b->jobs.size(); jn++) - { - if (b->jobs[jn]->flags.bits.suspend) - continue; - fjid = b->jobs[jn]->id; - break; - } + // check if this job is the first nonsuspended job on this building; if not, ignore it // (except for farms and trade depots) - if (fjid != j->id && - b->getType() != df::building_type::FarmPlot && - b->getType() != df::building_type::TradeDepot) - return; + + if (b->getType() != df::building_type::FarmPlot && + b->getType() != df::building_type::TradeDepot) + { + int fjid = -1; + for (int jn = 0; jn < b->jobs.size(); jn++) + { + if (b->jobs[jn]->flags.bits.suspend) + continue; + fjid = b->jobs[jn]->id; + break; + } + if (fjid != j->id) + return; + } } df::unit_labor labor = labor_mapper->find_job_labor (j); @@ -2054,7 +2059,8 @@ private: out.print("Dwarf \"%s\": state %s %d\n", dwarf->dwarf->name.first_name.c_str(), state_names[dwarf->state], dwarf->clear_all); // determine if dwarf has medical needs - if (dwarf->dwarf->health) + // babies cannot currently receive health care even if they need it + if (dwarf->dwarf->profession != profession::BABY && dwarf->dwarf->health) { if (dwarf->dwarf->health->flags.bits.needs_recovery) cnt_recover_wounded++; @@ -2158,13 +2164,10 @@ private: if (labor == df::unit_labor::OPERATE_PUMP) score += 50000; else - score += 1000; + score += 25000; if (default_labor_infos[labor].tool != TOOL_NONE && d->has_tool[default_labor_infos[labor].tool]) - score += 30000; - if (default_labor_infos[labor].tool != TOOL_NONE && - !d->has_tool[default_labor_infos[labor].tool]) - score -= 30000; + score += 10000000; if (d->has_children && labor_outside[labor]) score -= 15000; if (d->armed && labor_outside[labor]) @@ -2359,8 +2362,6 @@ public: } - labor_needed[df::unit_labor::CLEAN] = 1; - if (print_debug) { for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) @@ -2370,7 +2371,9 @@ public: } } + std::map base_priority; priority_queue> pq; + priority_queue> pq2; for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) { @@ -2381,15 +2384,16 @@ public: if (labor_infos[l].maximum_dwarfs() > 0 && i->second > labor_infos[l].maximum_dwarfs()) i->second = labor_infos[l].maximum_dwarfs(); - if (i->second > 0) - { - int priority = labor_infos[l].priority(); - if (l < df::unit_labor::HAUL_STONE || l > df::unit_labor::HAUL_ANIMALS) - priority += labor_infos[l].time_since_last_assigned()/12; + int priority = labor_infos[l].priority(); + + priority += labor_infos[l].time_since_last_assigned()/12; + priority -= labor_infos[l].busy_dwarfs; + + base_priority[l] = priority; - for (int n = 0; n < labor_infos[l].busy_dwarfs; n++) - priority /= 2; + if (i->second > 0) + { pq.push(make_pair(priority, l)); } } @@ -2416,9 +2420,22 @@ public: if (--labor_needed[labor] > 0) { - priority /= 2; - pq.push(make_pair(priority, labor)); + priority-=10; + pq2.push(make_pair(priority, labor)); } + + if (pq.empty()) + while(!pq2.empty()) + { + pq.push(pq2.top()); + pq2.pop(); + } + } + + while (!pq2.empty()) + { + pq.push(pq2.top()); + pq2.pop(); } int canary = (1 << df::unit_labor::HAUL_STONE) | @@ -2473,7 +2490,7 @@ public: if (l == best_labor && ( t == TOOL_NONE || tool_in_use[t] < tool_count[t]) ) { set_labor(*bestdwarf, l, true); - if (t != TOOL_NONE && (*bestdwarf)->has_tool[t]) + if (t != TOOL_NONE && !((*bestdwarf)->has_tool[t])) { df::job_type j; j = df::job_type::NONE; @@ -2524,8 +2541,7 @@ public: continue; int score = score_labor (*d, l); - if (l < df::unit_labor::HAUL_STONE || l > df::unit_labor::HAUL_ANIMALS) - score += labor_infos[l].time_since_last_assigned()/12; + if (l == df::unit_labor::HAUL_FOOD && priority_food > 0) score += 1000000; @@ -2536,7 +2552,9 @@ public: { set_labor(*d, l, true); } - if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000 && default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) + if ((*d)->using_labor != df::unit_labor::NONE && + (score > current_score + 5000 || base_priority[(*d)->using_labor] < base_priority[l]) && + default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) set_labor(*d, (*d)->using_labor, false); } } @@ -2577,18 +2595,23 @@ public: /* Assign any leftover dwarfs to "standard" labors */ + if (print_debug) + out.print ("After assignment, %d dwarfs left over\n", available_dwarfs.size()); + for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); d++) { FOR_ENUM_ITEMS (unit_labor, l) { - if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && - canary & (1 << l)) - set_labor(*d, l, true); - else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION || l == df::unit_labor::PULL_LEVER) - set_labor(*d, l, true); - else - set_labor(*d, l, false); - } + if (l == df::unit_labor::NONE) + continue; + + set_labor(*d, l, + (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS) || + l == df::unit_labor::CLEAN || + l == df::unit_labor::REMOVE_CONSTRUCTION || + l == df::unit_labor::PULL_LEVER || + l == df::unit_labor::HAUL_TRADE); + } } /* check for dwarfs assigned no labors and assign them the bucket list if there are */ @@ -2646,7 +2669,8 @@ public: bool has_tool = (*d)->has_tool[t]; bool needs_tool = (*d)->dwarf->status.labors[l]; - if (has_tool != needs_tool) + if ((needs_tool && !has_tool) || + (has_tool && !needs_tool && tool_in_use[t] >= tool_count[t])) { df::job_type j = df::job_type::NONE; @@ -2673,6 +2697,10 @@ public: *df::global::process_jobs = true; } + if (print_debug) { + *df::global::pause_state = true; + } + print_debug = 0; } @@ -2707,8 +2735,12 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) return CR_OK; } - if (++step_count < 60) +// if (++step_count < 60) +// return CR_OK; + + if (*df::global::process_jobs) return CR_OK; + step_count = 0; debug_stream = &out; From 338f6029a742def578beb6cc9302cb48e2a33428 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 26 Nov 2016 17:37:26 -0600 Subject: [PATCH 250/413] Use attributes in calculating assignment weight --- plugins/devel/labormanager.cpp | 156 ++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 2 deletions(-) diff --git a/plugins/devel/labormanager.cpp b/plugins/devel/labormanager.cpp index ae1f2c17c..7ba1578b2 100644 --- a/plugins/devel/labormanager.cpp +++ b/plugins/devel/labormanager.cpp @@ -1502,9 +1502,152 @@ static void generate_labor_to_skill_map() labor_to_skill[labor] = skill; } } - } +struct skill_attr_weight { + int phys_attr_weights [6]; + int mental_attr_weights [13]; +}; + +static struct skill_attr_weight skill_attr_weights[ENUM_LAST_ITEM(job_skill) + 1] = +{ + // S A T E R D AA F W C I P M LA SS M KS E SA + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MINING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WOODCUTTING */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CARPENTRY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DETAILSTONE */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MASONRY */, + { { 0, 1, 1, 1, 0, 0 }, { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 } } /* ANIMALTRAIN */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 } } /* ANIMALCARE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISSECT_FISH */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISSECT_VERMIN */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROCESSFISH */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BUTCHER */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* TRAPPING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* TANNER */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WEAVING */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BREWING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ALCHEMY */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CLOTHESMAKING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILLING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROCESSPLANTS */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CHEESEMAKING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILK */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* COOK */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLANT */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* HERBALISM */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } } /* FISH */, + { { 1, 0, 1, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SMELT */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* EXTRACT_STRAND */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_WEAPON */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_ARMOR */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_FURNITURE */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CUTGEM */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ENCRUSTGEM */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WOODCRAFT */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* STONECRAFT */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* METALCRAFT */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GLASSMAKER */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* LEATHERWORK */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BONECARVE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* AXE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SWORD */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DAGGER */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MACE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* HAMMER */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SPEAR */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CROSSBOW */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SHIELD */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* ARMOR */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SIEGECRAFT */, + { { 1, 0, 1, 1, 0, 0 }, { 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SIEGEOPERATE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BOWYER */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* PIKE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WHIP */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BOW */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BLOWGUN */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* THROW */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MECHANICS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MAGIC_NATURE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SNEAK */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DESIGNBUILDING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0 } } /* DRESS_WOUNDS */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 } } /* DIAGNOSE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SURGERY */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SET_BONE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SUTURE */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CRUTCH_WALK */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* WOOD_BURNING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* LYE_MAKING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SOAP_MAKING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* POTASH_MAKING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DYER */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* OPERATE_PUMP */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SWIMMING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* PERSUASION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* NEGOTIATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1 } } /* JUDGING_INTENT */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 } } /* APPRAISAL */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 } } /* ORGANIZATION */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* RECORD_KEEPING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 } } /* LYING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 } } /* INTIMIDATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* CONVERSATION */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 } } /* COMEDY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* FLATTERY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0 } } /* CONSOLE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* PACIFY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* TRACKING */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* KNOWLEDGE_ACQUISITION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } } /* CONCENTRATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISCIPLINE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SITUATIONAL_AWARENESS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* WRITING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROSE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* POETRY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* READING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SPEAKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* COORDINATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BALANCE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* LEADERSHIP */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* TEACHING */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MELEE_COMBAT */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* RANGED_COMBAT */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WRESTLING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BITE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GRASP_STRIKE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* STANCE_STRIKE */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DODGING */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MISC_WEAPON */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* KNAPPING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILITARY_TACTICS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SHEARING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SPINNING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* POTTERY */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GLAZING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PRESSING */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BEEKEEPING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WAX_WORKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CLIMBING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* GELD */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DANCE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MAKE_MUSIC */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SING_MUSIC */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_KEYBOARD_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_STRINGED_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_WIND_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_PERCUSSION_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CRITICAL_THINKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* LOGIC */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MATHEMATICS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ASTRONOMY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CHEMISTRY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* GEOGRAPHY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* OPTICS_ENGINEER */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FLUID_ENGINEER */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PAPERMAKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BOOKBINDING */ +}; static void enable_plugin(color_ostream &out) { @@ -2145,6 +2288,7 @@ private: { int skill_level = 0; int xp = 0; + int attr_weight = 0; if (labor != df::unit_labor::NONE) { @@ -2153,10 +2297,16 @@ private: { skill_level = Units::getEffectiveSkill(d->dwarf, skill); xp = Units::getExperience(d->dwarf, skill, false); + + for (int pa = 0; pa < 6; pa++) + attr_weight += (skill_attr_weights[skill].phys_attr_weights[pa]) * (d->dwarf->body.physical_attrs[pa].value - 1000); + + for (int ma = 0; ma < 13; ma++) + attr_weight += (skill_attr_weights[skill].mental_attr_weights[ma]) * (d->dwarf->status.current_soul->mental_attrs[ma].value - 1000); } } - int score = skill_level * 1000 - (d->high_skill - skill_level) * 2000 + (xp / (skill_level + 5) * 10); + int score = skill_level * 1000 - (d->high_skill - skill_level) * 2000 + (xp / (skill_level + 5) * 10) + attr_weight; if (labor != df::unit_labor::NONE) { @@ -2174,6 +2324,8 @@ private: score += 5000; } + score -= Units::computeMovementSpeed(d->dwarf); + return score; } From 491d53b76f8bc0c9667235b2483e97f9248e4b1a Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 26 Nov 2016 18:08:48 -0600 Subject: [PATCH 251/413] fix white space to make travis happy --- plugins/labormanager.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index ed3390868..e7ab6ce31 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1826,7 +1826,7 @@ private: // (except for farms and trade depots) if (b->getType() != df::building_type::FarmPlot && - b->getType() != df::building_type::TradeDepot) + b->getType() != df::building_type::TradeDepot) { int fjid = -1; for (int jn = 0; jn < b->jobs.size(); jn++) @@ -2301,10 +2301,10 @@ private: skill_level = Units::getEffectiveSkill(d->dwarf, skill); xp = Units::getExperience(d->dwarf, skill, false); - for (int pa = 0; pa < 6; pa++) + for (int pa = 0; pa < 6; pa++) attr_weight += (skill_attr_weights[skill].phys_attr_weights[pa]) * (d->dwarf->body.physical_attrs[pa].value - 1000); - for (int ma = 0; ma < 13; ma++) + for (int ma = 0; ma < 13; ma++) attr_weight += (skill_attr_weights[skill].mental_attr_weights[ma]) * (d->dwarf->status.current_soul->mental_attrs[ma].value - 1000); } } @@ -2541,10 +2541,10 @@ public: i->second = labor_infos[l].maximum_dwarfs(); int priority = labor_infos[l].priority(); - + priority += labor_infos[l].time_since_last_assigned()/12; priority -= labor_infos[l].busy_dwarfs; - + base_priority[l] = priority; if (i->second > 0) @@ -2579,8 +2579,8 @@ public: pq2.push(make_pair(priority, labor)); } - if (pq.empty()) - while(!pq2.empty()) + if (pq.empty()) + while(!pq2.empty()) { pq.push(pq2.top()); pq2.pop(); @@ -2707,8 +2707,8 @@ public: { set_labor(*d, l, true); } - if ((*d)->using_labor != df::unit_labor::NONE && - (score > current_score + 5000 || base_priority[(*d)->using_labor] < base_priority[l]) && + if ((*d)->using_labor != df::unit_labor::NONE && + (score > current_score + 5000 || base_priority[(*d)->using_labor] < base_priority[l]) && default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) set_labor(*d, (*d)->using_labor, false); } @@ -2760,10 +2760,10 @@ public: if (l == df::unit_labor::NONE) continue; - set_labor(*d, l, - (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS) || - l == df::unit_labor::CLEAN || - l == df::unit_labor::REMOVE_CONSTRUCTION || + set_labor(*d, l, + (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS) || + l == df::unit_labor::CLEAN || + l == df::unit_labor::REMOVE_CONSTRUCTION || l == df::unit_labor::PULL_LEVER || l == df::unit_labor::HAUL_TRADE); } @@ -2893,7 +2893,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) // if (++step_count < 60) // return CR_OK; - if (*df::global::process_jobs) + if (*df::global::process_jobs) return CR_OK; step_count = 0; From cbcb148182b0491283d0840d36b8dcadc941f8d0 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 8 Nov 2016 12:01:24 -0600 Subject: [PATCH 252/413] Better job assignment algorithm for labormanager. --- plugins/labormanager.cpp | 266 ++++++++++++++++++++++----------------- 1 file changed, 149 insertions(+), 117 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 5a2774cd2..298568a41 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -414,23 +414,23 @@ struct labor_default static std::vector labor_infos; static const struct labor_default default_labor_infos[] = { - /* MINEa */ {200, 0, TOOL_PICK}, + /* MINE */ {100, 0, TOOL_PICK}, /* HAUL_STONE */ {100, 0, TOOL_NONE}, /* HAUL_WOOD */ {100, 0, TOOL_NONE}, - /* HAUL_BODY */ {200, 0, TOOL_NONE}, - /* HAUL_FOOD */ {300, 0, TOOL_NONE}, - /* HAUL_REFUSE */ {100, 0, TOOL_NONE}, + /* HAUL_BODY */ {1000, 0, TOOL_NONE}, + /* HAUL_FOOD */ {500, 0, TOOL_NONE}, + /* HAUL_REFUSE */ {200, 0, TOOL_NONE}, /* HAUL_ITEM */ {100, 0, TOOL_NONE}, /* HAUL_FURNITURE */ {100, 0, TOOL_NONE}, /* HAUL_ANIMAL */ {100, 0, TOOL_NONE}, - /* CLEAN */ {200, 0, TOOL_NONE}, - /* CUTWOOD */ {200, 0, TOOL_AXE}, - /* CARPENTER */ {200, 0, TOOL_NONE}, - /* DETAIL */ {200, 0, TOOL_NONE}, - /* MASON */ {200, 0, TOOL_NONE}, - /* ARCHITECT */ {400, 0, TOOL_NONE}, - /* ANIMALTRAIN */ {200, 0, TOOL_NONE}, - /* ANIMALCARE */ {200, 0, TOOL_NONE}, + /* CLEAN */ {100, 0, TOOL_NONE}, + /* CUTWOOD */ {100, 0, TOOL_AXE}, + /* CARPENTER */ {100, 0, TOOL_NONE}, + /* DETAIL */ {100, 0, TOOL_NONE}, + /* MASON */ {100, 0, TOOL_NONE}, + /* ARCHITECT */ {100, 0, TOOL_NONE}, + /* ANIMALTRAIN */ {100, 0, TOOL_NONE}, + /* ANIMALCARE */ {100, 0, TOOL_NONE}, /* DIAGNOSE */ {1000, 0, TOOL_NONE}, /* SURGERY */ {1000, 0, TOOL_NONE}, /* BONE_SETTING */ {1000, 0, TOOL_NONE}, @@ -438,65 +438,65 @@ static const struct labor_default default_labor_infos[] = { /* DRESSING_WOUNDS */ {1000, 0, TOOL_NONE}, /* FEED_WATER_CIVILIANS */ {1000, 0, TOOL_NONE}, /* RECOVER_WOUNDED */ {200, 0, TOOL_NONE}, - /* BUTCHER */ {200, 0, TOOL_NONE}, - /* TRAPPER */ {200, 0, TOOL_NONE}, - /* DISSECT_VERMIN */ {200, 0, TOOL_NONE}, - /* LEATHER */ {200, 0, TOOL_NONE}, - /* TANNER */ {200, 0, TOOL_NONE}, - /* BREWER */ {200, 0, TOOL_NONE}, - /* ALCHEMIST */ {200, 0, TOOL_NONE}, - /* SOAP_MAKER */ {200, 0, TOOL_NONE}, - /* WEAVER */ {200, 0, TOOL_NONE}, - /* CLOTHESMAKER */ {200, 0, TOOL_NONE}, - /* MILLER */ {200, 0, TOOL_NONE}, - /* PROCESS_PLANT */ {200, 0, TOOL_NONE}, - /* MAKE_CHEESE */ {200, 0, TOOL_NONE}, - /* MILK */ {200, 0, TOOL_NONE}, - /* COOK */ {200, 0, TOOL_NONE}, - /* PLANT */ {200, 0, TOOL_NONE}, - /* HERBALIST */ {200, 0, TOOL_NONE}, + /* BUTCHER */ {500, 0, TOOL_NONE}, + /* TRAPPER */ {100, 0, TOOL_NONE}, + /* DISSECT_VERMIN */ {100, 0, TOOL_NONE}, + /* LEATHER */ {100, 0, TOOL_NONE}, + /* TANNER */ {100, 0, TOOL_NONE}, + /* BREWER */ {100, 0, TOOL_NONE}, + /* ALCHEMIST */ {100, 0, TOOL_NONE}, + /* SOAP_MAKER */ {100, 0, TOOL_NONE}, + /* WEAVER */ {100, 0, TOOL_NONE}, + /* CLOTHESMAKER */ {100, 0, TOOL_NONE}, + /* MILLER */ {100, 0, TOOL_NONE}, + /* PROCESS_PLANT */ {100, 0, TOOL_NONE}, + /* MAKE_CHEESE */ {100, 0, TOOL_NONE}, + /* MILK */ {100, 0, TOOL_NONE}, + /* COOK */ {100, 0, TOOL_NONE}, + /* PLANT */ {100, 0, TOOL_NONE}, + /* HERBALIST */ {100, 0, TOOL_NONE}, /* FISH */ {100, 0, TOOL_NONE}, - /* CLEAN_FISH */ {200, 0, TOOL_NONE}, - /* DISSECT_FISH */ {200, 0, TOOL_NONE}, + /* CLEAN_FISH */ {100, 0, TOOL_NONE}, + /* DISSECT_FISH */ {100, 0, TOOL_NONE}, /* HUNT */ {100, 0, TOOL_CROSSBOW}, - /* SMELT */ {200, 0, TOOL_NONE}, - /* FORGE_WEAPON */ {200, 0, TOOL_NONE}, - /* FORGE_ARMOR */ {200, 0, TOOL_NONE}, - /* FORGE_FURNITURE */ {200, 0, TOOL_NONE}, - /* METAL_CRAFT */ {200, 0, TOOL_NONE}, - /* CUT_GEM */ {200, 0, TOOL_NONE}, - /* ENCRUST_GEM */ {200, 0, TOOL_NONE}, - /* WOOD_CRAFT */ {200, 0, TOOL_NONE}, - /* STONE_CRAFT */ {200, 0, TOOL_NONE}, - /* BONE_CARVE */ {200, 0, TOOL_NONE}, - /* GLASSMAKER */ {200, 0, TOOL_NONE}, - /* EXTRACT_STRAND */ {200, 0, TOOL_NONE}, - /* SIEGECRAFT */ {200, 0, TOOL_NONE}, - /* SIEGEOPERATE */ {200, 0, TOOL_NONE}, - /* BOWYER */ {200, 0, TOOL_NONE}, - /* MECHANIC */ {200, 0, TOOL_NONE}, - /* POTASH_MAKING */ {200, 0, TOOL_NONE}, - /* LYE_MAKING */ {200, 0, TOOL_NONE}, - /* DYER */ {200, 0, TOOL_NONE}, - /* BURN_WOOD */ {200, 0, TOOL_NONE}, - /* OPERATE_PUMP */ {200, 0, TOOL_NONE}, - /* SHEARER */ {200, 0, TOOL_NONE}, - /* SPINNER */ {200, 0, TOOL_NONE}, - /* POTTERY */ {200, 0, TOOL_NONE}, - /* GLAZING */ {200, 0, TOOL_NONE}, - /* PRESSING */ {200, 0, TOOL_NONE}, - /* BEEKEEPING */ {200, 0, TOOL_NONE}, - /* WAX_WORKING */ {200, 0, TOOL_NONE}, - /* PUSH_HAUL_VEHICLES */ {200, 0, TOOL_NONE}, - /* HAUL_TRADE */ {200, 0, TOOL_NONE}, - /* PULL_LEVER */ {200, 0, TOOL_NONE}, - /* REMOVE_CONSTRUCTION */ {200, 0, TOOL_NONE}, - /* HAUL_WATER */ {200, 0, TOOL_NONE}, - /* GELD */ {200, 0, TOOL_NONE}, - /* BUILD_ROAD */ {200, 0, TOOL_NONE}, - /* BUILD_CONSTRUCTION */ {200, 0, TOOL_NONE}, - /* PAPERMAKING */ {200, 0, TOOL_NONE}, - /* BOOKBINDING */ {200, 0, TOOL_NONE} + /* SMELT */ {100, 0, TOOL_NONE}, + /* FORGE_WEAPON */ {100, 0, TOOL_NONE}, + /* FORGE_ARMOR */ {100, 0, TOOL_NONE}, + /* FORGE_FURNITURE */ {100, 0, TOOL_NONE}, + /* METAL_CRAFT */ {100, 0, TOOL_NONE}, + /* CUT_GEM */ {100, 0, TOOL_NONE}, + /* ENCRUST_GEM */ {100, 0, TOOL_NONE}, + /* WOOD_CRAFT */ {100, 0, TOOL_NONE}, + /* STONE_CRAFT */ {100, 0, TOOL_NONE}, + /* BONE_CARVE */ {100, 0, TOOL_NONE}, + /* GLASSMAKER */ {100, 0, TOOL_NONE}, + /* EXTRACT_STRAND */ {100, 0, TOOL_NONE}, + /* SIEGECRAFT */ {100, 0, TOOL_NONE}, + /* SIEGEOPERATE */ {100, 0, TOOL_NONE}, + /* BOWYER */ {100, 0, TOOL_NONE}, + /* MECHANIC */ {100, 0, TOOL_NONE}, + /* POTASH_MAKING */ {100, 0, TOOL_NONE}, + /* LYE_MAKING */ {100, 0, TOOL_NONE}, + /* DYER */ {100, 0, TOOL_NONE}, + /* BURN_WOOD */ {100, 0, TOOL_NONE}, + /* OPERATE_PUMP */ {100, 0, TOOL_NONE}, + /* SHEARER */ {100, 0, TOOL_NONE}, + /* SPINNER */ {100, 0, TOOL_NONE}, + /* POTTERY */ {100, 0, TOOL_NONE}, + /* GLAZING */ {100, 0, TOOL_NONE}, + /* PRESSING */ {100, 0, TOOL_NONE}, + /* BEEKEEPING */ {100, 0, TOOL_NONE}, + /* WAX_WORKING */ {100, 0, TOOL_NONE}, + /* PUSH_HAUL_VEHICLES */ {100, 0, TOOL_NONE}, + /* HAUL_TRADE */ {1000, 0, TOOL_NONE}, + /* PULL_LEVER */ {1000, 0, TOOL_NONE}, + /* REMOVE_CONSTRUCTION */ {100, 0, TOOL_NONE}, + /* HAUL_WATER */ {100, 0, TOOL_NONE}, + /* GELD */ {100, 0, TOOL_NONE}, + /* BUILD_ROAD */ {100, 0, TOOL_NONE}, + /* BUILD_CONSTRUCTION */ {100, 0, TOOL_NONE}, + /* PAPERMAKING */ {100, 0, TOOL_NONE}, + /* BOOKBINDING */ {100, 0, TOOL_NONE} }; void debug (char* fmt, ...); @@ -852,12 +852,13 @@ private: return df::unit_labor::TRAPPER; case df::building_type::Civzone: case df::building_type::Nest: - case df::building_type::RoadDirt: case df::building_type::Stockpile: case df::building_type::Weapon: return df::unit_labor::NONE; case df::building_type::SiegeEngine: return df::unit_labor::SIEGECRAFT; + case df::building_type::RoadDirt: + return df::unit_labor::BUILD_ROAD; } debug ("LABORMANAGER: Cannot deduce labor for construct building job of type %s\n", @@ -1167,13 +1168,13 @@ public: job_to_labor_table[df::job_type::CheckChest] = jlf_no_labor; job_to_labor_table[df::job_type::StoreOwnedItem] = jlf_no_labor; job_to_labor_table[df::job_type::PlaceItemInTomb] = jlf_const(df::unit_labor::HAUL_BODY); - job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list - job_to_labor_table[df::job_type::StoreItemInBag] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list + job_to_labor_table[df::job_type::StoreItemInStockpile] = jlf_hauling; + job_to_labor_table[df::job_type::StoreItemInBag] = jlf_hauling; job_to_labor_table[df::job_type::StoreItemInHospital] = jlf_hauling; job_to_labor_table[df::job_type::StoreWeapon] = jlf_hauling; job_to_labor_table[df::job_type::StoreArmor] = jlf_hauling; - job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list - job_to_labor_table[df::job_type::StoreItemInBin] = jlf_no_labor; // Can arise from many different labors, but will never appear in a pending job list + job_to_labor_table[df::job_type::StoreItemInBarrel] = jlf_hauling; + job_to_labor_table[df::job_type::StoreItemInBin] = jlf_hauling; job_to_labor_table[df::job_type::SeekArtifact] = jlf_no_labor; job_to_labor_table[df::job_type::SeekInfant] = jlf_no_labor; job_to_labor_table[df::job_type::AttendParty] = jlf_no_labor; @@ -1676,20 +1677,24 @@ private: if (bld != -1) { df::building* b = binsearch_in_vector(world->buildings.all, bld); - int fjid = -1; - for (int jn = 0; jn < b->jobs.size(); jn++) - { - if (b->jobs[jn]->flags.bits.suspend) - continue; - fjid = b->jobs[jn]->id; - break; - } + // check if this job is the first nonsuspended job on this building; if not, ignore it // (except for farms and trade depots) - if (fjid != j->id && - b->getType() != df::building_type::FarmPlot && - b->getType() != df::building_type::TradeDepot) - return; + + if (b->getType() != df::building_type::FarmPlot && + b->getType() != df::building_type::TradeDepot) + { + int fjid = -1; + for (int jn = 0; jn < b->jobs.size(); jn++) + { + if (b->jobs[jn]->flags.bits.suspend) + continue; + fjid = b->jobs[jn]->id; + break; + } + if (fjid != j->id) + return; + } } df::unit_labor labor = labor_mapper->find_job_labor (j); @@ -2056,7 +2061,8 @@ private: out.print("Dwarf \"%s\": state %s %d\n", dwarf->dwarf->name.first_name.c_str(), state_names[dwarf->state], dwarf->clear_all); // determine if dwarf has medical needs - if (dwarf->dwarf->health) + // babies cannot currently receive health care even if they need it + if (dwarf->dwarf->profession != profession::BABY && dwarf->dwarf->health) { if (dwarf->dwarf->health->flags.bits.needs_recovery) cnt_recover_wounded++; @@ -2160,13 +2166,10 @@ private: if (labor == df::unit_labor::OPERATE_PUMP) score += 50000; else - score += 1000; + score += 25000; if (default_labor_infos[labor].tool != TOOL_NONE && d->has_tool[default_labor_infos[labor].tool]) - score += 30000; - if (default_labor_infos[labor].tool != TOOL_NONE && - !d->has_tool[default_labor_infos[labor].tool]) - score -= 30000; + score += 10000000; if (d->has_children && labor_outside[labor]) score -= 15000; if (d->armed && labor_outside[labor]) @@ -2361,8 +2364,6 @@ public: } - labor_needed[df::unit_labor::CLEAN] = 1; - if (print_debug) { for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) @@ -2372,7 +2373,9 @@ public: } } + std::map base_priority; priority_queue> pq; + priority_queue> pq2; for (auto i = labor_needed.begin(); i != labor_needed.end(); i++) { @@ -2383,15 +2386,16 @@ public: if (labor_infos[l].maximum_dwarfs() > 0 && i->second > labor_infos[l].maximum_dwarfs()) i->second = labor_infos[l].maximum_dwarfs(); - if (i->second > 0) - { - int priority = labor_infos[l].priority(); - if (l < df::unit_labor::HAUL_STONE || l > df::unit_labor::HAUL_ANIMALS) - priority += labor_infos[l].time_since_last_assigned()/12; + int priority = labor_infos[l].priority(); + + priority += labor_infos[l].time_since_last_assigned()/12; + priority -= labor_infos[l].busy_dwarfs; + + base_priority[l] = priority; - for (int n = 0; n < labor_infos[l].busy_dwarfs; n++) - priority /= 2; + if (i->second > 0) + { pq.push(make_pair(priority, l)); } } @@ -2418,9 +2422,22 @@ public: if (--labor_needed[labor] > 0) { - priority /= 2; - pq.push(make_pair(priority, labor)); + priority-=10; + pq2.push(make_pair(priority, labor)); } + + if (pq.empty()) + while(!pq2.empty()) + { + pq.push(pq2.top()); + pq2.pop(); + } + } + + while (!pq2.empty()) + { + pq.push(pq2.top()); + pq2.pop(); } int canary = (1 << df::unit_labor::HAUL_STONE) | @@ -2475,7 +2492,7 @@ public: if (l == best_labor && ( t == TOOL_NONE || tool_in_use[t] < tool_count[t]) ) { set_labor(*bestdwarf, l, true); - if (t != TOOL_NONE && (*bestdwarf)->has_tool[t]) + if (t != TOOL_NONE && !((*bestdwarf)->has_tool[t])) { df::job_type j; j = df::job_type::NONE; @@ -2526,8 +2543,7 @@ public: continue; int score = score_labor (*d, l); - if (l < df::unit_labor::HAUL_STONE || l > df::unit_labor::HAUL_ANIMALS) - score += labor_infos[l].time_since_last_assigned()/12; + if (l == df::unit_labor::HAUL_FOOD && priority_food > 0) score += 1000000; @@ -2538,7 +2554,9 @@ public: { set_labor(*d, l, true); } - if ((*d)->using_labor != df::unit_labor::NONE && score > current_score + 5000 && default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) + if ((*d)->using_labor != df::unit_labor::NONE && + (score > current_score + 5000 || base_priority[(*d)->using_labor] < base_priority[l]) && + default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) set_labor(*d, (*d)->using_labor, false); } } @@ -2579,18 +2597,23 @@ public: /* Assign any leftover dwarfs to "standard" labors */ + if (print_debug) + out.print ("After assignment, %d dwarfs left over\n", available_dwarfs.size()); + for (auto d = available_dwarfs.begin(); d != available_dwarfs.end(); d++) { FOR_ENUM_ITEMS (unit_labor, l) { - if (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS && - canary & (1 << l)) - set_labor(*d, l, true); - else if (l == df::unit_labor::CLEAN || l == df::unit_labor::REMOVE_CONSTRUCTION || l == df::unit_labor::PULL_LEVER) - set_labor(*d, l, true); - else - set_labor(*d, l, false); - } + if (l == df::unit_labor::NONE) + continue; + + set_labor(*d, l, + (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS) || + l == df::unit_labor::CLEAN || + l == df::unit_labor::REMOVE_CONSTRUCTION || + l == df::unit_labor::PULL_LEVER || + l == df::unit_labor::HAUL_TRADE); + } } /* check for dwarfs assigned no labors and assign them the bucket list if there are */ @@ -2648,7 +2671,8 @@ public: bool has_tool = (*d)->has_tool[t]; bool needs_tool = (*d)->dwarf->status.labors[l]; - if (has_tool != needs_tool) + if ((needs_tool && !has_tool) || + (has_tool && !needs_tool && tool_in_use[t] >= tool_count[t])) { df::job_type j = df::job_type::NONE; @@ -2675,6 +2699,10 @@ public: *df::global::process_jobs = true; } + if (print_debug) { + *df::global::pause_state = true; + } + print_debug = 0; } @@ -2709,8 +2737,12 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) return CR_OK; } - if (++step_count < 60) +// if (++step_count < 60) +// return CR_OK; + + if (*df::global::process_jobs) return CR_OK; + step_count = 0; debug_stream = &out; From 61baaa0c374d252bc72645af01dd527c91c8fd7b Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 25 Oct 2016 18:02:07 -0500 Subject: [PATCH 253/413] Docs for labormanager --- docs/Plugins.rst | 104 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index ba502c38e..adf4d1206 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -810,6 +810,110 @@ Examples: ``autolabor CUTWOOD disable`` Turn off autolabor for wood cutting. +.. _labormanager: + +labormanager +============ +Automatically manage dwarf labors to efficiently complete jobs. +Labormanager is derived from autolabor (above) but uses a completely +different approach to assigning jobs to dwarves. While autolabor tries +to keep as many dwarves busy as possible, labormanager instead strives +to get jobs done as quickly as possible. + +Labormanager frequently scans the current job list, current list of +dwarfs, and the map to determine how many dwarves need to be assigned to +what labors in order to meet all current labor needs without starving +any particular type of job. + +.. warning:: + + *As with autolabor, labormanager will override any manual changes you + make to labors while it is enabled, including through other tools such + as Dwarf Therapist* + +Simple usage: + +:enable labormanager: Enables the plugin with default settings. +(Persistent per fortress) :disable labormanager: Disables the plugin. + +Anything beyond this is optional - autolabor works fairly well on the +default settings. + +The default priorities for each labor vary (some labors are higher +priority by default than others). The way the plugin works is that, once +it determines how many of each labor is needed, it then sorts them by +adjusted priority. (Labors other than hauling have a bias added to them +based on how long it's been since they were last used, to prevent job +starvation.) The labor with the highest priority is selected, the "best +fit" dwarf for that labor is assigned to that labor, and then its +priority is *halved*. This process is repeated until either dwarfs or +labors run out. + +Because there is no easy way to detect how many haulers are actually +needed at any moment, the plugin always ensures that at least one dwarf +is assigned to each of the hauling labors, even if no hauling jobs are +detected. At least one dwarf is always assigned to construction removing +and cleaning because these jobs also cannot be easily detected. Lever +pulling is always assigned to everyone. Any dwarfs for which there are +no jobs will be assigned hauling, lever pulling, and cleaning labors. If +you use animal trainers, note that labormanager + +Labormanager also sometimes assigns extra labors to currently busy +dwarfs so that when they finish their current job, they will go off and +do something useful instead of standing around waiting for a job. + +There is special handling to ensure that at least one dwarf is assigned +to haul food whenever food is detected left in a place where it will rot +if not stored. This will cause a dwarf to go idle if you have no +storepiles to haul food to. + +Dwarfs who are unable to work (child, in the military, wounded, +handless, asleep, in a meeting) are entirely excluded from labor +assignment. Any dwarf explicitly assigned to a burrow will also be +completely ignored by labormanager. + +The fitness algorithm for assigning jobs to dwarfs generally attempts to +favor dwarfs who are more skilled over those who are less skilled. It +also tries to avoid assigning female dwarfs with children to jobs that +are "outside", favors assigning "outside" jobs to dwarfs who are +carrying a tool that could be used as a weapon, and tries to minimize +how often dwarfs have to reequip. + +Labormanager automatically determines medical needs and reserves health +care providers as needed. Note that this may cause idling if you have +injured dwarfs but no or inadequate hospital facilities. + +Hunting is never assigned without a butchery, and fishing is never +assigned without a fishery, and neither of these labors is assigned +unless specifically enabled. + +The method by which labormanager determines what labor is needed for a +particular job is complicated and, in places, incomplete. In some +situations, labormanager will detect that it cannot determine what labor +is required. It will, by default, pause and print an error message on +the dfhack console, followed by the message "LABORMANAGER: Game paused +so you can investigate the above message.". If this happens, please open +an issue on github, reporting the lines that immediately preceded this +message. You can tell labormanager to ignore this error and carry on by +typing "autolabor pause-on-error no", but be warned that some job may go +undone in this situation. + +Advanced usage: + +:autolabor enable: Turn plugin on. +:autolabor disable: Turn plugin off. +:autolabor priority : Set the priority value (see above) for labor to . +:autolabor reset : Reset the priority value of labor to its default. +:autolabor reset-all: Reset all priority values to their defaults. +:autolabor allow-fishing: Allow dwarfs to fish. *Warning* This tends to result in most of the fort going fishing. +:autolabor forbid-fishing: Forbid dwarfs from fishing. Default behavior. +:autolabor allow-hunting: Allow dwarfs to hunt. *Warning* This tends to result in as many dwarfs going hunting as you have crossbows. +:autolabor forbid-hunting: Forbid dwarfs from hunting. Default behavior. +:autolabor list: Show current priorities and current allocation stats. +:autolabor pause-on-error yes: Make labormanager pause if the labor inference engine fails. See above. +:autolabor pause-on-error no: Allow labormanager to continue past a labor inference engine failure. + + .. _autohauler: autohauler From a28c4db69ae8441d9e6d38a080dea8673e0a7a4a Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 25 Oct 2016 18:10:29 -0500 Subject: [PATCH 254/413] Finish clipped sentence. (erk.) --- docs/Plugins.rst | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index adf4d1206..c82d68389 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -856,7 +856,10 @@ detected. At least one dwarf is always assigned to construction removing and cleaning because these jobs also cannot be easily detected. Lever pulling is always assigned to everyone. Any dwarfs for which there are no jobs will be assigned hauling, lever pulling, and cleaning labors. If -you use animal trainers, note that labormanager +you use animal trainers, note that labormanager will misbehave if you +assign specific trainers to specific animals; results are only guaranteed +if you use "any trainer", and animal trainers will probably be +overallocated in any case. Labormanager also sometimes assigns extra labors to currently busy dwarfs so that when they finish their current job, they will go off and @@ -900,18 +903,18 @@ undone in this situation. Advanced usage: -:autolabor enable: Turn plugin on. -:autolabor disable: Turn plugin off. -:autolabor priority : Set the priority value (see above) for labor to . -:autolabor reset : Reset the priority value of labor to its default. -:autolabor reset-all: Reset all priority values to their defaults. -:autolabor allow-fishing: Allow dwarfs to fish. *Warning* This tends to result in most of the fort going fishing. -:autolabor forbid-fishing: Forbid dwarfs from fishing. Default behavior. -:autolabor allow-hunting: Allow dwarfs to hunt. *Warning* This tends to result in as many dwarfs going hunting as you have crossbows. -:autolabor forbid-hunting: Forbid dwarfs from hunting. Default behavior. -:autolabor list: Show current priorities and current allocation stats. -:autolabor pause-on-error yes: Make labormanager pause if the labor inference engine fails. See above. -:autolabor pause-on-error no: Allow labormanager to continue past a labor inference engine failure. +:labormanager enable: Turn plugin on. +:labormanager disable: Turn plugin off. +:labormanager priority : Set the priority value (see above) for labor to . +:labormanager reset : Reset the priority value of labor to its default. +:labormanager reset-all: Reset all priority values to their defaults. +:labormanager allow-fishing: Allow dwarfs to fish. *Warning* This tends to result in most of the fort going fishing. +:labormanager forbid-fishing: Forbid dwarfs from fishing. Default behavior. +:labormanager allow-hunting: Allow dwarfs to hunt. *Warning* This tends to result in as many dwarfs going hunting as you have crossbows. +:labormanager forbid-hunting: Forbid dwarfs from hunting. Default behavior. +:labormanager list: Show current priorities and current allocation stats. +:labormanager pause-on-error yes: Make labormanager pause if the labor inference engine fails. See above. +:labormanager pause-on-error no: Allow labormanager to continue past a labor inference engine failure. .. _autohauler: From 47426e3e002356980f632c91ade9ded5073656f3 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 26 Nov 2016 17:37:26 -0600 Subject: [PATCH 255/413] Use attributes in calculating assignment weight --- plugins/labormanager.cpp | 156 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 2 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 298568a41..eedcffe7e 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1504,9 +1504,152 @@ static void generate_labor_to_skill_map() labor_to_skill[labor] = skill; } } - } +struct skill_attr_weight { + int phys_attr_weights [6]; + int mental_attr_weights [13]; +}; + +static struct skill_attr_weight skill_attr_weights[ENUM_LAST_ITEM(job_skill) + 1] = +{ + // S A T E R D AA F W C I P M LA SS M KS E SA + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MINING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WOODCUTTING */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CARPENTRY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DETAILSTONE */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MASONRY */, + { { 0, 1, 1, 1, 0, 0 }, { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 } } /* ANIMALTRAIN */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 } } /* ANIMALCARE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISSECT_FISH */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISSECT_VERMIN */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROCESSFISH */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BUTCHER */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* TRAPPING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* TANNER */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WEAVING */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BREWING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ALCHEMY */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CLOTHESMAKING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILLING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROCESSPLANTS */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CHEESEMAKING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILK */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* COOK */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLANT */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* HERBALISM */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } } /* FISH */, + { { 1, 0, 1, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SMELT */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* EXTRACT_STRAND */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_WEAPON */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_ARMOR */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_FURNITURE */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CUTGEM */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ENCRUSTGEM */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WOODCRAFT */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* STONECRAFT */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* METALCRAFT */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GLASSMAKER */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* LEATHERWORK */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BONECARVE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* AXE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SWORD */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DAGGER */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MACE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* HAMMER */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SPEAR */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CROSSBOW */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SHIELD */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* ARMOR */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SIEGECRAFT */, + { { 1, 0, 1, 1, 0, 0 }, { 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SIEGEOPERATE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BOWYER */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* PIKE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WHIP */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BOW */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BLOWGUN */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* THROW */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MECHANICS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MAGIC_NATURE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SNEAK */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DESIGNBUILDING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0 } } /* DRESS_WOUNDS */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 } } /* DIAGNOSE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SURGERY */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SET_BONE */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SUTURE */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CRUTCH_WALK */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* WOOD_BURNING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* LYE_MAKING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SOAP_MAKING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* POTASH_MAKING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DYER */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* OPERATE_PUMP */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SWIMMING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* PERSUASION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* NEGOTIATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1 } } /* JUDGING_INTENT */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 } } /* APPRAISAL */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 } } /* ORGANIZATION */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* RECORD_KEEPING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 } } /* LYING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 } } /* INTIMIDATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* CONVERSATION */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 } } /* COMEDY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* FLATTERY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0 } } /* CONSOLE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* PACIFY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* TRACKING */, + { { 0, 1, 0, 0, 0, 0 }, { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* KNOWLEDGE_ACQUISITION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } } /* CONCENTRATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISCIPLINE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SITUATIONAL_AWARENESS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* WRITING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROSE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* POETRY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* READING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SPEAKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* COORDINATION */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BALANCE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* LEADERSHIP */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* TEACHING */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MELEE_COMBAT */, + { { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* RANGED_COMBAT */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WRESTLING */, + { { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BITE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GRASP_STRIKE */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* STANCE_STRIKE */, + { { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DODGING */, + { { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MISC_WEAPON */, + { { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* KNAPPING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILITARY_TACTICS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SHEARING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SPINNING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* POTTERY */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GLAZING */, + { { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PRESSING */, + { { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BEEKEEPING */, + { { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WAX_WORKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CLIMBING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* GELD */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DANCE */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MAKE_MUSIC */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SING_MUSIC */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_KEYBOARD_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_STRINGED_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_WIND_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLAY_PERCUSSION_INSTRUMENT */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CRITICAL_THINKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* LOGIC */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MATHEMATICS */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ASTRONOMY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CHEMISTRY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* GEOGRAPHY */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* OPTICS_ENGINEER */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FLUID_ENGINEER */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PAPERMAKING */, + { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BOOKBINDING */ +}; static void enable_plugin(color_ostream &out) { @@ -2147,6 +2290,7 @@ private: { int skill_level = 0; int xp = 0; + int attr_weight = 0; if (labor != df::unit_labor::NONE) { @@ -2155,10 +2299,16 @@ private: { skill_level = Units::getEffectiveSkill(d->dwarf, skill); xp = Units::getExperience(d->dwarf, skill, false); + + for (int pa = 0; pa < 6; pa++) + attr_weight += (skill_attr_weights[skill].phys_attr_weights[pa]) * (d->dwarf->body.physical_attrs[pa].value - 1000); + + for (int ma = 0; ma < 13; ma++) + attr_weight += (skill_attr_weights[skill].mental_attr_weights[ma]) * (d->dwarf->status.current_soul->mental_attrs[ma].value - 1000); } } - int score = skill_level * 1000 - (d->high_skill - skill_level) * 2000 + (xp / (skill_level + 5) * 10); + int score = skill_level * 1000 - (d->high_skill - skill_level) * 2000 + (xp / (skill_level + 5) * 10) + attr_weight; if (labor != df::unit_labor::NONE) { @@ -2176,6 +2326,8 @@ private: score += 5000; } + score -= Units::computeMovementSpeed(d->dwarf); + return score; } From ad84217687fa84ef9e0375a705a14b35290c2cf9 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 26 Nov 2016 18:08:48 -0600 Subject: [PATCH 256/413] fix white space to make travis happy --- plugins/labormanager.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index eedcffe7e..e0c26bb61 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1825,7 +1825,7 @@ private: // (except for farms and trade depots) if (b->getType() != df::building_type::FarmPlot && - b->getType() != df::building_type::TradeDepot) + b->getType() != df::building_type::TradeDepot) { int fjid = -1; for (int jn = 0; jn < b->jobs.size(); jn++) @@ -2300,10 +2300,10 @@ private: skill_level = Units::getEffectiveSkill(d->dwarf, skill); xp = Units::getExperience(d->dwarf, skill, false); - for (int pa = 0; pa < 6; pa++) + for (int pa = 0; pa < 6; pa++) attr_weight += (skill_attr_weights[skill].phys_attr_weights[pa]) * (d->dwarf->body.physical_attrs[pa].value - 1000); - for (int ma = 0; ma < 13; ma++) + for (int ma = 0; ma < 13; ma++) attr_weight += (skill_attr_weights[skill].mental_attr_weights[ma]) * (d->dwarf->status.current_soul->mental_attrs[ma].value - 1000); } } @@ -2540,10 +2540,10 @@ public: i->second = labor_infos[l].maximum_dwarfs(); int priority = labor_infos[l].priority(); - + priority += labor_infos[l].time_since_last_assigned()/12; priority -= labor_infos[l].busy_dwarfs; - + base_priority[l] = priority; if (i->second > 0) @@ -2578,8 +2578,8 @@ public: pq2.push(make_pair(priority, labor)); } - if (pq.empty()) - while(!pq2.empty()) + if (pq.empty()) + while(!pq2.empty()) { pq.push(pq2.top()); pq2.pop(); @@ -2706,8 +2706,8 @@ public: { set_labor(*d, l, true); } - if ((*d)->using_labor != df::unit_labor::NONE && - (score > current_score + 5000 || base_priority[(*d)->using_labor] < base_priority[l]) && + if ((*d)->using_labor != df::unit_labor::NONE && + (score > current_score + 5000 || base_priority[(*d)->using_labor] < base_priority[l]) && default_labor_infos[(*d)->using_labor].tool == TOOL_NONE) set_labor(*d, (*d)->using_labor, false); } @@ -2759,10 +2759,10 @@ public: if (l == df::unit_labor::NONE) continue; - set_labor(*d, l, - (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS) || - l == df::unit_labor::CLEAN || - l == df::unit_labor::REMOVE_CONSTRUCTION || + set_labor(*d, l, + (l >= df::unit_labor::HAUL_STONE && l <= df::unit_labor::HAUL_ANIMALS) || + l == df::unit_labor::CLEAN || + l == df::unit_labor::REMOVE_CONSTRUCTION || l == df::unit_labor::PULL_LEVER || l == df::unit_labor::HAUL_TRADE); } @@ -2892,7 +2892,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out ) // if (++step_count < 60) // return CR_OK; - if (*df::global::process_jobs) + if (*df::global::process_jobs) return CR_OK; step_count = 0; From 10384fe720d739c787cdc99dd55544fc1c6b6bdd Mon Sep 17 00:00:00 2001 From: nocico Date: Sat, 26 Nov 2016 13:34:56 +0200 Subject: [PATCH 257/413] make labormanager know building instruments is furniture hauling --- plugins/labormanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index e0c26bb61..362b6a4f5 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -841,6 +841,7 @@ private: case df::building_type::BarsVertical: case df::building_type::GrateWall: case df::building_type::Bookcase: + case df::building_type::Instrument: return df::unit_labor::HAUL_FURNITURE; case df::building_type::Trap: case df::building_type::GearAssembly: From 0acd1c9059d985591525ca96599a5e444790749c Mon Sep 17 00:00:00 2001 From: nocico Date: Sat, 26 Nov 2016 13:34:56 +0200 Subject: [PATCH 258/413] make labormanager know building instruments is furniture hauling --- plugins/labormanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index e7ab6ce31..12bac7227 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -842,6 +842,7 @@ private: case df::building_type::BarsVertical: case df::building_type::GrateWall: case df::building_type::Bookcase: + case df::building_type::Instrument: return df::unit_labor::HAUL_FURNITURE; case df::building_type::Trap: case df::building_type::GearAssembly: From 5405c7674616ad4ddb13dfa0a9281ba29980a89e Mon Sep 17 00:00:00 2001 From: nocico Date: Mon, 28 Nov 2016 05:25:38 +0200 Subject: [PATCH 259/413] labormanager: support for jobs in bowyer's shop --- plugins/labormanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 7e2bf9584..635eadaa7 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1021,6 +1021,8 @@ private: return df::unit_labor::LEATHER; case df::workshop_type::Clothiers: return df::unit_labor::CLOTHESMAKER; + case df::workshop_type::Bowyers: + return df::unit_labor::BOWYER; case df::workshop_type::MagmaForge: case df::workshop_type::MetalsmithsForge: return metaltype; From ae48612ebd59d67a5c5082503f6cce31355a7b21 Mon Sep 17 00:00:00 2001 From: nocico Date: Mon, 28 Nov 2016 05:25:38 +0200 Subject: [PATCH 260/413] labormanager: support for jobs in bowyer's shop --- plugins/labormanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 362b6a4f5..ce8e18a6d 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1020,6 +1020,8 @@ private: return df::unit_labor::LEATHER; case df::workshop_type::Clothiers: return df::unit_labor::CLOTHESMAKER; + case df::workshop_type::Bowyers: + return df::unit_labor::BOWYER; case df::workshop_type::MagmaForge: case df::workshop_type::MetalsmithsForge: return metaltype; From ba4952491a3b62a1817148ecdc5fdaac2e141391 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 28 Nov 2016 00:02:59 -0500 Subject: [PATCH 261/413] Update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 25f85f8c7..35cd74b06 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 25f85f8c7b7a2f0b5a635a237985952337dcfef7 +Subproject commit 35cd74b0688565e8b37275d20d99911c7f5b2c7e From 15b7ba552d42e47ab2bc3cd96fb8386f04bdcc2d Mon Sep 17 00:00:00 2001 From: nocico Date: Tue, 29 Nov 2016 01:12:40 +0200 Subject: [PATCH 262/413] labormanager: trap components --- plugins/labormanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 635eadaa7..a582ce2d1 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1273,7 +1273,7 @@ public: job_to_labor_table[df::job_type::FireCatapult] = jlf_const(df::unit_labor::SIEGEOPERATE); job_to_labor_table[df::job_type::FireBallista] = jlf_const(df::unit_labor::SIEGEOPERATE); job_to_labor_table[df::job_type::ConstructMechanisms] = jlf_const(df::unit_labor::MECHANIC); - job_to_labor_table[df::job_type::MakeTrapComponent] = jlf_const(df::unit_labor::MECHANIC) ; + job_to_labor_table[df::job_type::MakeTrapComponent] = jlf_make_weapon; job_to_labor_table[df::job_type::LoadCageTrap] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::LoadStoneTrap] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::LoadWeaponTrap] = jlf_const(df::unit_labor::MECHANIC) ; From 442a12a9b28580a96fb44bb6aaf7a1f7d859107f Mon Sep 17 00:00:00 2001 From: nocico Date: Tue, 29 Nov 2016 04:24:25 +0200 Subject: [PATCH 263/413] labormanager: multimaterial constructions --- plugins/labormanager.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index a582ce2d1..b90b1656c 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -673,8 +673,15 @@ static df::building* get_building_from_job(df::job* j) return 0; } -static df::unit_labor construction_build_labor (df::item* i) +static df::unit_labor construction_build_labor (df::building_actual* b) { + if (b->getType() == df::building_type::RoadPaved) + return df::unit_labor::BUILD_ROAD; + auto a = (df::building_actual *) b; + // For screw pumps contained_items[0] = pipe, 1 corkscrew, 2 block + // For wells 0 mechanism, 1 rope, 2 bucket, 3 block + // Trade depots and bridges use the last one too + df::item* i = a->contained_items.back()->item; MaterialInfo matinfo; if (i && matinfo.decode(i)) { @@ -813,7 +820,7 @@ private: df::building_actual* b = (df::building_actual*) bld; if (b->design && !b->design->flags.bits.designed) return df::unit_labor::ARCHITECT; - return construction_build_labor(j->items[0]->item); + return construction_build_labor(b); } break; case df::building_type::FarmPlot: @@ -911,8 +918,8 @@ private: case df::building_type::Well: case df::building_type::Windmill: { - df::building_actual* b = (df::building_actual*) bld; - return construction_build_labor(b->contained_items[0]->item); + auto b = (df::building_actual*) bld; + return construction_build_labor(b); } break; case df::building_type::FarmPlot: From d626990ac850936ffaec2bee36ae13a7b8fd4059 Mon Sep 17 00:00:00 2001 From: nocico Date: Tue, 29 Nov 2016 01:12:40 +0200 Subject: [PATCH 264/413] labormanager: trap components --- plugins/labormanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index ce8e18a6d..cf84faf8b 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1272,7 +1272,7 @@ public: job_to_labor_table[df::job_type::FireCatapult] = jlf_const(df::unit_labor::SIEGEOPERATE); job_to_labor_table[df::job_type::FireBallista] = jlf_const(df::unit_labor::SIEGEOPERATE); job_to_labor_table[df::job_type::ConstructMechanisms] = jlf_const(df::unit_labor::MECHANIC); - job_to_labor_table[df::job_type::MakeTrapComponent] = jlf_const(df::unit_labor::MECHANIC) ; + job_to_labor_table[df::job_type::MakeTrapComponent] = jlf_make_weapon; job_to_labor_table[df::job_type::LoadCageTrap] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::LoadStoneTrap] = jlf_const(df::unit_labor::MECHANIC) ; job_to_labor_table[df::job_type::LoadWeaponTrap] = jlf_const(df::unit_labor::MECHANIC) ; From 5c16b5a2b730959a44f6f712c98ef5e40ee6c133 Mon Sep 17 00:00:00 2001 From: nocico Date: Tue, 29 Nov 2016 04:24:25 +0200 Subject: [PATCH 265/413] labormanager: multimaterial constructions --- plugins/labormanager.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index cf84faf8b..d263c1c66 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -672,8 +672,15 @@ static df::building* get_building_from_job(df::job* j) return 0; } -static df::unit_labor construction_build_labor (df::item* i) +static df::unit_labor construction_build_labor (df::building_actual* b) { + if (b->getType() == df::building_type::RoadPaved) + return df::unit_labor::BUILD_ROAD; + auto a = (df::building_actual *) b; + // For screw pumps contained_items[0] = pipe, 1 corkscrew, 2 block + // For wells 0 mechanism, 1 rope, 2 bucket, 3 block + // Trade depots and bridges use the last one too + df::item* i = a->contained_items.back()->item; MaterialInfo matinfo; if (i && matinfo.decode(i)) { @@ -812,7 +819,7 @@ private: df::building_actual* b = (df::building_actual*) bld; if (b->design && !b->design->flags.bits.designed) return df::unit_labor::ARCHITECT; - return construction_build_labor(j->items[0]->item); + return construction_build_labor(b); } break; case df::building_type::FarmPlot: @@ -910,8 +917,8 @@ private: case df::building_type::Well: case df::building_type::Windmill: { - df::building_actual* b = (df::building_actual*) bld; - return construction_build_labor(b->contained_items[0]->item); + auto b = (df::building_actual*) bld; + return construction_build_labor(b); } break; case df::building_type::FarmPlot: From d5d0775f1ad3888ea671df1f9f2de80324996672 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 29 Nov 2016 00:22:34 -0600 Subject: [PATCH 266/413] Remove redundant cast --- plugins/labormanager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index d263c1c66..53fce05ea 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -676,11 +676,10 @@ static df::unit_labor construction_build_labor (df::building_actual* b) { if (b->getType() == df::building_type::RoadPaved) return df::unit_labor::BUILD_ROAD; - auto a = (df::building_actual *) b; // For screw pumps contained_items[0] = pipe, 1 corkscrew, 2 block // For wells 0 mechanism, 1 rope, 2 bucket, 3 block // Trade depots and bridges use the last one too - df::item* i = a->contained_items.back()->item; + df::item* i = b->contained_items.back()->item; MaterialInfo matinfo; if (i && matinfo.decode(i)) { From 77a1264a947f3201639b5991f57b36e31f69b125 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 1 Dec 2016 11:06:40 -0600 Subject: [PATCH 267/413] Fix deconstruction of buildings containing items --- plugins/labormanager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 53fce05ea..49645234a 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -676,10 +676,15 @@ static df::unit_labor construction_build_labor (df::building_actual* b) { if (b->getType() == df::building_type::RoadPaved) return df::unit_labor::BUILD_ROAD; + // Find last item in building with use mode 2 // For screw pumps contained_items[0] = pipe, 1 corkscrew, 2 block // For wells 0 mechanism, 1 rope, 2 bucket, 3 block // Trade depots and bridges use the last one too - df::item* i = b->contained_items.back()->item; + // Must check use mode b/c buildings may have items in them that are not part of the building + + if ((*p)->use_mode == 2) + i = (*p)->item; + MaterialInfo matinfo; if (i && matinfo.decode(i)) { From 1d976385794a7050b2c5c9a4db169653080842fe Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 1 Dec 2016 11:10:52 -0600 Subject: [PATCH 268/413] Mysteriously disappearing code reinserted --- plugins/labormanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 49645234a..12e8aa0c3 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -682,6 +682,8 @@ static df::unit_labor construction_build_labor (df::building_actual* b) // Trade depots and bridges use the last one too // Must check use mode b/c buildings may have items in them that are not part of the building + df::item* i = 0; + for (auto p = b->contained_items.begin(); p != b->contained_items.end(); p++) if ((*p)->use_mode == 2) i = (*p)->item; From ad6d6fbaa6907c5ca482fff3eb0589ea0d704322 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 1 Dec 2016 14:36:46 -0600 Subject: [PATCH 269/413] further tweak building construction labor identification It's always more complicated than you expect.... --- plugins/labormanager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 12e8aa0c3..2a97b7d58 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -676,7 +676,7 @@ static df::unit_labor construction_build_labor (df::building_actual* b) { if (b->getType() == df::building_type::RoadPaved) return df::unit_labor::BUILD_ROAD; - // Find last item in building with use mode 2 + // Find last item in building with use mode appropriate to the building's constructions state // For screw pumps contained_items[0] = pipe, 1 corkscrew, 2 block // For wells 0 mechanism, 1 rope, 2 bucket, 3 block // Trade depots and bridges use the last one too @@ -684,7 +684,8 @@ static df::unit_labor construction_build_labor (df::building_actual* b) df::item* i = 0; for (auto p = b->contained_items.begin(); p != b->contained_items.end(); p++) - if ((*p)->use_mode == 2) + if (b->construction_stage > 0 && (*p)->use_mode == 2 || + b->construction_stage == 0 && (*p)->use_mode == 0) i = (*p)->item; MaterialInfo matinfo; From 595f3857b6b11cc42adc518fce787e914e54536c Mon Sep 17 00:00:00 2001 From: Stephen Baynham Date: Thu, 1 Dec 2016 20:13:49 -0800 Subject: [PATCH 270/413] Reverse the param order of these two methods The current way doesn't match other Job module methods --- library/include/modules/Job.h | 4 ++-- library/modules/Job.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/include/modules/Job.h b/library/include/modules/Job.h index 439a4484d..814f1e062 100644 --- a/library/include/modules/Job.h +++ b/library/include/modules/Job.h @@ -69,13 +69,13 @@ namespace DFHack // This helpful method only removes the backref from the item to the job, but it doesn't // remove the item ref from the job's vector, or delete it or anything. Think of it as a method // that does all the needful to make an item ref ready to delete. - DFHACK_EXPORT void disconnectJobItem(df::job_item_ref *item, df::job *job); + DFHACK_EXPORT void disconnectJobItem(df::job *job, df::job_item_ref *item); // This helpful method only removes the backref from whatever the general_ref points to, // it doesn't remove the general_ref from the job's vector, or delete it or anything. // Think of it as a method that does all the needful to make a ref ready to delete. // If it returns false, you've found a ref that the method doesn't know how to handle. Congratulations! // You should report that and/or check in a fix. - DFHACK_EXPORT bool disconnectJobGeneralRef(df::general_ref *ref, df::job *job); + DFHACK_EXPORT bool disconnectJobGeneralRef(df::job *job, df::general_ref *ref); // Delete a job & remove all refs from everywhere. // This method DELETES the job object! Everything related to it will be wiped // clean from the earth, so make sure you pull what you need out before calling this! diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index 531c85773..3f12ea2c2 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -304,7 +304,7 @@ void DFHack::Job::setJobCooldown(df::building *workshop, df::unit *worker, int c } } -void DFHack::Job::disconnectJobItem(df::job_item_ref *ref, df::job *job) { +void DFHack::Job::disconnectJobItem(df::job *job, df::job_item_ref *ref) { if (!ref) return; auto item = ref->item; @@ -329,7 +329,7 @@ void DFHack::Job::disconnectJobItem(df::job_item_ref *ref, df::job *job) { if (!stillHasJobs) item->flags.bits.in_job = false; } -bool DFHack::Job::disconnectJobGeneralRef(df::general_ref *ref, df::job *job) { +bool DFHack::Job::disconnectJobGeneralRef(df::job *job, df::general_ref *ref) { if (ref == NULL) return true; df::building *building = NULL; @@ -388,7 +388,7 @@ bool DFHack::Job::removeJob(df::job *job) { //Our code above should have ensured that this won't return false- if it does, there's not //a great way of recovering since we can't properly destroy the job & we can't leave it //around. Better to know the moment that becomes a problem. - bool success = disconnectJobGeneralRef(ref, job); + bool success = disconnectJobGeneralRef(job, ref); assert(success); vector_erase_at(job->general_refs, 0); @@ -398,7 +398,7 @@ bool DFHack::Job::removeJob(df::job *job) { //Detach all items from the job while (job->items.size() > 0) { auto itemRef = job->items[0]; - disconnectJobItem(itemRef, job); + disconnectJobItem(job, itemRef); vector_erase_at(job->items, 0); if (itemRef != NULL) delete itemRef; } From 8488b1a95396260566791c3f386e4770b1fadd57 Mon Sep 17 00:00:00 2001 From: jj Date: Mon, 5 Dec 2016 10:29:16 +0100 Subject: [PATCH 271/413] ruby: use correct raw string length with encodings --- plugins/ruby/ruby.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 006d63402..83463b870 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -624,7 +624,7 @@ static VALUE rb_dfget_vtable_ptr(VALUE self, VALUE objptr) static VALUE rb_dfhack_run(VALUE self, VALUE cmd) { std::string s; - int strlen = FIX2INT(rb_funcall(cmd, rb_intern("length"), 0)); + int strlen = FIX2INT(rb_funcall(cmd, rb_intern("bytesize"), 0)); s.assign(rb_string_value_ptr(&cmd), strlen); dfhack_run_queue->push_back(s); return Qtrue; @@ -686,7 +686,7 @@ static VALUE rb_dfmemory_read_double(VALUE self, VALUE addr) static VALUE rb_dfmemory_write(VALUE self, VALUE addr, VALUE raw) { // no stable api for raw.length between rb1.8/rb1.9 ... - int strlen = FIX2INT(rb_funcall(raw, rb_intern("length"), 0)); + int strlen = FIX2INT(rb_funcall(raw, rb_intern("bytesize"), 0)); memcpy((void*)rb_num2ulong(addr), rb_string_value_ptr(&raw), strlen); @@ -752,7 +752,7 @@ static VALUE rb_dfmemory_check(VALUE self, VALUE addr) // memory write (tmp override page permissions, eg patch code) static VALUE rb_dfmemory_patch(VALUE self, VALUE addr, VALUE raw) { - int strlen = FIX2INT(rb_funcall(raw, rb_intern("length"), 0)); + int strlen = FIX2INT(rb_funcall(raw, rb_intern("bytesize"), 0)); bool ret; ret = Core::getInstance().p->patchMemory((void*)rb_num2ulong(addr), @@ -831,7 +831,7 @@ static VALUE rb_dfmemory_read_stlstring(VALUE self, VALUE addr) static VALUE rb_dfmemory_write_stlstring(VALUE self, VALUE addr, VALUE val) { std::string *s = (std::string*)rb_num2ulong(addr); - int strlen = FIX2INT(rb_funcall(val, rb_intern("length"), 0)); + int strlen = FIX2INT(rb_funcall(val, rb_intern("bytesize"), 0)); s->assign(rb_string_value_ptr(&val), strlen); return Qtrue; } From a5afd9886390f11929c1f51b641cb9e3e25b3ee0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 5 Dec 2016 12:14:08 -0500 Subject: [PATCH 272/413] travis: install requests[security] to silence sphinx warning --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 22fe49e2d..38d053570 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ matrix: - gcc-4.8-multilib - g++-4.8-multilib before_install: - pip install --user sphinx + pip install --user sphinx "requests[security]" script: - git tag tmp-travis-build - sh travis/git-info.sh From 672410bea72e04c4ddada7a6ece68820be1bd5c6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 5 Dec 2016 12:21:27 -0500 Subject: [PATCH 273/413] travis: Use sphinx 1.4 only for now The sphinx.domains.cpp extension (which I'm not sure we're explicitly using) generates a warning with parallel docs builds, which causes the Travis build to fail. This may be something that needs to be fixed upstream. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 38d053570..932375656 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ matrix: - gcc-4.8-multilib - g++-4.8-multilib before_install: - pip install --user sphinx "requests[security]" + pip install --user "sphinx==1.4" "requests[security]" script: - git tag tmp-travis-build - sh travis/git-info.sh From 144675c74b1a5a03d218537c77e697b9dee1514d Mon Sep 17 00:00:00 2001 From: Ben Rosser Date: Tue, 6 Dec 2016 21:40:30 -0500 Subject: [PATCH 274/413] Update bundled tinyxml version from 2.5.3 to 2.6.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream has moved onto tinyxml2, so this is likely to be the last release of the original tinyxml (2.6.2 came out in 2011). dfhack should therefore probably ship 2.6.2, since it's unlikely there will ever be future fixes to this code. The upstream changelog (taken from "changes.txt" in upstream tarball) contains many bugfixes and is included in the commit message below. 2.5.4 - A TiXMLDocument can't be a sub-node. Block this from happening in the 'replace'. Thanks Noam. - [ 1714831 ] TiXmlBase::location is not copied by copy-ctors, fix reported and suggested by Nicola Civran. - Fixed possible memory overrun in the comment reading code - thanks gcarlton77 2.5.5 - Alex van der Wal spotted incorrect types (lf) being used in print and scan. robertnestor pointed out some problems with the simple solution. Types updated. - Johannes Hillert pointed out some bug typos. - Christian Mueller identified inconsistent error handling with Attributes. - olivier barthelemy also reported a problem with double truncation, also related to the %lf issue. - zaelsius came up with a great (and simple) suggestion to fix QueryValueAttribute truncating strings. - added some null pointer checks suggested by hansenk - Sami V�is�nen found a (rare) buffer overrun that could occur in parsing. - vi tri filed a bug that led to a refactoring of the attribute setting mess (as well as adding a missing SetDoubleAttribute() ) - removed TIXML_ERROR_OUT_OF_MEMORY. TinyXML does not systematically address OOO, and the notion it does is misleading. - vanneto, keithmarshall, others all reported the warning from IsWhiteSpace() usage. Cleaned this up - many thanks to everyone who reported this one. - tibur found a bug in end tag parsing 2.6.2 - Switched over to VC 2010 - Fixed up all the build issues arising from that. (Lots of latent build problems.) - Removed the old, now unmaintained and likely not working, build files. - Fixed some static analysis issues reported by orbitcowboy from cppcheck. - Bayard 95 sent in analysis from a different analyzer - fixes applied from that as well. - Tim Kosse sent a patch fixing an infinite loop. - Ma Anguo identified a doc issue. - Eddie Cohen identified a missing qualifier resulting in a compilation error on some systems. - Fixed a line ending bug. (What year is this? Can we all agree on a format for text files? Please? ...oh well.) --- depends/tinyxml/tinystr.cpp | 5 - depends/tinyxml/tinystr.h | 14 - depends/tinyxml/tinyxml.cpp | 434 +++++++++++++++--------------- depends/tinyxml/tinyxml.h | 127 ++++----- depends/tinyxml/tinyxmlerror.cpp | 3 +- depends/tinyxml/tinyxmlparser.cpp | 60 ++--- 6 files changed, 312 insertions(+), 331 deletions(-) diff --git a/depends/tinyxml/tinystr.cpp b/depends/tinyxml/tinystr.cpp index 681250714..066576820 100644 --- a/depends/tinyxml/tinystr.cpp +++ b/depends/tinyxml/tinystr.cpp @@ -1,6 +1,5 @@ /* www.sourceforge.net/projects/tinyxml -Original file by Yves Berquin. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -22,10 +21,6 @@ must not be misrepresented as being the original software. distribution. */ -/* - * THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005. - */ - #ifndef TIXML_USE_STL diff --git a/depends/tinyxml/tinystr.h b/depends/tinyxml/tinystr.h index 3c2aa9d54..89cca3341 100644 --- a/depends/tinyxml/tinystr.h +++ b/depends/tinyxml/tinystr.h @@ -1,6 +1,5 @@ /* www.sourceforge.net/projects/tinyxml -Original file by Yves Berquin. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -22,17 +21,6 @@ must not be misrepresented as being the original software. distribution. */ -/* - * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005. - * - * - completely rewritten. compact, clean, and fast implementation. - * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems) - * - fixed reserve() to work as per specification. - * - fixed buggy compares operator==(), operator<(), and operator>() - * - fixed operator+=() to take a const ref argument, following spec. - * - added "copy" constructor with length, and most compare operators. - * - added swap(), clear(), size(), capacity(), operator+(). - */ #ifndef TIXML_USE_STL @@ -106,13 +94,11 @@ class TiXmlString quit(); } - // = operator TiXmlString& operator = (const char * copy) { return assign( copy, (size_type)strlen(copy)); } - // = operator TiXmlString& operator = (const TiXmlString & copy) { return assign(copy.start(), copy.length()); diff --git a/depends/tinyxml/tinyxml.cpp b/depends/tinyxml/tinyxml.cpp index 5de21f6de..9c161dfcb 100644 --- a/depends/tinyxml/tinyxml.cpp +++ b/depends/tinyxml/tinyxml.cpp @@ -1,6 +1,6 @@ /* www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) +Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -31,6 +31,7 @@ distribution. #include "tinyxml.h" +FILE* TiXmlFOpen( const char* filename, const char* mode ); bool TiXmlBase::condenseWhiteSpace = true; @@ -161,6 +162,7 @@ void TiXmlNode::CopyTo( TiXmlNode* target ) const { target->SetValue (value.c_str() ); target->userData = userData; + target->location = location; } @@ -186,10 +188,11 @@ TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) assert( node->parent == 0 || node->parent == this ); assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); - if ( node->Type() == TiXmlNode::DOCUMENT ) + if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) { delete node; - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } @@ -210,9 +213,10 @@ TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) { - if ( addThis.Type() == TiXmlNode::DOCUMENT ) + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } TiXmlNode* node = addThis.Clone(); @@ -228,9 +232,10 @@ TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& if ( !beforeThis || beforeThis->parent != this ) { return 0; } - if ( addThis.Type() == TiXmlNode::DOCUMENT ) + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } @@ -260,9 +265,10 @@ TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& a if ( !afterThis || afterThis->parent != this ) { return 0; } - if ( addThis.Type() == TiXmlNode::DOCUMENT ) + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) { - if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } @@ -289,9 +295,20 @@ TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& a TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) { + if ( !replaceThis ) + return 0; + if ( replaceThis->parent != this ) return 0; + if ( withThis.ToDocument() ) { + // A document can never be a child. Thanks to Noam. + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + TiXmlNode* node = withThis.Clone(); if ( !node ) return 0; @@ -317,6 +334,10 @@ TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& wit bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) { + if ( !removeThis ) { + return false; + } + if ( removeThis->parent != this ) { assert( 0 ); @@ -502,7 +523,7 @@ const TiXmlDocument* TiXmlNode::GetDocument() const TiXmlElement::TiXmlElement (const char * _value) - : TiXmlNode( TiXmlNode::ELEMENT ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; value = _value; @@ -511,7 +532,7 @@ TiXmlElement::TiXmlElement (const char * _value) #ifdef TIXML_USE_STL TiXmlElement::TiXmlElement( const std::string& _value ) - : TiXmlNode( TiXmlNode::ELEMENT ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; value = _value; @@ -520,17 +541,18 @@ TiXmlElement::TiXmlElement( const std::string& _value ) TiXmlElement::TiXmlElement( const TiXmlElement& copy) - : TiXmlNode( TiXmlNode::ELEMENT ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) { firstChild = lastChild = 0; copy.CopyTo( this ); } -void TiXmlElement::operator=( const TiXmlElement& base ) +TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) { ClearThis(); base.CopyTo( this ); + return *this; } @@ -564,9 +586,9 @@ const char* TiXmlElement::Attribute( const char* name ) const #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name ) const { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - return &node->ValueStr(); + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( attrib ) + return &attrib->ValueStr(); return 0; } #endif @@ -574,195 +596,202 @@ const std::string* TiXmlElement::Attribute( const std::string& name ) const const char* TiXmlElement::Attribute( const char* name, int* i ) const { - const char* s = Attribute( name ); - if ( i ) - { - if ( s ) { - *i = atoi( s ); - } - else { - *i = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const char* result = 0; + + if ( attrib ) { + result = attrib->Value(); + if ( i ) { + attrib->QueryIntValue( i ); } } - return s; + return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const { - const std::string* s = Attribute( name ); - if ( i ) - { - if ( s ) { - *i = atoi( s->c_str() ); - } - else { - *i = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const std::string* result = 0; + + if ( attrib ) { + result = &attrib->ValueStr(); + if ( i ) { + attrib->QueryIntValue( i ); } } - return s; + return result; } #endif const char* TiXmlElement::Attribute( const char* name, double* d ) const { - const char* s = Attribute( name ); - if ( d ) - { - if ( s ) { - *d = atof( s ); - } - else { - *d = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const char* result = 0; + + if ( attrib ) { + result = attrib->Value(); + if ( d ) { + attrib->QueryDoubleValue( d ); } } - return s; + return result; } #ifdef TIXML_USE_STL const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const { - const std::string* s = Attribute( name ); - if ( d ) - { - if ( s ) { - *d = atof( s->c_str() ); - } - else { - *d = 0; + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const std::string* result = 0; + + if ( attrib ) { + result = &attrib->ValueStr(); + if ( d ) { + attrib->QueryDoubleValue( d ); } } - return s; + return result; } #endif int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryIntValue( ival ); +} + + +int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; - return node->QueryIntValue( ival ); + + int ival = 0; + int result = node->QueryIntValue( &ival ); + *value = (unsigned)ival; + return result; } -#ifdef TIXML_USE_STL -int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const +int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) return TIXML_NO_ATTRIBUTE; - return node->QueryIntValue( ival ); + + int result = TIXML_WRONG_TYPE; + if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) + { + *bval = true; + result = TIXML_SUCCESS; + } + else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) + { + *bval = false; + result = TIXML_SUCCESS; + } + return result; +} + + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryIntValue( ival ); } #endif int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) return TIXML_NO_ATTRIBUTE; - return node->QueryDoubleValue( dval ); + return attrib->QueryDoubleValue( dval ); } #ifdef TIXML_USE_STL int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const { - const TiXmlAttribute* node = attributeSet.Find( name ); - if ( !node ) + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) return TIXML_NO_ATTRIBUTE; - return node->QueryDoubleValue( dval ); + return attrib->QueryDoubleValue( dval ); } #endif void TiXmlElement::SetAttribute( const char * name, int val ) { - char buf[64]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%d", val ); - #else - sprintf( buf, "%d", val ); - #endif - SetAttribute( name, buf ); + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetIntValue( val ); + } } #ifdef TIXML_USE_STL void TiXmlElement::SetAttribute( const std::string& name, int val ) { - std::ostringstream oss; - oss << val; - SetAttribute( name, oss.str() ); + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetIntValue( val ); + } } #endif void TiXmlElement::SetDoubleAttribute( const char * name, double val ) { - char buf[256]; - #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%f", val ); - #else - sprintf( buf, "%f", val ); - #endif - SetAttribute( name, buf ); + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetDoubleValue( val ); + } } -void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) -{ - #ifdef TIXML_USE_STL - TIXML_STRING _name( cname ); - TIXML_STRING _value( cvalue ); - #else - const char* _name = cname; - const char* _value = cvalue; - #endif - - TiXmlAttribute* node = attributeSet.Find( _name ); - if ( node ) - { - node->SetValue( _value ); - return; +#ifdef TIXML_USE_STL +void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetDoubleValue( val ); } +} +#endif - TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue ); - if ( attrib ) - { - attributeSet.Add( attrib ); - } - else - { - TiXmlDocument* document = GetDocument(); - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + +void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); + if ( attrib ) { + attrib->SetValue( cvalue ); } } #ifdef TIXML_USE_STL -void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) +void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) { - TiXmlAttribute* node = attributeSet.Find( name ); - if ( node ) - { - node->SetValue( _value ); - return; - } - - TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); - if ( attrib ) - { - attributeSet.Add( attrib ); - } - else - { - TiXmlDocument* document = GetDocument(); - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); + if ( attrib ) { + attrib->SetValue( _value ); } } #endif @@ -881,14 +910,14 @@ const char* TiXmlElement::GetText() const } -TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) +TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; ClearError(); } -TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; @@ -898,7 +927,7 @@ TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode #ifdef TIXML_USE_STL -TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { tabsize = 4; useMicrosoftBOM = false; @@ -908,49 +937,33 @@ TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiX #endif -TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) +TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) { copy.CopyTo( this ); } -void TiXmlDocument::operator=( const TiXmlDocument& copy ) +TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) { Clear(); copy.CopyTo( this ); + return *this; } bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) { - // See STL_STRING_BUG below. - //StringToBuffer buf( value ); - return LoadFile( Value(), encoding ); } bool TiXmlDocument::SaveFile() const { - // See STL_STRING_BUG below. -// StringToBuffer buf( value ); -// -// if ( buf.buffer && SaveFile( buf.buffer ) ) -// return true; -// -// return false; return SaveFile( Value() ); } bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) { - // There was a really terrifying little bug here. The code: - // value = filename - // in the STL case, cause the assignment method of the std::string to - // be called. What is strange, is that the std::string had the same - // address as it's c_str() method, and so bad things happen. Looks - // like a bug in the Microsoft STL implementation. - // Add an extra string to avoid the crash. TIXML_STRING filename( _filename ); value = filename; @@ -995,11 +1008,6 @@ bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) return false; } - // If we have a file, assume it is all one big XML file, and read it in. - // The document parser may decide the document ends sooner than the entire file, however. - TIXML_STRING data; - data.reserve( length ); - // Subtle bug here. TinyXml did use fgets. But from the XML spec: // 2.11 End-of-Line Handling // @@ -1030,58 +1038,46 @@ bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) return false; } - const char* lastPos = buf; - const char* p = buf; + // Process the buffer in place to normalize new lines. (See comment above.) + // Copies from the 'p' to 'q' pointer, where p can advance faster if + // a newline-carriage return is hit. + // + // Wikipedia: + // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or + // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... + // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others + // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS + // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 + + const char* p = buf; // the read head + char* q = buf; // the write head + const char CR = 0x0d; + const char LF = 0x0a; buf[length] = 0; while( *p ) { assert( p < (buf+length) ); - if ( *p == 0xa ) { - // Newline character. No special rules for this. Append all the characters - // since the last string, and include the newline. - data.append( lastPos, (p-lastPos+1) ); // append, include the newline - ++p; // move past the newline - lastPos = p; // and point to the new buffer (may be 0) - assert( p <= (buf+length) ); - } - else if ( *p == 0xd ) { - // Carriage return. Append what we have so far, then - // handle moving forward in the buffer. - if ( (p-lastPos) > 0 ) { - data.append( lastPos, p-lastPos ); // do not add the CR - } - data += (char)0xa; // a proper newline - - if ( *(p+1) == 0xa ) { - // Carriage return - new line sequence - p += 2; - lastPos = p; - assert( p <= (buf+length) ); - } - else { - // it was followed by something else...that is presumably characters again. - ++p; - lastPos = p; - assert( p <= (buf+length) ); + assert( q <= (buf+length) ); + assert( q <= p ); + + if ( *p == CR ) { + *q++ = LF; + p++; + if ( *p == LF ) { // check for CR+LF (and skip LF) + p++; } } else { - ++p; + *q++ = *p++; } } - // Handle any left over characters. - if ( p-lastPos ) { - data.append( lastPos, p-lastPos ); - } - delete [] buf; - buf = 0; + assert( q <= (buf+length) ); + *q = 0; - Parse( data.c_str(), 0, encoding ); + Parse( buf, 0, encoding ); - if ( Error() ) - return false; - else - return true; + delete [] buf; + return !Error(); } @@ -1220,7 +1216,7 @@ void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) cons if (value.find ('\"') == TIXML_STRING::npos) { if ( cfile ) { - fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); + fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; @@ -1228,7 +1224,7 @@ void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) cons } else { if ( cfile ) { - fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); + fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); } if ( str ) { (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; @@ -1266,9 +1262,9 @@ void TiXmlAttribute::SetDoubleValue( double _value ) { char buf [256]; #if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value); + TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); #else - sprintf (buf, "%lf", _value); + sprintf (buf, "%g", _value); #endif SetValue (buf); } @@ -1284,16 +1280,17 @@ double TiXmlAttribute::DoubleValue() const } -TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) +TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { copy.CopyTo( this ); } -void TiXmlComment::operator=( const TiXmlComment& base ) +TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) { Clear(); base.CopyTo( this ); + return *this; } @@ -1382,7 +1379,7 @@ TiXmlNode* TiXmlText::Clone() const TiXmlDeclaration::TiXmlDeclaration( const char * _version, const char * _encoding, const char * _standalone ) - : TiXmlNode( TiXmlNode::DECLARATION ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { version = _version; encoding = _encoding; @@ -1394,7 +1391,7 @@ TiXmlDeclaration::TiXmlDeclaration( const char * _version, TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ) - : TiXmlNode( TiXmlNode::DECLARATION ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { version = _version; encoding = _encoding; @@ -1404,16 +1401,17 @@ TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) - : TiXmlNode( TiXmlNode::DECLARATION ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) { copy.CopyTo( this ); } -void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) +TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) { Clear(); copy.CopyTo( this ); + return *this; } @@ -1548,9 +1546,9 @@ void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) #ifdef TIXML_USE_STL -const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const +TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const { - for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( node->name == name ) return node; @@ -1558,23 +1556,22 @@ const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const return 0; } -/* -TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) +TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) { - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( node->name == name ) - return node; + TiXmlAttribute* attrib = Find( _name ); + if ( !attrib ) { + attrib = new TiXmlAttribute(); + Add( attrib ); + attrib->SetName( _name ); } - return 0; + return attrib; } -*/ #endif -const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const +TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const { - for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) { if ( strcmp( node->name.c_str(), name ) == 0 ) return node; @@ -1582,17 +1579,18 @@ const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const return 0; } -/* -TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) + +TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) { - for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) - { - if ( strcmp( node->name.c_str(), name ) == 0 ) - return node; + TiXmlAttribute* attrib = Find( _name ); + if ( !attrib ) { + attrib = new TiXmlAttribute(); + Add( attrib ); + attrib->SetName( _name ); } - return 0; + return attrib; } -*/ + #ifdef TIXML_USE_STL std::istream& operator>> (std::istream & in, TiXmlNode & base) diff --git a/depends/tinyxml/tinyxml.h b/depends/tinyxml/tinyxml.h index c6f40cc27..a3589e5b2 100644 --- a/depends/tinyxml/tinyxml.h +++ b/depends/tinyxml/tinyxml.h @@ -1,6 +1,6 @@ /* www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) +Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -63,21 +63,19 @@ distribution. #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) // Microsoft visual studio, version 2005 and higher. #define TIXML_SNPRINTF _snprintf_s - #define TIXML_SNSCANF _snscanf_s #define TIXML_SSCANF sscanf_s #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) // Microsoft visual studio, version 6 and higher. //#pragma message( "Using _sn* functions." ) #define TIXML_SNPRINTF _snprintf - #define TIXML_SNSCANF _snscanf #define TIXML_SSCANF sscanf #elif defined(__GNUC__) && (__GNUC__ >= 3 ) // GCC version 3 and higher.s //#warning( "Using sn* functions." ) #define TIXML_SNPRINTF snprintf - #define TIXML_SNSCANF snscanf #define TIXML_SSCANF sscanf #else + #define TIXML_SNPRINTF snprintf #define TIXML_SSCANF sscanf #endif #endif @@ -92,8 +90,8 @@ class TiXmlDeclaration; class TiXmlParsingData; const int TIXML_MAJOR_VERSION = 2; -const int TIXML_MINOR_VERSION = 5; -const int TIXML_PATCH_VERSION = 3; +const int TIXML_MINOR_VERSION = 6; +const int TIXML_PATCH_VERSION = 2; /* Internal structure for tracking location of items in the XML file. @@ -109,10 +107,11 @@ struct TiXmlCursor /** + Implements the interface to the "Visitor pattern" (see the Accept() method.) If you call the Accept() method, it requires being passed a TiXmlVisitor class to handle callbacks. For nodes that contain other nodes (Document, Element) you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves - are simple called with Visit(). + are simply called with Visit(). If you return 'true' from a Visit method, recursive parsing will continue. If you return false, no children of this node or its sibilings will be Visited. @@ -147,7 +146,7 @@ public: virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } /// Visit a comment node virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } - /// Visit an unknow node + /// Visit an unknown node virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } }; @@ -267,7 +266,6 @@ public: TIXML_NO_ERROR = 0, TIXML_ERROR, TIXML_ERROR_OPENING_FILE, - TIXML_ERROR_OUT_OF_MEMORY, TIXML_ERROR_PARSING_ELEMENT, TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, TIXML_ERROR_READING_ELEMENT_VALUE, @@ -288,6 +286,7 @@ public: protected: static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); + inline static bool IsWhiteSpace( char c ) { return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); @@ -462,13 +461,13 @@ public: */ enum NodeType { - DOCUMENT, - ELEMENT, - COMMENT, - UNKNOWN, - TEXT, - DECLARATION, - TYPECOUNT + TINYXML_DOCUMENT, + TINYXML_ELEMENT, + TINYXML_COMMENT, + TINYXML_UNKNOWN, + TINYXML_TEXT, + TINYXML_DECLARATION, + TINYXML_TYPECOUNT }; virtual ~TiXmlNode(); @@ -679,8 +678,8 @@ public: #endif /** Query the type (as an enumerated value, above) of this node. - The possible types are: DOCUMENT, ELEMENT, COMMENT, - UNKNOWN, TEXT, and DECLARATION. + The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, + TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION. */ int Type() const { return type; } @@ -915,17 +914,14 @@ public: const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } - const TiXmlAttribute* Find( const char* _name ) const; - TiXmlAttribute* Find( const char* _name ) { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); - } - #ifdef TIXML_USE_STL - const TiXmlAttribute* Find( const std::string& _name ) const; - TiXmlAttribute* Find( const std::string& _name ) { - return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); - } + TiXmlAttribute* Find( const char* _name ) const; + TiXmlAttribute* FindOrCreate( const char* _name ); + +# ifdef TIXML_USE_STL + TiXmlAttribute* Find( const std::string& _name ) const; + TiXmlAttribute* FindOrCreate( const std::string& _name ); +# endif - #endif private: //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), @@ -954,7 +950,7 @@ public: TiXmlElement( const TiXmlElement& ); - void operator=( const TiXmlElement& base ); + TiXmlElement& operator=( const TiXmlElement& base ); virtual ~TiXmlElement(); @@ -987,6 +983,13 @@ public: does not exist, then TIXML_NO_ATTRIBUTE is returned. */ int QueryIntAttribute( const char* name, int* _value ) const; + /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). + int QueryUnsignedAttribute( const char* name, unsigned* _value ) const; + /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). + Note that '1', 'true', or 'yes' are considered true, while '0', 'false' + and 'no' are considered false. + */ + int QueryBoolAttribute( const char* name, bool* _value ) const; /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). int QueryDoubleAttribute( const char* name, double* _value ) const; /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). @@ -1000,11 +1003,21 @@ public: } #ifdef TIXML_USE_STL + /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). + int QueryStringAttribute( const char* name, std::string* _value ) const { + const char* cstr = Attribute( name ); + if ( cstr ) { + *_value = std::string( cstr ); + return TIXML_SUCCESS; + } + return TIXML_NO_ATTRIBUTE; + } + /** Template form of the attribute query which will try to read the attribute into the specified type. Very easy, very powerful, but be careful to make sure to call this with the correct type. - NOTE: This method doesn't work correctly for 'string' types. + NOTE: This method doesn't work correctly for 'string' types that contain spaces. @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE */ @@ -1020,13 +1033,8 @@ public: return TIXML_SUCCESS; return TIXML_WRONG_TYPE; } - /* - This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string" - but template specialization is hard to get working cross-compiler. Leaving the bug for now. - - // The above will fail for std::string because the space character is used as a seperator. - // Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string - template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const + + int QueryValueAttribute( const std::string& name, std::string* outValue ) const { const TiXmlAttribute* node = attributeSet.Find( name ); if ( !node ) @@ -1034,7 +1042,6 @@ public: *outValue = node->ValueStr(); return TIXML_SUCCESS; } - */ #endif /** Sets an attribute of name to a given value. The attribute @@ -1053,6 +1060,8 @@ public: void SetAttribute( const std::string& name, const std::string& _value ); ///< STL std::string form. void SetAttribute( const std::string& name, int _value ); + ///< STL std::string form. + void SetDoubleAttribute( const std::string& name, double value ); #endif /** Sets an attribute of name to a given value. The attribute @@ -1144,7 +1153,6 @@ protected: const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); private: - TiXmlAttributeSet attributeSet; }; @@ -1155,13 +1163,13 @@ class TiXmlComment : public TiXmlNode { public: /// Constructs an empty comment. - TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} + TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {} /// Construct a comment from text. - TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) { + TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { SetValue( _value ); } TiXmlComment( const TiXmlComment& ); - void operator=( const TiXmlComment& base ); + TiXmlComment& operator=( const TiXmlComment& base ); virtual ~TiXmlComment() {} @@ -1175,8 +1183,8 @@ public: */ virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ @@ -1209,7 +1217,7 @@ public: normal, encoded text. If you want it be output as a CDATA text element, set the parameter _cdata to 'true' */ - TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT) + TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) { SetValue( initValue ); cdata = false; @@ -1218,15 +1226,15 @@ public: #ifdef TIXML_USE_STL /// Constructor. - TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) + TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) { SetValue( initValue ); cdata = false; } #endif - TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } - void operator=( const TiXmlText& base ) { base.CopyTo( this ); } + TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT ) { copy.CopyTo( this ); } + TiXmlText& operator=( const TiXmlText& base ) { base.CopyTo( this ); return *this; } // Write this text object to a FILE stream. virtual void Print( FILE* cfile, int depth ) const; @@ -1278,7 +1286,7 @@ class TiXmlDeclaration : public TiXmlNode { public: /// Construct an empty declaration. - TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} + TiXmlDeclaration() : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {} #ifdef TIXML_USE_STL /// Constructor. @@ -1293,7 +1301,7 @@ public: const char* _standalone ); TiXmlDeclaration( const TiXmlDeclaration& copy ); - void operator=( const TiXmlDeclaration& copy ); + TiXmlDeclaration& operator=( const TiXmlDeclaration& copy ); virtual ~TiXmlDeclaration() {} @@ -1346,11 +1354,11 @@ private: class TiXmlUnknown : public TiXmlNode { public: - TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} + TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) {} virtual ~TiXmlUnknown() {} - TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } - void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } + TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) { copy.CopyTo( this ); } + TiXmlUnknown& operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); return *this; } /// Creates a copy of this Unknown and returns it. virtual TiXmlNode* Clone() const; @@ -1359,8 +1367,8 @@ public: virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); - virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. - virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. /** Walk the XML tree visiting this node and all of its children. */ @@ -1396,7 +1404,7 @@ public: #endif TiXmlDocument( const TiXmlDocument& copy ); - void operator=( const TiXmlDocument& copy ); + TiXmlDocument& operator=( const TiXmlDocument& copy ); virtual ~TiXmlDocument() {} @@ -1423,14 +1431,10 @@ public: #ifdef TIXML_USE_STL bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. { -// StringToBuffer f( filename ); -// return ( f.buffer && LoadFile( f.buffer, encoding )); return LoadFile( filename.c_str(), encoding ); } bool SaveFile( const std::string& filename ) const ///< STL std::string version. { -// StringToBuffer f( filename ); -// return ( f.buffer && SaveFile( f.buffer )); return SaveFile( filename.c_str() ); } #endif @@ -1638,7 +1642,7 @@ public: TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } /// Copy constructor TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } - TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } + TiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; } /// Return a handle to the first child node. TiXmlHandle FirstChild() const; @@ -1799,4 +1803,3 @@ private: #endif #endif - diff --git a/depends/tinyxml/tinyxmlerror.cpp b/depends/tinyxml/tinyxmlerror.cpp index d24f63b2e..538c21d0b 100644 --- a/depends/tinyxml/tinyxmlerror.cpp +++ b/depends/tinyxml/tinyxmlerror.cpp @@ -31,12 +31,11 @@ distribution. // It also cleans up the code a bit. // -const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] = +const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] = { "No error", "Error", "Failed to open file", - "Memory allocation failed.", "Error parsing Element.", "Failed to read Element name", "Error reading Element value.", diff --git a/depends/tinyxml/tinyxmlparser.cpp b/depends/tinyxml/tinyxmlparser.cpp index 5793f0528..81b7eae96 100644 --- a/depends/tinyxml/tinyxmlparser.cpp +++ b/depends/tinyxml/tinyxmlparser.cpp @@ -1,6 +1,6 @@ /* www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) +Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any @@ -40,7 +40,7 @@ distribution. // Note tha "PutString" hardcodes the same list. This // is less flexible than it appears. Changing the entries // or order will break putstring. -TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = +TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = { { "&", 5, '&' }, { "<", 4, '<' }, @@ -174,7 +174,7 @@ class TiXmlParsingData public: void Stamp( const char* now, TiXmlEncoding encoding ); - const TiXmlCursor& Cursor() { return cursor; } + const TiXmlCursor& Cursor() const { return cursor; } private: // Only used by the document! @@ -346,7 +346,7 @@ const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) continue; } - if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. + if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. ++p; else break; @@ -354,7 +354,7 @@ const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) } else { - while ( (*p && IsWhiteSpace( *p )) || *p == '\n' || *p =='\r' ) + while ( *p && IsWhiteSpace( *p ) ) ++p; } @@ -631,9 +631,9 @@ const char* TiXmlBase::ReadText( const char* p, } } } - if ( p ) + if ( p && *p ) p += strlen( endTag ); - return p; + return ( p && *p ) ? p : 0; } #ifdef TIXML_USE_STL @@ -825,7 +825,6 @@ TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) return 0; } - TiXmlDocument* doc = GetDocument(); p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) @@ -896,11 +895,6 @@ TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) // Set the parent, so it can report errors returnNode->parent = this; } - else - { - if ( doc ) - doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); - } return returnNode; } @@ -1083,7 +1077,6 @@ const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc TIXML_STRING endTag (""; // Check for and read attributes. Also look for an empty // tag or an end tag. @@ -1122,10 +1115,20 @@ const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc } // We should find the end tag now + // note that: + // and + // + // are both valid end tags. if ( StringEqual( p, endTag.c_str(), false, encoding ) ) { p += endTag.length(); - return p; + p = SkipWhiteSpace( p, encoding ); + if ( p && *p && *p == '>' ) { + ++p; + return p; + } + if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); + return 0; } else { @@ -1139,7 +1142,6 @@ const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc TiXmlAttribute* attrib = new TiXmlAttribute(); if ( !attrib ) { - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding ); return 0; } @@ -1162,7 +1164,7 @@ const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc #endif if ( node ) { - node->SetValue( attrib->Value() ); + if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); delete attrib; return 0; } @@ -1191,8 +1193,7 @@ const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXm if ( !textNode ) { - if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding ); - return 0; + return 0; } if ( TiXmlBase::IsWhiteSpaceCondensed() ) @@ -1297,9 +1298,10 @@ const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc if ( !p ) { - if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); + if ( document ) + document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); } - if ( *p == '>' ) + if ( p && *p == '>' ) return p+1; return p; } @@ -1349,7 +1351,8 @@ const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc if ( !StringEqual( p, startTag, false, encoding ) ) { - document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); + if ( document ) + document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); return 0; } p += strlen( startTag ); @@ -1379,7 +1382,7 @@ const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEnc value.append( p, 1 ); ++p; } - if ( p ) + if ( p && *p ) p += strlen( endTag ); return p; @@ -1391,10 +1394,6 @@ const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlE p = SkipWhiteSpace( p, encoding ); if ( !p || !*p ) return 0; -// int tabsize = 4; -// if ( document ) -// tabsize = document->TabSize(); - if ( data ) { data->Stamp( p, encoding ); @@ -1446,7 +1445,7 @@ const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlE // its best, even without them. value = ""; while ( p && *p // existence - && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace + && !IsWhiteSpace( *p ) // whitespace && *p != '/' && *p != '>' ) // tag end { if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { @@ -1515,7 +1514,8 @@ const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncodi if ( !StringEqual( p, startTag, false, encoding ) ) { - document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); + if ( document ) + document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); return 0; } p += strlen( startTag ); @@ -1539,7 +1539,7 @@ const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncodi const char* end = "<"; p = ReadText( p, &value, ignoreWhite, end, false, encoding ); - if ( p ) + if ( p && *p ) return p-1; // don't truncate the '<' return 0; } From 50ce9942f443c4a51d65f31edf5d9984a1ece718 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 8 Dec 2016 16:01:14 -0600 Subject: [PATCH 275/413] labormanager: add deconstruct labor for constructed instruments (#7) --- plugins/labormanager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index bb971ebd2..fed0b1abe 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -961,6 +961,7 @@ private: case df::building_type::GrateFloor: case df::building_type::GrateWall: case df::building_type::Bookcase: + case df::building_type::Instrument: return df::unit_labor::HAUL_FURNITURE; case df::building_type::AnimalTrap: return df::unit_labor::TRAPPER; From 1a9d8629c555ea2cdfb48468561f90b98bd0f938 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 9 Dec 2016 09:54:20 -0600 Subject: [PATCH 276/413] labormanager: fix StoreItemInVehicle labor inference (#8) * labormanager: add deconstruct labor for constructed instruments * labormanager: fix StoreItemInVehicle labor inference StoreItemInVehicle requires the labor appropriate to the item being stashed --- plugins/labormanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index fed0b1abe..94a22acb3 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1375,7 +1375,7 @@ public: job_to_labor_table[df::job_type::CarveTrack] = jlf_const(df::unit_labor::DETAIL); job_to_labor_table[df::job_type::PushTrackVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES); job_to_labor_table[df::job_type::PlaceTrackVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES); - job_to_labor_table[df::job_type::StoreItemInVehicle] = jlf_const(df::unit_labor::HANDLE_VEHICLES); + job_to_labor_table[df::job_type::StoreItemInVehicle] = jlf_hauling; job_to_labor_table[df::job_type::GeldAnimal] = jlf_const(df::unit_labor::GELD); job_to_labor_table[df::job_type::MakeFigurine] = jlf_make_object; job_to_labor_table[df::job_type::MakeAmulet] = jlf_make_object; From 6e16a7a20c5d5c3e75aa0964f0dd3cc5011b30ea Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 9 Dec 2016 11:27:44 -0500 Subject: [PATCH 277/413] Update xml, scripts --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 84f6e968a..666083d1c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 84f6e968a9ec5515f9dbef96b445e3fc83f83e8b +Subproject commit 666083d1c705f65e2865759e27ead5ff32cd6005 diff --git a/scripts b/scripts index 35cd74b06..611e119cd 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 35cd74b0688565e8b37275d20d99911c7f5b2c7e +Subproject commit 611e119cdbbfa1559f6c11de16f773ef9babe0a2 From acdb369aa8479edbfbd4e30327876ad7592ff870 Mon Sep 17 00:00:00 2001 From: David Corbett Date: Fri, 9 Dec 2016 13:41:14 -0500 Subject: [PATCH 278/413] Avoid non-trivial bitfield constructors --- library/include/modules/MapCache.h | 4 ++-- library/modules/Gui.cpp | 8 ++++---- library/modules/Maps.cpp | 2 +- plugins/building-hacks.cpp | 4 +++- plugins/burrows.cpp | 4 ++-- plugins/stocks.cpp | 2 +- plugins/workflow.cpp | 4 ++-- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/library/include/modules/MapCache.h b/library/include/modules/MapCache.h index b64cc7859..0048f5bd9 100644 --- a/library/include/modules/MapCache.h +++ b/library/include/modules/MapCache.h @@ -542,7 +542,7 @@ class DFHACK_EXPORT MapCache df::tile_designation designationAt (DFCoord tilecoord) { Block * b= BlockAtTile(tilecoord); - return b ? b->DesignationAt(tilecoord) : df::tile_designation(0); + return b ? b->DesignationAt(tilecoord) : df::tile_designation(); } bool setDesignationAt (DFCoord tilecoord, df::tile_designation des) { @@ -554,7 +554,7 @@ class DFHACK_EXPORT MapCache df::tile_occupancy occupancyAt (DFCoord tilecoord) { Block * b= BlockAtTile(tilecoord); - return b ? b->OccupancyAt(tilecoord) : df::tile_occupancy(0); + return b ? b->OccupancyAt(tilecoord) : df::tile_occupancy(); } bool setOccupancyAt (DFCoord tilecoord, df::tile_occupancy occ) { diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 2cc955d63..9a86e69ec 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -1303,16 +1303,16 @@ bool Gui::addCombatReportAuto(df::unit *unit, df::announcement_flags mode, int r void Gui::showAnnouncement(std::string message, int color, bool bright) { - df::announcement_flags mode(0); + df::announcement_flags mode; mode.bits.D_DISPLAY = mode.bits.A_DISPLAY = true; - makeAnnouncement(df::announcement_type(0), mode, df::coord(), message, color, bright); + makeAnnouncement(df::announcement_type(), mode, df::coord(), message, color, bright); } void Gui::showZoomAnnouncement( df::announcement_type type, df::coord pos, std::string message, int color, bool bright ) { - df::announcement_flags mode(0); + df::announcement_flags mode; mode.bits.D_DISPLAY = mode.bits.A_DISPLAY = true; makeAnnouncement(type, mode, pos, message, color, bright); @@ -1335,7 +1335,7 @@ void Gui::showAutoAnnouncement( ) { using df::global::announcements; - df::announcement_flags flags(0); + df::announcement_flags flags; flags.bits.D_DISPLAY = flags.bits.A_DISPLAY = true; if (is_valid_enum_item(type) && announcements) diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index e56ae3109..e9674437a 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -195,7 +195,7 @@ df::map_block *Maps::ensureTileBlock (int32_t x, int32_t y, int32_t z) slot->map_pos.z = z; // Assume sky - df::tile_designation dsgn(0); + df::tile_designation dsgn; dsgn.bits.light = true; dsgn.bits.outside = true; diff --git a/plugins/building-hacks.cpp b/plugins/building-hacks.cpp index 483082c67..bc989df30 100644 --- a/plugins/building-hacks.cpp +++ b/plugins/building-hacks.cpp @@ -391,7 +391,9 @@ static int addBuilding(lua_State* L) int y=lua_tonumber(L,-1); lua_pop(L,1); - newDefinition.connections.can_connect.push_back(-1);//TODO add this too... + df::machine_conn_modes modes; + modes.whole = -1; + newDefinition.connections.can_connect.push_back(modes);//TODO add this too... newDefinition.connections.tiles.push_back(df::coord(x,y,0)); lua_pop(L,1); diff --git a/plugins/burrows.cpp b/plugins/burrows.cpp index 87adbe734..69325331e 100644 --- a/plugins/burrows.cpp +++ b/plugins/burrows.cpp @@ -547,8 +547,8 @@ static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable) { CHECK_NULL_POINTER(target); - df::tile_designation mask(0); - df::tile_designation value(0); + df::tile_designation mask; + df::tile_designation value; if (name == "ABOVE_GROUND") mask.bits.subterranean = true; diff --git a/plugins/stocks.cpp b/plugins/stocks.cpp index 8565c703f..3c7193701 100644 --- a/plugins/stocks.cpp +++ b/plugins/stocks.cpp @@ -1198,7 +1198,7 @@ private: if (state_to_apply == -1) state_to_apply = (item->flags.whole & flags.whole) ? 0 : 1; - grouped_entry->setFlags(flags.whole, state_to_apply); + grouped_entry->setFlags(flags, state_to_apply); } } diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp index 18090afc6..55f1dc504 100644 --- a/plugins/workflow.cpp +++ b/plugins/workflow.cpp @@ -793,7 +793,7 @@ static ItemConstraint *get_constraint(color_ostream &out, const std::string &str if (item.subtype >= 0) weight += 10000; - df::dfhack_material_category mat_mask(0); + df::dfhack_material_category mat_mask; std::string maskstr = vector_get(tokens,1); if (!maskstr.empty() && !parseJobMaterialCategory(&mat_mask, maskstr)) { out.printerr("Cannot decode material mask: %s\n", maskstr.c_str()); @@ -1031,7 +1031,7 @@ static int cbEnumJobOutputs(lua_State *L) lua_settop(L, 6); - df::dfhack_material_category mat_mask(0); + df::dfhack_material_category mat_mask; if (!lua_isnil(L, 3)) Lua::CheckDFAssign(L, &mat_mask, 3); From 3bae9d9d656172faea64f29b69dfcf6c6d8053af Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 10 Dec 2016 12:27:43 -0500 Subject: [PATCH 279/413] Lua API: Make bitfield.whole return an integer, not a decimal --- library/LuaTypes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index 8d61906b9..f281afe86 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -945,7 +945,7 @@ static int meta_bitfield_index(lua_State *state) { size_t intv = 0; memcpy(&intv, ptr, std::min(sizeof(intv), size_t(id->byte_size()))); - lua_pushnumber(state, intv); + lua_pushinteger(state, intv); return 1; } From e8c8953cbbce77cff69c9f1b49bc37bb27e9681d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 10 Dec 2016 18:22:28 -0500 Subject: [PATCH 280/413] Re-add and update misery plugin Closes #1037 Ref #1011 --- NEWS.rst | 1 + docs/Plugins.rst | 15 ++++ library/xml | 2 +- plugins/CMakeLists.txt | 2 +- plugins/misery.cpp | 200 ++++++++++++++++++++--------------------- 5 files changed, 113 insertions(+), 107 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index b7e80cf77..c011f6df2 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -58,6 +58,7 @@ New Plugins ----------- - `dwarfvet` enables animal caretaking - `labormanager` (formerly autolabor2): a more advanced alternative to `autolabor` +- `misery`: re-added and updated for the 0.4x series - `title-folder`: shows DF folder name in window title bar when enabled New Scripts diff --git a/docs/Plugins.rst b/docs/Plugins.rst index fac50d254..6e9dd566e 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -2469,6 +2469,21 @@ Options: .. _mode: +misery +====== +When enabled, fake bad thoughts will be added to all dwarves. + +Usage: + +:misery enable n: enable misery with optional magnitude n. If specified, n must + be positive. +:misery n: same as "misery enable n" +:misery enable: same as "misery enable 1" +:misery disable: stop adding new negative thoughts. This will not remove + existing negative thoughts. Equivalent to "misery 0". +:misery clear: remove fake thoughts, even after saving and reloading. Does + not change factor. + mode ==== This command lets you see and change the game mode directly. diff --git a/library/xml b/library/xml index 666083d1c..589e71541 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 666083d1c705f65e2865759e27ead5ff32cd6005 +Subproject commit 589e71541f54fac4ee3c575530317a67affac9e6 diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index c83f14e60..4611009c3 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -132,7 +132,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) DFHACK_PLUGIN(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) DFHACK_PLUGIN(manipulator manipulator.cpp) - #DFHACK_PLUGIN(misery misery.cpp) + DFHACK_PLUGIN(misery misery.cpp) DFHACK_PLUGIN(mode mode.cpp) DFHACK_PLUGIN(mousequery mousequery.cpp) DFHACK_PLUGIN(petcapRemover petcapRemover.cpp) diff --git a/plugins/misery.cpp b/plugins/misery.cpp index 59b745871..6a67dc90f 100644 --- a/plugins/misery.cpp +++ b/plugins/misery.cpp @@ -1,64 +1,107 @@ -#include "PluginManager.h" -#include "Export.h" +#include +#include +#include +#include #include "DataDefs.h" -#include "df/world.h" +#include "Export.h" +#include "PluginManager.h" + +#include "modules/Units.h" + +#include "df/emotion_type.h" #include "df/ui.h" #include "df/unit.h" +#include "df/unit_personality.h" +#include "df/unit_soul.h" #include "df/unit_thought_type.h" - -#include -#include -#include +#include "df/world.h" using namespace std; using namespace DFHack; -/* -misery -====== -When enabled, every new negative dwarven thought will be multiplied by a factor (2 by default). - -Usage: - -:misery enable n: enable misery with optional magnitude n. If specified, n must be positive. -:misery n: same as "misery enable n" -:misery enable: same as "misery enable 2" -: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. -*/ DFHACK_PLUGIN("misery"); DFHACK_PLUGIN_IS_ENABLED(is_enabled); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(ui); +REQUIRE_GLOBAL(cur_year); +REQUIRE_GLOBAL(cur_year_tick); -static int factor = 1; -static map processedThoughtCountTable; +typedef df::unit_personality::T_emotions Emotion; -//keep track of fake thoughts so you can remove them if requested -static vector > fakeThoughts; -static int count; -const int maxCount = 1000; +static int factor = 1; +static int tick = 0; +const int INTERVAL = 1000; command_result misery(color_ostream& out, vector& parameters); +void add_misery(df::unit *unit); +void clear_misery(df::unit *unit); + +const int FAKE_EMOTION_FLAG = (1 << 30); +const int STRENGTH_MULTIPLIER = 100; + +bool is_valid_unit (df::unit *unit) { + if (!Units::isOwnRace(unit) || !Units::isOwnCiv(unit)) + return false; + if (Units::isDead(unit)) + return false; + return true; +} + +inline bool is_fake_emotion (Emotion *e) { + return e->flags.whole & FAKE_EMOTION_FLAG; +} + +void add_misery (df::unit *unit) { + // Add a fake miserable thought + // Remove any fake ones that already exist + if (!unit || !unit->status.current_soul) + return; + clear_misery(unit); + auto &emotions = unit->status.current_soul->personality.emotions; + Emotion *e = new Emotion; + e->type = df::emotion_type::MISERY; + e->thought = df::unit_thought_type::SoapyBath; + e->flags.whole |= FAKE_EMOTION_FLAG; + emotions.push_back(e); + + for (Emotion *e : emotions) { + if (is_fake_emotion(e)) { + e->year = *cur_year; + e->year_tick = *cur_year_tick; + e->strength = STRENGTH_MULTIPLIER * factor; + e->severity = STRENGTH_MULTIPLIER * factor; + } + } +} + +void clear_misery (df::unit *unit) { + if (!unit || !unit->status.current_soul) + return; + auto &emotions = unit->status.current_soul->personality.emotions; + auto it = remove_if(emotions.begin(), emotions.end(), [](Emotion *e) { + if (is_fake_emotion(e)) { + delete e; + return true; + } + return false; + }); + emotions.erase(it, emotions.end()); +} DFhackCExport command_result plugin_shutdown(color_ostream& out) { - factor = 1; + factor = 0; return CR_OK; } DFhackCExport command_result plugin_onupdate(color_ostream& out) { static bool wasLoaded = false; - if ( factor == 1 || !world || !world->map.block_index ) { + if ( factor == 0 || !world || !world->map.block_index ) { if ( wasLoaded ) { //we just unloaded the game: clear all data - factor = 1; + factor = 0; is_enabled = false; - processedThoughtCountTable.clear(); - fakeThoughts.clear(); wasLoaded = false; } return CR_OK; @@ -68,71 +111,17 @@ DFhackCExport command_result plugin_onupdate(color_ostream& out) { wasLoaded = true; } - if ( count < maxCount ) { - count++; + if ( tick < INTERVAL ) { + tick++; return CR_OK; } - count = 0; - - int32_t race_id = ui->race_id; - int32_t civ_id = ui->civ_id; - for ( size_t a = 0; a < world->units.all.size(); a++ ) { - df::unit* unit = world->units.all[a]; //TODO: consider units.active - //living, native units only - if ( unit->race != race_id || unit->civ_id != civ_id ) - continue; - if ( unit->flags1.bits.dead ) - continue; - - int processedThoughtCount; - map::iterator i = processedThoughtCountTable.find(unit->id); - if ( i == processedThoughtCountTable.end() ) { - processedThoughtCount = unit->status.recent_events.size(); - processedThoughtCountTable[unit->id] = processedThoughtCount; - } else { - processedThoughtCount = (*i).second; - } - - if ( processedThoughtCount == unit->status.recent_events.size() ) { - continue; - } else if ( processedThoughtCount > unit->status.recent_events.size() ) { - processedThoughtCount = unit->status.recent_events.size(); - } + tick = 0; - //don't reprocess any old thoughts - vector newThoughts; - for ( size_t b = processedThoughtCount; b < unit->status.recent_events.size(); b++ ) { - df::unit_thought* oldThought = unit->status.recent_events[b]; - const char* bob = ENUM_ATTR(unit_thought_type, value, oldThought->type); - if ( bob[0] != '-' ) { - //out.print("unit %4d: old thought value = %s\n", unit->id, bob); - continue; - } - /*out.print("unit %4d: Duplicating thought type %d (%s), value %s, age %d, subtype %d, severity %d\n", - unit->id, - oldThought->type.value, - ENUM_ATTR(unit_thought_type, caption, (oldThought->type)), - //df::enum_traits::attr_table[oldThought->type].caption - bob, - oldThought->age, - oldThought->subtype, - oldThought->severity - );*/ - //add duplicate thoughts to the temp list - for ( size_t c = 0; c < factor; c++ ) { - df::unit_thought* thought = new df::unit_thought; - thought->type = unit->status.recent_events[b]->type; - thought->age = unit->status.recent_events[b]->age; - thought->subtype = unit->status.recent_events[b]->subtype; - thought->severity = unit->status.recent_events[b]->severity; - newThoughts.push_back(thought); - } + //TODO: consider units.active + for (df::unit *unit : world->units.all) { + if (is_valid_unit(unit)) { + add_misery(unit); } - for ( size_t b = 0; b < newThoughts.size(); b++ ) { - fakeThoughts.push_back(std::pair(a, unit->status.recent_events.size())); - unit->status.recent_events.push_back(newThoughts[b]); - } - processedThoughtCountTable[unit->id] = unit->status.recent_events.size(); } return CR_OK; @@ -162,7 +151,8 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) if (enable != is_enabled) { is_enabled = enable; - factor = enable ? 2 : 1; + factor = enable ? 1 : 0; + tick = INTERVAL; } return CR_OK; @@ -182,34 +172,34 @@ command_result misery(color_ostream &out, vector& parameters) { if ( parameters.size() > 1 ) { return CR_WRONG_USAGE; } - factor = 1; + factor = 0; is_enabled = false; return CR_OK; } else if ( parameters[0] == "enable" ) { is_enabled = true; - factor = 2; + factor = 1; if ( parameters.size() == 2 ) { int a = atoi(parameters[1].c_str()); - if ( a <= 1 ) { + if ( a < 1 ) { out.printerr("Second argument must be a positive integer.\n"); return CR_WRONG_USAGE; } factor = a; } + tick = INTERVAL; } else if ( parameters[0] == "clear" ) { - for ( size_t a = 0; a < fakeThoughts.size(); a++ ) { - int dorfIndex = fakeThoughts[a].first; - int thoughtIndex = fakeThoughts[a].second; - world->units.all[dorfIndex]->status.recent_events[thoughtIndex]->age = 1000000; + for (df::unit *unit : world->units.all) { + if (is_valid_unit(unit)) { + clear_misery(unit); + } } - fakeThoughts.clear(); } else { int a = atoi(parameters[0].c_str()); - if ( a < 1 ) { + if ( a < 0 ) { return CR_WRONG_USAGE; } factor = a; - is_enabled = factor > 1; + is_enabled = factor > 0; } return CR_OK; From 92c01edf98f8103f3fdf06759f6bacfcc3ac2a4a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 10 Dec 2016 18:23:17 -0500 Subject: [PATCH 281/413] Update scripts (fix export-dt-ini) --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 611e119cd..ad5b365f3 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 611e119cdbbfa1559f6c11de16f773ef9babe0a2 +Subproject commit ad5b365f3ec1db4648152b00af13b0cf32340425 From 4b91d3799ee358fb4124ec6c0d9c6c0d0b27858d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 10 Dec 2016 18:30:34 -0500 Subject: [PATCH 282/413] Fix misery docs anchor --- docs/Plugins.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 6e9dd566e..ccba07973 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -2467,7 +2467,7 @@ Options: :lair: Mark the map as monster lair :lair reset: Mark the map as ordinary (not lair) -.. _mode: +.. _misery: misery ====== @@ -2484,6 +2484,8 @@ Usage: :misery clear: remove fake thoughts, even after saving and reloading. Does not change factor. +.. _mode: + mode ==== This command lets you see and change the game mode directly. From 4c0cb6854f3ef87212bb43a46300130bcc1b0108 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 11 Dec 2016 00:23:16 -0500 Subject: [PATCH 283/413] Change minimum GCC version to 4.8 --- CMakeLists.txt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 654553f6b..9a0bffb84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,17 +24,14 @@ project(dfhack) macro(CHECK_GCC COMPILER_PATH) execute_process(COMMAND ${COMPILER_PATH} -dumpversion OUTPUT_VARIABLE GCC_VERSION_OUT) string(STRIP "${GCC_VERSION_OUT}" GCC_VERSION_OUT) - if (${GCC_VERSION_OUT} VERSION_LESS "4.5") - message(SEND_ERROR "${COMPILER_PATH} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.5 or later") + if (${GCC_VERSION_OUT} VERSION_LESS "4.8") + message(SEND_ERROR "${COMPILER_PATH} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.8 or later") elseif (${GCC_VERSION_OUT} VERSION_GREATER "4.9.9") # GCC 5 changes ABI name mangling to enable C++11 changes. # This must be disabled to enable linking against DF. # http://developerblog.redhat.com/2015/02/05/gcc5-and-the-c11-abi/ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) endif() - if(${GCC_VERSION_OUT} VERSION_LESS "4.8") - message(WARNING "You are using GCC < 4.8 (detected version: ${GCC_VERSION_OUT}). Support for GCC versions before 4.8 may be removed in the future.") - endif() endmacro() if(UNIX) From f3e2e5e7d45b7edd4f38ba0d175cbf04b252ec46 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 11 Dec 2016 18:04:00 -0500 Subject: [PATCH 284/413] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 589e71541..d08339d3c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 589e71541f54fac4ee3c575530317a67affac9e6 +Subproject commit d08339d3ce144152cdbb703462d53231b282757d From 697d35a583405c68b70c71353c1718ee6996c45f Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 11 Dec 2016 18:04:15 -0500 Subject: [PATCH 285/413] Update scripts: Merge dfhack/scripts#8 --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index ad5b365f3..619d5b311 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ad5b365f3ec1db4648152b00af13b0cf32340425 +Subproject commit 619d5b3116061fdfffa06b9e7cd266367bb42c0a From c8b7dbd2553baa2a98f2ef11e76f3a4ebe855be3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 11 Dec 2016 21:16:21 -0500 Subject: [PATCH 286/413] Fix manipulator crash when selecting profession from empty list Also add ListColumn::hasSelection() Fixes #1040 --- plugins/listcolumn.h | 12 ++++++++++++ plugins/manipulator.cpp | 15 +++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/plugins/listcolumn.h b/plugins/listcolumn.h index 5c96b4594..9914c8ea7 100644 --- a/plugins/listcolumn.h +++ b/plugins/listcolumn.h @@ -317,6 +317,18 @@ public: return results[0]; } + bool hasSelection() + { + for (auto item : list) + { + if (item.selected) + { + return true; + } + } + return false; + } + void clearSelection() { for_each_(list, clear_fn); diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index dfc7c1f0d..2bbb9d8c3 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -954,6 +954,7 @@ public: viewscreen_unitprofessionset(vector &base_units, bool filter_selected = true ) + :menu_options(-1) // default { menu_options.multiselect = false; menu_options.auto_select = true; @@ -967,7 +968,7 @@ public: std::string name = manager.templates[i].name; if (manager.templates[i].mask) name += " (mask)"; - ListEntry elem(name, i+1); + ListEntry elem(name, i); menu_options.add(elem); } menu_options.filterDisplay(); @@ -1001,20 +1002,22 @@ public: } if (events->count(interface_key::SELECT)) { - select_profession(menu_options.getFirstSelectedElem()); + if (menu_options.hasSelection()) + { + select_profession(menu_options.getFirstSelectedElem()); + } Screen::dismiss(this); return; } } void select_profession(size_t selected) { - if (selected > manager.templates.size()) + if (manager.templates.empty() || selected >= manager.templates.size()) return; - ProfessionTemplate prof = manager.templates[selected - 1]; + ProfessionTemplate prof = manager.templates[selected]; - for (auto it = units.begin(); it != units.end(); ++it) + for (UnitInfo *u : units) { - UnitInfo* u = (*it); if (!u || !u->unit || !u->allowEdit) continue; prof.apply(u); } From 439e13643c0458fcf0dd9c9ce14cdf44d409506a Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 13 Dec 2016 23:55:20 -0600 Subject: [PATCH 287/413] better hack to make ruby work on win64 --- plugins/ruby/ruby.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 83463b870..ed38868bd 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -345,7 +345,8 @@ static int df_loadruby(void) // ruby_sysinit is optional (ruby1.9 only) ruby_sysinit = (decltype(ruby_sysinit))LookupPlugin(libruby_handle, "ruby_sysinit"); -#define rbloadsym(s) if (!(s = (decltype(s))LookupPlugin(libruby_handle, #s))) return 0 +#define rbloadsyma(s,a) if (!(s = (decltype(s))LookupPlugin(libruby_handle, #a))) return 0 +#define rbloadsym(s) rbloadsyma(s,s) rbloadsym(ruby_init_stack); rbloadsym(ruby_init); rbloadsym(ruby_init_loadpath); @@ -362,8 +363,14 @@ static int df_loadruby(void) rbloadsym(rb_ary_shift); rbloadsym(rb_num2dbl); rbloadsym(rb_int2inum); +#if defined(_WIN64) + rbloadsyma(rb_uint2inum, rb_ull2inum); + rbloadsyma(rb_num2ulong, rb_num2ull); +#else rbloadsym(rb_uint2inum); rbloadsym(rb_num2ulong); +#endif + #undef rbloadsym // rb_float_new_in_heap in ruby 2 if (!((rb_float_new = (decltype(rb_float_new))(LookupPlugin(libruby_handle, "rb_float_new"))) || From 4c3515cc6b189a075acc57e867f65bcd511b0753 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 14 Dec 2016 12:56:54 -0500 Subject: [PATCH 288/413] Update NEWS.rst, add NEWS-dev.rst for prerelease changes --- NEWS.rst | 16 +++++++- docs/NEWS-dev.rst | 101 ++++++++++++++++++++++++++++++++++++++++++++++ docs/Plugins.rst | 5 ++- index.rst | 1 + 4 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 docs/NEWS-dev.rst diff --git a/NEWS.rst b/NEWS.rst index c011f6df2..1c7517adf 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -4,6 +4,11 @@ Items within each section are listed in alphabetical order to minimise merge conflicts. Try to match the style and level of detail of the other entries. + This file should not contain details specific to prereleases, but it should + contain changes from previous stable releases. For example, if a bug was + introduced in one alpha version and fixed in another, do not include it + here. + Sections for each release are added as required, and consist solely of the following in order as subheadings:: @@ -37,8 +42,10 @@ Internals --------- - 64-bit support on all platforms - Visual Studio 2015 now required on Windows instead of 2010 -- GCC 4.8 recommended on Linux and OS X (and now supported on OS X) +- GCC 4.8 or newer required on Linux and OS X (and now supported on OS X) - Several structure fixes to match 64-bit DF's memory layout +- Added ``DFHack::Job::removeJob()`` function +- Updated TinyXML from 2.5.3 to 2.6.2 Lua --- @@ -52,7 +59,6 @@ Lua Ruby ---- - Added support for loading ruby 2.x libraries -- Fixed some layouts on x64 (incomplete) New Plugins ----------- @@ -64,12 +70,18 @@ New Plugins New Scripts ----------- - `load-save`: loads a save non-interactively +- `modtools/change-build-menu`: Edit the build mode sidebar menus +- `modtools/if-entity`: Run a command if the current entity matches a given ID +- `season-palette`: Swap color palettes with the changes of the seasons Fixes ----- - The DF path on OS X can now contain spaces and ``:`` characters - Buildings::setOwner() changes now persist properly when saved +- `add-thought`: fixed support for emotion names +- `autofarm`: Made surface farms detect local biome - `devel/find-offsets`: fixed a crash when vtables used by globals aren't available +- `manipulator`: Fixed crash when selecting a profession from an empty list Misc Improvements ----------------- diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst new file mode 100644 index 000000000..6a247294b --- /dev/null +++ b/docs/NEWS-dev.rst @@ -0,0 +1,101 @@ +.. comment + This is the development changelog file for DFHack. If you add or change + anything, note it here under the heading "DFHack Future", in the appropriate + section. Items within each section are listed in alphabetical order to + minimise merge conflicts. Try to match the style and level of detail of the + other entries. + + This file contains changes that are relevant to users of prereleases. These + changes should include changes from just the previous release, whether that + release was stable or not. For instance, a feature added in 0.43.05-alpha1 + should go under "0.43.05-alpha1" here *and* "0.43.05-r1" (or "future") in + NEWS.rst. A fix in one prerelease for an issue in the previous prerelease + should just go here in the appropriate section, not in NEWS.rst. + + Sections for each release are added as required, and consist solely of the + following in order as subheadings:: + + Fixes + Structures + API Changes + Additions/Removals + Other Changes + + When referring to a script, plugin, or command, use backticks (```) to + create a link to the relevant documentation - and check that the docs are + still up to date! + + When adding a new release, change "DFHack future" to the appropriate title + before releasing, and then add a new "DFHack future" section after releasing. + +.. _dev-changelog: + +##################### +Development Changelog +##################### + +.. contents:: + :depth: 2 + +DFHack 0.43.05-alpha3 +===================== + +Fixes +----- +- `add-thought`: fixed support for emotion names +- `autofarm`: Made surface farms detect local biome +- `devel/export-dt-ini`: fixed squad_schedule_entry size +- `labormanager`: + + - Now accounts for unit attributes + - Made instrument-building jobs work (constructed instruments) + - Fixed deconstructing constructed instruments + - Fixed jobs in bowyer's shops + - Fixed trap component jobs + - Fixed multi-material construction jobs + - Fixed deconstruction of buildings containing items + - Fixed interference caused by "store item in vehicle" jobs + +- `manipulator`: Fixed crash when selecting a profession from an empty list +- `ruby`: + + - Fixed crash on Win64 due to truncated global addresses + - Fixed compilation on Win64 + - Use correct raw string length with encodings + +Structures +---------- +- Changed many ``comment`` XML attributes with version numbers to use new + ``since`` attribute instead +- ``activity_event_conflictst.sides``: named many fields +- ``building_def.build_key``: fixed size on 64-bit Linux and OS X +- ``historical_kills``: + + - ``unk_30`` -> ``killed_underground_region`` + - ``unk_40`` -> ``killed_region`` + +- ``historical_kills.killed_undead``: removed ``skeletal`` flag +- ``ui_advmode``: aligned enough so that it doesn't crash (64-bit OS X/Linux) +- ``ui_advmode.show_menu``: changed from bool to enum +- ``unit_personality.emotions.flags``: now a bitfield + +API Changes +----------- +- Added ``DFHack::Job::removeJob()`` function +- C++: Removed bitfield constructors that take an initial value. These kept + bitfields from being used in unions. Set ``bitfield.whole`` directly instead. +- Lua: ``bitfield.whole`` now returns an integer, not a decimal + +Additions/Removals +------------------ +- Removed source for treefarm plugin (wasn't built) +- Added `modtools/change-build-menu`: Edit the build mode sidebar menus +- Added `modtools/if-entity`: Run a command if the current entity matches a + given ID +- Added `season-palette`: Swap color palettes with the changes of the seasons + +Other changes +------------- +- Changed minimum GCC version to 4.8 on OS X and Linux (earlier versions + wouldn't have worked on Linux anyway) +- Updated TinyXML from 2.5.3 to 2.6.2 diff --git a/docs/Plugins.rst b/docs/Plugins.rst index ccba07973..b3e68459d 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -380,9 +380,10 @@ active in the current context. See also `hotkey-notes`. :dfhack-keybind:`hotkeys` .. _rb: +.. _ruby: -rb -== +ruby +==== Ruby language plugin, which evaluates the following arguments as a ruby string. Best used as ``:rb [string]``, for the special parsing mode. Alias ``rb_eval``. diff --git a/index.rst b/index.rst index 88d3ca6b1..1f647907b 100644 --- a/index.rst +++ b/index.rst @@ -59,6 +59,7 @@ For Developers /Contributing /docs/Compile + /docs/NEWS-dev /docs/Lua API /library/xml/SYNTAX /library/xml/how-to-update From 7b2e6f299f7f7dfb1b9a99562c47b38dbf04df2a Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 14 Dec 2016 13:18:37 -0500 Subject: [PATCH 289/413] Bump version to 0.43.05-alpha3 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a0bffb84..488dd323d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,7 @@ endif() # set up versioning. set(DF_VERSION "0.43.05") -SET(DFHACK_RELEASE "alpha2") +SET(DFHACK_RELEASE "alpha3") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From a5eb5d25028eaea2e2ad4454e0961676597d99d4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 15 Dec 2016 19:18:07 -0500 Subject: [PATCH 290/413] manipulator: Sort custom professions Also use == instead of string::compare() --- plugins/manipulator.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index 2bbb9d8c3..76b8251b5 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -647,7 +647,7 @@ struct ProfessionTemplate name = line.substr(nextInd + 1); continue; } - if (line.compare("MASK")==0) + if (line == "MASK") { mask = true; continue; @@ -655,7 +655,7 @@ struct ProfessionTemplate for (int i = 0; i < NUM_COLUMNS; i++) { - if (line.compare(ENUM_KEY_STR(unit_labor, columns[i].labor)) == 0) + if (line == ENUM_KEY_STR(unit_labor, columns[i].labor)) { labors.push_back(columns[i].labor); } @@ -743,9 +743,10 @@ public: return; } Filesystem::listdir(professions_folder, files); + std::sort(files.begin(), files.end()); for(size_t i = 0; i < files.size(); i++) { - if (files[i].compare(".") == 0 || files[i].compare("..") == 0) + if (files[i] == "." || files[i] == "..") continue; ProfessionTemplate t; From 5be77fa63dcdba88e1418eeea50d81fa462a52fe Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 16 Dec 2016 08:09:53 -0600 Subject: [PATCH 291/413] stockflow: Fix "integer expected" problem in stockflow --- plugins/lua/stockflow.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/lua/stockflow.lua b/plugins/lua/stockflow.lua index 6027bb455..510718ff1 100644 --- a/plugins/lua/stockflow.lua +++ b/plugins/lua/stockflow.lua @@ -1137,6 +1137,7 @@ function check_stockpiles(verbose) local filled, empty = check_pile(spec.stockpile, verbose) local amount = trigger.filled and filled or empty amount = (amount - (amount % trigger.divisor)) / trigger.divisor + amount = math.floor(amount) result[reaction] = (result[reaction] or 0) + amount end end From 1419d58b9a6d074edb0d56deda62f5f2e4f12852 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 16 Dec 2016 13:04:51 -0600 Subject: [PATCH 292/413] stockflow: Use "floor division" Per suggestion by @dscorbett --- plugins/lua/stockflow.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/lua/stockflow.lua b/plugins/lua/stockflow.lua index 510718ff1..32fc342fb 100644 --- a/plugins/lua/stockflow.lua +++ b/plugins/lua/stockflow.lua @@ -1136,8 +1136,7 @@ function check_stockpiles(verbose) local reaction = spec.entry.ints[entry_ints.order_number] local filled, empty = check_pile(spec.stockpile, verbose) local amount = trigger.filled and filled or empty - amount = (amount - (amount % trigger.divisor)) / trigger.divisor - amount = math.floor(amount) + amount = (amount - (amount % trigger.divisor)) // trigger.divisor result[reaction] = (result[reaction] or 0) + amount end end From ba48afe9080fdba05a94fc7b66f31bda4264c749 Mon Sep 17 00:00:00 2001 From: Lethosor Date: Fri, 16 Dec 2016 14:22:00 -0500 Subject: [PATCH 293/413] stockflow: Simplify calculation See #1046 Use math.floor() for now until we can get Lua 5.3 working on Travis --- plugins/lua/stockflow.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/lua/stockflow.lua b/plugins/lua/stockflow.lua index 32fc342fb..dd83e65d9 100644 --- a/plugins/lua/stockflow.lua +++ b/plugins/lua/stockflow.lua @@ -1135,8 +1135,7 @@ function check_stockpiles(verbose) if trigger and trigger.divisor then local reaction = spec.entry.ints[entry_ints.order_number] local filled, empty = check_pile(spec.stockpile, verbose) - local amount = trigger.filled and filled or empty - amount = (amount - (amount % trigger.divisor)) // trigger.divisor + local amount = math.floor((trigger.filled and filled or empty) / trigger.divisor) result[reaction] = (result[reaction] or 0) + amount end end From 3c7d2626e250a4128e2fa1a98f1480e40235ab33 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sun, 18 Dec 2016 17:57:23 -0600 Subject: [PATCH 294/413] df::dfhack_material_category has no constructor, must be manually initialized see #1047 --- plugins/buildingplan-lib.h | 4 +++- plugins/workflow.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/buildingplan-lib.h b/plugins/buildingplan-lib.h index 7ec0c41d4..6975960d2 100644 --- a/plugins/buildingplan-lib.h +++ b/plugins/buildingplan-lib.h @@ -114,7 +114,9 @@ struct ItemFilter bool decorated_only; ItemFilter() : min_quality(df::item_quality::Ordinary), decorated_only(false), valid(true) - { } + { + clear(); // mat_mask is not cleared by default (see issue #1047) + } bool matchesMask(DFHack::MaterialInfo &mat); diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp index 55f1dc504..f8f9e8231 100644 --- a/plugins/workflow.cpp +++ b/plugins/workflow.cpp @@ -357,7 +357,9 @@ public: : is_craft(false), min_quality(item_quality::Ordinary), is_local(false), weight(0), item_amount(0), item_count(0), item_inuse_amount(0), item_inuse_count(0), is_active(false), cant_resume_reported(false), low_stock_reported(-1) - {} + { + mat_mask.whole = 0; // see https://github.com/DFHack/dfhack/issues/1047 + } int goalCount() { return config.ival(0); } void setGoalCount(int v) { config.ival(0) = v; } From 506d124a98693cd7bad859b5429dbd660423d797 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 26 Dec 2016 19:41:25 -0500 Subject: [PATCH 295/413] Update xml Ref #1047, #1050 --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index d08339d3c..666f4c7f5 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit d08339d3ce144152cdbb703462d53231b282757d +Subproject commit 666f4c7f5fc578240d2a2ab2aa097bfc5c60d6ad From 8bd92b6a083d729e580811d5050e2f68414469ba Mon Sep 17 00:00:00 2001 From: Milo Christiansen Date: Tue, 27 Dec 2016 16:49:46 -0500 Subject: [PATCH 296/413] Add a Lua module for getting a tile's material (#1031) --- library/lua/tile-material.lua | 400 ++++++++++++++++++++++++++++++++++ 1 file changed, 400 insertions(+) create mode 100644 library/lua/tile-material.lua diff --git a/library/lua/tile-material.lua b/library/lua/tile-material.lua new file mode 100644 index 000000000..5661de73e --- /dev/null +++ b/library/lua/tile-material.lua @@ -0,0 +1,400 @@ +-- tile-material: Functions to help retrieve the material for a tile. + +--[[ +Copyright 2015-2016 Milo Christiansen + +This software is provided 'as-is', without any express or implied warranty. In +no event will the authors be held liable for any damages arising from the use of +this software. + +Permission is granted to anyone to use this software for any purpose, including +commercial applications, and to alter it and redistribute it freely, subject to +the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim +that you wrote the original software. If you use this software in a product, an +acknowledgment in the product documentation would be appreciated but is not +required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. +]] + +local _ENV = mkmodule("tile-material") + +--[====[ +tile-material +============= + +This module contains functions for finding the material of a tile. + +There is a function that will find the material of the tile based on it's type (in other words +it will return the material DF is using for that tile), and there are functions that will attempt +to return only a certain class of materials. + +Most users will be most interested in the generic "GetTileMat" function, but the other functions +should be useful in certain cases. For example "GetLayerMat" will always return the material of +the stone (or soil) in the current layer, ignoring any veins or other inclusions. + +Some tile types/materials have special behavior with the "GetTileMat" function. + +* Open space and other "material-less" tiles (such as semi-molten rock or eerie glowing pits) + will return nil. +* Ice will return the hard-coded water material ("WATER:NONE"). + +The specialized functions will return nil if a material of their type is not possible for a tile. +For example calling "GetVeinMat" for a tile that does not have (and has never had) a mineral vein +will always return nil. + +There are two functions for dealing with constructions, one to get the material of the construction +and one that gets the material of the tile the construction was built over. + +All the functions take coordinates as either three arguments (x, y, z) or one argument containing +a table with numeric x, y, and z keys. + +I am not sure how caved in tiles are handled, but after some quick testing it appears that the +game creates mineral veins for them. I am not 100% sure if these functions will reliably work +with all caved in tiles, but I can confirm that they do in at least some cases... +]====] + +-- Since there isn't any consistent style for module documentation I documented every function in +-- the style used by GoDoc (which is what I am most used to). + +-- Internal +local function prepPos(x, y, z) + if x ~= nil and y == nil and z == nil then + if type(x) ~= "table" or type(x.x) ~= "number" or type(x.y) ~= "number" or type(x.z) ~= "number" or x.x == -30000 then + error "Invalid coordinate argument(s)." + end + return x + else + if type(x) ~= "number" or type(y) ~= "number" or type(z) ~= "number" or x == -30000 then + error "Invalid coordinate argument(s)." + end + return {x = x, y = y, z = z} + end +end + +-- Internal +local function fixedMat(id) + local mat = dfhack.matinfo.find(id) + return function(x, y, z) + return mat + end +end + +-- BasicMats is a matspec table to pass to GetTileMatSpec or GetTileTypeMat. This particular +-- matspec table covers the common case of returning plant materials for plant tiles and other +-- materials for the remaining tiles. +BasicMats = { + [df.tiletype_material.AIR] = nil, -- Empty + [df.tiletype_material.SOIL] = GetLayerMat, + [df.tiletype_material.STONE] = GetLayerMat, + [df.tiletype_material.FEATURE] = GetFeatureMat, + [df.tiletype_material.LAVA_STONE] = GetLavaStone, + [df.tiletype_material.MINERAL] = GetVeinMat, + [df.tiletype_material.FROZEN_LIQUID] = fixedMat("WATER:NONE"), + [df.tiletype_material.CONSTRUCTION] = GetConstructionMat, + [df.tiletype_material.GRASS_LIGHT] = GetGrassMat, + [df.tiletype_material.GRASS_DARK] = GetGrassMat, + [df.tiletype_material.GRASS_DRY] = GetGrassMat, + [df.tiletype_material.GRASS_DEAD] = GetGrassMat, + [df.tiletype_material.PLANT] = GetShrubMat, + [df.tiletype_material.HFS] = nil, -- Eerie Glowing Pit + [df.tiletype_material.CAMPFIRE] = GetLayerMat, + [df.tiletype_material.FIRE] = GetLayerMat, + [df.tiletype_material.ASHES] = GetLayerMat, + [df.tiletype_material.MAGMA] = nil, -- SMR + [df.tiletype_material.DRIFTWOOD] = GetLayerMat, + [df.tiletype_material.POOL] = GetLayerMat, + [df.tiletype_material.BROOK] = GetLayerMat, + [df.tiletype_material.ROOT] = GetLayerMat, + [df.tiletype_material.TREE] = GetTreeMat, + [df.tiletype_material.MUSHROOM] = GetTreeMat, + [df.tiletype_material.UNDERWORLD_GATE] = nil, -- I guess this is for the gates found in vaults? +} + +-- NoPlantMats is a matspec table to pass to GetTileMatSpec or GetTileTypeMat. This particular +-- matspec table will ignore plants, returning layer materials (or nil for trees) instead. +NoPlantMats = { + [df.tiletype_material.SOIL] = GetLayerMat, + [df.tiletype_material.STONE] = GetLayerMat, + [df.tiletype_material.FEATURE] = GetFeatureMat, + [df.tiletype_material.LAVA_STONE] = GetLavaStone, + [df.tiletype_material.MINERAL] = GetVeinMat, + [df.tiletype_material.FROZEN_LIQUID] = fixedMat("WATER:NONE"), + [df.tiletype_material.CONSTRUCTION] = GetConstructionMat, + [df.tiletype_material.GRASS_LIGHT] = GetLayerMat, + [df.tiletype_material.GRASS_DARK] = GetLayerMat, + [df.tiletype_material.GRASS_DRY] = GetLayerMat, + [df.tiletype_material.GRASS_DEAD] = GetLayerMat, + [df.tiletype_material.PLANT] = GetLayerMat, + [df.tiletype_material.CAMPFIRE] = GetLayerMat, + [df.tiletype_material.FIRE] = GetLayerMat, + [df.tiletype_material.ASHES] = GetLayerMat, + [df.tiletype_material.DRIFTWOOD] = GetLayerMat, + [df.tiletype_material.POOL] = GetLayerMat, + [df.tiletype_material.BROOK] = GetLayerMat, + [df.tiletype_material.ROOT] = GetLayerMat, +} + +-- OnlyPlantMats is a matspec table to pass to GetTileMatSpec or GetTileTypeMat. This particular +-- matspec table will return nil for any non-plant tile. Plant tiles return the plant material. +OnlyPlantMats = { + [df.tiletype_material.GRASS_LIGHT] = GetGrassMat, + [df.tiletype_material.GRASS_DARK] = GetGrassMat, + [df.tiletype_material.GRASS_DRY] = GetGrassMat, + [df.tiletype_material.GRASS_DEAD] = GetGrassMat, + [df.tiletype_material.PLANT] = GetShrubMat, + [df.tiletype_material.TREE] = GetTreeMat, + [df.tiletype_material.MUSHROOM] = GetTreeMat, +} + +-- GetLayerMat returns the layer material for the given tile. +-- AFAIK this will never return nil. +function GetLayerMat(x, y, z) + local pos = prepPos(x, y, z) + + local region_info = dfhack.maps.getRegionBiome(dfhack.maps.getTileBiomeRgn(pos)) + local map_block = dfhack.maps.ensureTileBlock(pos) + + local biome = df.world_geo_biome.find(region_info.geo_index) + + local layer_index = map_block.designation[pos.x%16][pos.y%16].geolayer_index + local layer_mat_index = biome.layers[layer_index].mat_index + + return dfhack.matinfo.decode(0, layer_mat_index) +end + +-- GetLavaStone returns the biome lava stone material (generally obsidian). +function GetLavaStone(x, y, z) + local pos = prepPos(x, y, z) + + local regions = df.global.world.world_data.region_details + + local rx, ry = dfhack.maps.getTileBiomeRgn(pos) + + for _, region in ipairs(regions) do + if region.pos.x == rx and region.pos.y == ry then + return dfhack.matinfo.decode(0, region.lava_stone) + end + end + return nil +end + +-- GetVeinMat returns the vein material of the given tile or nil if the tile has no veins. +-- Multiple veins in one tile should be handled properly (smallest vein type, last in the list wins, +-- which seems to be the rule DF uses). +function GetVeinMat(x, y, z) + local pos = prepPos(x, y, z) + + local map_block = dfhack.maps.ensureTileBlock(pos) + + local events = {} + for _, event in ipairs(map_block.block_events) do + if getmetatable(event) == "block_square_event_mineralst" then + if dfhack.maps.getTileAssignment(event.tile_bitmask, pos.x, pos.y) then + table.insert(events, event) + end + end + end + + if #events == 0 then + return nil + end + + local event_priority = function(event) + if event.flags.cluster then + return 1 + elseif event.flags.vein then + return 2 + elseif event.flags.cluster_small then + return 3 + elseif event.flags.cluster_one then + return 4 + else + return 5 + end + end + + local priority = events[1] + for _, event in ipairs(events) do + if event_priority(event) >= event_priority(priority) then + priority = event + end + end + + return dfhack.matinfo.decode(0, priority.inorganic_mat) +end + +-- GetConstructionMat returns the material of the construction at the given tile or nil if the tile +-- has no construction. +function GetConstructionMat(x, y, z) + local pos = prepPos(x, y, z) + + for _, construction in ipairs(df.global.world.constructions) do + if construction.pos.x == pos.x and construction.pos.y == pos.y and construction.pos.z == pos.z then + return dfhack.matinfo.decode(construction) + end + end + return nil +end + +-- GetConstructOriginalTileMat returns the material of the tile under the construction at the given +-- tile or nil if the tile has no construction. +function GetConstructOriginalTileMat(x, y, z) + local pos = prepPos(x, y, z) + + for _, construction in ipairs(df.global.world.constructions) do + if construction.pos.x == pos.x and construction.pos.y == pos.y and construction.pos.z == pos.z then + return GetTileTypeMat(construction.original_tile, BasicMats, pos) + end + end + return nil +end + +-- GetTreeMat returns the material of the tree at the given tile or nil if the tile does not have a +-- tree or giant mushroom. +-- Currently roots are ignored. +function GetTreeMat(x, y, z) + local pos = prepPos(x, y, z) + + local function coordInTree(pos, tree) + local x1 = tree.pos.x - math.floor(tree.tree_info.dim_x / 2) + local x2 = tree.pos.x + math.floor(tree.tree_info.dim_x / 2) + local y1 = tree.pos.y - math.floor(tree.tree_info.dim_y / 2) + local y2 = tree.pos.y + math.floor(tree.tree_info.dim_y / 2) + local z1 = tree.pos.z + local z2 = tree.pos.z + tree.tree_info.body_height + + if not ((pos.x >= x1 and pos.x <= x2) and (pos.y >= y1 and pos.y <= y2) and (pos.z >= z1 and pos.z <= z2)) then + return false + end + + return not tree.tree_info.body[pos.z - tree.pos.z]:_displace((pos.y - y1) * tree.tree_info.dim_x + (pos.x - x1)).blocked + end + + for _, tree in ipairs(df.global.world.plants.all) do + if tree.tree_info ~= nil then + if coordInTree(pos, tree) then + return dfhack.matinfo.decode(419, tree.material) + end + end + end + return nil +end + +-- GetShrubMat returns the material of the shrub at the given tile or nil if the tile does not +-- contain a shrub or sapling. +function GetShrubMat(x, y, z) + local pos = prepPos(x, y, z) + + for _, shrub in ipairs(df.global.world.plants.all) do + if shrub.tree_info == nil then + if shrub.pos.x == pos.x and shrub.pos.y == pos.y and shrub.pos.z == pos.z then + return dfhack.matinfo.decode(419, shrub.material) + end + end + end + return nil +end + +-- GetGrassMat returns the material of the grass at the given tile or nil if the tile is not +-- covered in grass. +function GetGrassMat(x, y, z) + local pos = prepPos(x, y, z) + + local map_block = dfhack.maps.ensureTileBlock(pos) + + for _, event in ipairs(map_block.block_events) do + if getmetatable(event) == "block_square_event_grassst" then + local amount = event.amount[pos.x%16][pos.y%16] + if amount > 0 then + return df.plant_raw.find(event.plant_index).material + end + end + end + return nil +end + +-- GetFeatureMat returns the material of the feature (adamantine tube, underworld surface, etc) at +-- the given tile or nil if the tile is not made of a feature stone. +function GetFeatureMat(x, y, z) + local pos = prepPos(x, y, z) + + local map_block = dfhack.maps.ensureTileBlock(pos) + + if df.tiletype.attrs[map_block.tiletype[pos.x%16][pos.y%16]].material ~= df.tiletype_material.FEATURE then + return nil + end + + if map_block.designation[pos.x%16][pos.y%16].feature_local then + -- adamantine tube, etc + for id, idx in ipairs(df.global.world.features.feature_local_idx) do + if idx == map_block.local_feature then + return dfhack.matinfo.decode(df.global.world.features.map_features[id]) + end + end + elseif map_block.designation[pos.x%16][pos.y%16].feature_global then + -- cavern, magma sea, underworld, etc + for id, idx in ipairs(df.global.world.features.feature_global_idx) do + if idx == map_block.global_feature then + return dfhack.matinfo.decode(df.global.world.features.map_features[id]) + end + end + end + + return nil +end + +-- GetTileMat will return the material of the specified tile as determined by its tile type and the +-- world geology data, etc. +-- The returned material should exactly match the material reported by DF except in cases where is +-- is impossible to get a material. +-- This is equivalent to calling GetTileMatSpec with the BasicMats matspec table. +function GetTileMat(x, y, z) + return GetTileMatSpec(BasicMats, x, y, z) +end + +-- GetTileMatSpec is exactly like GetTileMat except you may specify an explicit matspec table. +-- +-- "matspec" tables are simply tables with tiletype material classes as keys and functions +-- taking a coordinate table and returning a material as values. These tables are used to +-- determine how a specific material for a given tiletype material classification is determined. +-- Any tiletype material class that is unset (left nil) in a matspec table will result in tiles +-- of that type returning nil for their material. +function GetTileMatSpec(matspec, x, y, z) + local pos = prepPos(x, y, z) + + local typ = dfhack.maps.getTileType(pos) + if typ == nil then + return nil + end + + return GetTileTypeMat(typ, matspec, pos) +end + +-- GetTileTypeMat returns the material of the given tile assuming it is the given tiletype. +-- +-- Use this function when you want to check to see what material a given tile would be if it +-- was a specific tiletype. For example you can check to see if the tile used to be part of +-- a mineral vein or similar. Note that you can do the same basic thing by calling the individual +-- material finders directly, but this is sometimes simpler. +-- +-- Unless the tile could be the given type this function will probably return nil. +function GetTileTypeMat(typ, matspec, x, y, z) + local pos = prepPos(x, y, z) + + local type_mat = df.tiletype.attrs[typ].material + + local mat_getter = matspec[type_mat] + if mat_getter == nil then + return nil + end + return mat_getter(pos) +end + +return _ENV + From cd0d9fed18a5c8597834506c8bb0630e5c195c43 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 27 Dec 2016 17:40:54 -0500 Subject: [PATCH 297/413] stocks: Support getSelectedItem() --- plugins/stocks.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/stocks.cpp b/plugins/stocks.cpp index 3c7193701..1d3d04d6f 100644 --- a/plugins/stocks.cpp +++ b/plugins/stocks.cpp @@ -1062,6 +1062,18 @@ public: std::string getFocusString() { return "stocks_view"; } + df::item *getSelectedItem() override + { + if (is_grouped) + return nullptr; + vector items = getSelectedItems(); + if (items.size() != 1) + return nullptr; + if (items[0]->entries.size() != 1) + return nullptr; + return items[0]->entries[0]; + } + private: StockListColumn items_column; int selected_column; From 538b07d214e26db4f390c2347fdefe54c6a7f88d Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 27 Dec 2016 23:24:22 -0500 Subject: [PATCH 298/413] Update xml and fix knowledge_scholar_category_flag::value() custom method Allows bitfields within unions (#1047, dfhack/df-structures#169) --- .../df/custom/knowledge_scholar_category_flag.methods.inc | 2 +- library/xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/include/df/custom/knowledge_scholar_category_flag.methods.inc b/library/include/df/custom/knowledge_scholar_category_flag.methods.inc index f5c4e9a76..c1fe1a564 100644 --- a/library/include/df/custom/knowledge_scholar_category_flag.methods.inc +++ b/library/include/df/custom/knowledge_scholar_category_flag.methods.inc @@ -3,7 +3,7 @@ df::enums::dfhack_knowledge_scholar_flag::dfhack_knowledge_scholar_flag value() int32_t value = category * 32; for (int32_t i = 0; i < 32; i++) { - if (flags & (1 << i)) + if (flags.whole & (1 << i)) { value += i; break; diff --git a/library/xml b/library/xml index 666f4c7f5..e84bdcd02 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 666f4c7f5fc578240d2a2ab2aa097bfc5c60d6ad +Subproject commit e84bdcd0280495aeb49f12c124b4e52c62aaafc9 From c99780aafd5294cc64feb18a14214182187327f8 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 15 Dec 2016 01:38:19 -0600 Subject: [PATCH 299/413] Add support for shell crafts. --- plugins/labormanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/labormanager.cpp b/plugins/labormanager.cpp index 94a22acb3..699e04605 100644 --- a/plugins/labormanager.cpp +++ b/plugins/labormanager.cpp @@ -1007,7 +1007,8 @@ private: case df::item_type::NONE: if (j->material_category.bits.bone || j->material_category.bits.horn || - j->material_category.bits.tooth) + j->material_category.bits.tooth || + j->material_category.bits.shell) return df::unit_labor::BONE_CARVE; else { From 408dba9da7ab2c04f983b6ee08d1df5807373d9b Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 28 Dec 2016 22:12:22 -0500 Subject: [PATCH 300/413] Update NEWS(-dev) and scripts (add fix/tile-occupancy) --- NEWS.rst | 7 ++++++- docs/NEWS-dev.rst | 22 ++++++++++++++++++++++ scripts | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 1c7517adf..2fdbfc561 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -55,6 +55,7 @@ Lua - ``df.new()`` supports more types: ``char``, ``intptr_t``, ``uintptr_t``, ``long``, ``unsigned long`` - String representations of vectors and a few other containers now include their lengths +- Added a ``tile-material`` module Ruby ---- @@ -69,6 +70,7 @@ New Plugins New Scripts ----------- +- `fix/tile-occupancy`: Clears bad occupancy flags on the selected tile. - `load-save`: loads a save non-interactively - `modtools/change-build-menu`: Edit the build mode sidebar menus - `modtools/if-entity`: Run a command if the current entity matches a given ID @@ -81,7 +83,10 @@ Fixes - `add-thought`: fixed support for emotion names - `autofarm`: Made surface farms detect local biome - `devel/find-offsets`: fixed a crash when vtables used by globals aren't available -- `manipulator`: Fixed crash when selecting a profession from an empty list +- `manipulator`: + + - Fixed crash when selecting a profession from an empty list + - Custom professions are now sorted alphabetically more reliably Misc Improvements ----------------- diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 6a247294b..1ff96f7bb 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -37,6 +37,28 @@ Development Changelog .. contents:: :depth: 2 +DFHack 0.43.05-alpha4 +===================== + +Fixes +----- +- Fixed an issue with uninitialized bitfields that was causing several issues + (disappearing buildings in `buildingplan`'s planning mode, strange behavior in + the extended `stocks` screen, and likely other problems). This issue was + introduced in 0.43.05-alpha3. +- `stockflow`: Fixed an "integer expected" error + +Additions/Removals +------------------ +- Added `fix/tile-occupancy`: Clears bad occupancy flags on the selected tile. + Useful for fixing blocked tiles introduced by the above buildingplan issue. +- Added a Lua ``tile-material`` module + +Other Changes +------------- +- `labormanager`: Add support for shell crafts +- `manipulator`: Custom professions are now sorted alphabetically more reliably + DFHack 0.43.05-alpha3 ===================== diff --git a/scripts b/scripts index 619d5b311..1cbbced78 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 619d5b3116061fdfffa06b9e7cd266367bb42c0a +Subproject commit 1cbbced78fe8433f78cd2b236c9d4e53e6493e60 From 6b3a5ac7848cfffe8a8b467655967dbb3fea5f19 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 29 Dec 2016 00:40:43 -0500 Subject: [PATCH 301/413] Bump to alpha4 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 488dd323d..3602655b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,7 @@ endif() # set up versioning. set(DF_VERSION "0.43.05") -SET(DFHACK_RELEASE "alpha3") +SET(DFHACK_RELEASE "alpha4") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From d18beb8dafb575cb8cb135910cf56e5a127965ff Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 29 Dec 2016 15:33:09 -0500 Subject: [PATCH 302/413] xml: Add some linux64 offsets, fix ui_sidebar_menus alignment Fixes #1053 Fixes #1054 Fixes #1055 --- docs/NEWS-dev.rst | 8 ++++++++ library/xml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 1ff96f7bb..9920e3433 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -48,6 +48,14 @@ Fixes introduced in 0.43.05-alpha3. - `stockflow`: Fixed an "integer expected" error +Structures +---------- +- Located several globals on 64-bit Linux: flows, timed_events, ui_advmode, + ui_building_assign_type, ui_building_assign_is_marked, + ui_building_assign_units, ui_building_assign_items, and ui_look_list. This + fixes `search-plugin`, `zone`, and `force`, among others. +- ``ui_sidebar_menus``: Fixed some x64 alignment issues + Additions/Removals ------------------ - Added `fix/tile-occupancy`: Clears bad occupancy flags on the selected tile. diff --git a/library/xml b/library/xml index e84bdcd02..bb4228f58 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e84bdcd0280495aeb49f12c124b4e52c62aaafc9 +Subproject commit bb4228f58b1601c4868c95be6763f5ff2e5d0a08 From 61d081849e76a2b5a60c63fc31ec4c193e3b295e Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 30 Dec 2016 18:02:51 -0500 Subject: [PATCH 303/413] xml: ui_sidebar_menus.command_line fix --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index bb4228f58..6ff5d183f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit bb4228f58b1601c4868c95be6763f5ff2e5d0a08 +Subproject commit 6ff5d183f5029cba683b4160b09438a2bbe3646f From cda4e7a30023dab81f4d1f52f2e901846aa3aba1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 30 Dec 2016 18:03:28 -0500 Subject: [PATCH 304/413] title-version: add prerelease indicator --- plugins/title-version.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/title-version.cpp b/plugins/title-version.cpp index 78a694211..127a1bd9f 100644 --- a/plugins/title-version.cpp +++ b/plugins/title-version.cpp @@ -36,10 +36,15 @@ struct title_version_hook : df::viewscreen_titlest { if (!DFHACK_IS_RELEASE) { OutputString(COLOR_WHITE, x, y, " (dev)"); - x = 0; y = 1; + x = 0; y++; OutputString(COLOR_WHITE, x, y, "Git: "); OutputString(COLOR_WHITE, x, y, DFHACK_GIT_DESCRIPTION); } + if (DFHACK_IS_PRERELEASE) + { + x = 0; y++; + OutputString(COLOR_LIGHTRED, x, y, "Pre-release build"); + } } }; From 92f890d3c6256ff62ecd393f2628eee3b931a4bf Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 4 Jan 2017 12:30:42 -0500 Subject: [PATCH 305/413] Update xml, scripts (#994 and file_compressor fix) --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 6ff5d183f..34331ef67 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 6ff5d183f5029cba683b4160b09438a2bbe3646f +Subproject commit 34331ef67f3d163f4ab66121449a8217eb1cfb47 diff --git a/scripts b/scripts index 1cbbced78..20eb2146f 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 1cbbced78fe8433f78cd2b236c9d4e53e6493e60 +Subproject commit 20eb2146fb93912b07034f3192dde1cf95a9ec7f From affcd658dc77cf16489439a0876c16fca784d2a8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 4 Jan 2017 12:29:21 -0500 Subject: [PATCH 306/413] title-version: Hide when loading a game (e.g. arena) --- plugins/title-version.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/title-version.cpp b/plugins/title-version.cpp index 127a1bd9f..be7bc7e79 100644 --- a/plugins/title-version.cpp +++ b/plugins/title-version.cpp @@ -31,6 +31,9 @@ struct title_version_hook : df::viewscreen_titlest { DEFINE_VMETHOD_INTERPOSE(void, render, ()) { INTERPOSE_NEXT(render)(); + if (loading) + return; + int x = 0, y = 0; OutputString(COLOR_WHITE, x, y, string("DFHack ") + DFHACK_VERSION); if (!DFHACK_IS_RELEASE) From e2fc7d3e00affe847de41278c42379d6b68a6191 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 5 Jan 2017 18:32:12 -0500 Subject: [PATCH 307/413] Update OS X compilation instructions - GCC 4.8+ is now required - remove references to 4.5, XCode 7, etc. - Homebrew's formula has been renamed to "gcc@4.8". "gcc48" still works as well, so applying this change to the master branch isn't urgent. --- docs/Compile.rst | 37 +++++++++---------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 4cea7713b..ac324a9f7 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -219,41 +219,22 @@ DFHack functions similarly on OS X and Linux, and the majority of the information above regarding the build process (cmake and make) applies here as well. -DFHack can officially be built on OS X with anything from GCC 4.5 to 4.8, so 4.8 -is recommended, as 4.5 has issues on newer systems, but 4.5-4.7 should also -work. Anything newer than 4.8 will require you to perform extra steps to get -DFHack to run (see `osx-new-gcc-notes`), and your build will likely not be -redistributable. +DFHack can officially be built on OS X with GCC 4.8. Anything newer than 4.8 +will require you to perform extra steps to get DFHack to run (see `osx-new-gcc-notes`), +and your build will likely not be redistributable. .. _osx-new-gcc-notes: -Notes for GCC 4.9+, OS X 10.10+, or XCode 7 users -------------------------------------------------- +Notes for GCC 4.9+ or OS X 10.10+ users +--------------------------------------- If none of these situations apply to you, skip to `osx-setup`. -If you have issues building on OS X 10.10 (Yosemite) or above, try definining the -following environment variable:: +If you have issues building on OS X 10.10 (Yosemite) or above, try definining +the following environment variable:: export MACOSX_DEPLOYMENT_TARGET=10.9 - -If you try to build with GCC 4.5, you will probably find that GCC 4.5 will fail -to install on OS X 10.11 and newer, or any older OS X that is using XCode 7 or -newer. There are two workarounds: - -* Install a newer version of GCC instead (e.g. ``brew install gcc48`` or ``brew - install gcc5``) and follow the instructions for linking libstdc++ below. - -* Install XCode 6, which is available as a free download from the Apple - Developer Center. - - * Either install this as your only XCode, or install it additionally - to XCode 7 and then switch between them using ``xcode-select`` - * Ensure XCode 6 is active before attempting to install GCC 4.5 and - whenever you are compiling DFHack with GCC 4.5. - - If you build with a GCC version newer than 4.8, DFHack will probably crash immediately on startup, or soon after. To fix this, you will need to replace ``hack/libstdc++.6.dylib`` with a symlink to the ``libstdc++.6.dylib`` included @@ -271,7 +252,7 @@ For example, with GCC 5.2.0, ``PATH_TO_LIBSTDC++`` would be:: build will *not* be redistributable. (Even if you copy the ``libstdc++.6.dylib`` from your GCC version and distribute that too, it will fail on older OS X versions.) For this reason, if you plan on distributing DFHack, it is highly -recommended to use GCC 4.5-4.8. +recommended to use GCC 4.8. .. _osx-setup: @@ -298,7 +279,7 @@ Dependencies and system set-up brew tap homebrew/versions brew install git brew install cmake - brew install gcc48 + brew install gcc@4.8 Using `MacPorts `_:: From f0d4a1f563b81e9a3c6a85b9467eaf01ad9335d0 Mon Sep 17 00:00:00 2001 From: Ben Rosser Date: Fri, 20 Jan 2017 17:16:19 -0500 Subject: [PATCH 308/413] Add DOWNLOAD_RUBY option to Ruby plugin cmake, defaulting to ON If DOWNLOAD_RUBY is set to OFF, the build will not attempt to download a prebuilt libruby.so and not fire a warning that one is not present. This may be desired if one wants to link dfhack against a newer system libruby.so, now that dfhack supports ruby 2.x and also supports linking against system libruby (at least, on Linux), as per the following commit: https://github.com/DFHack/dfhack/commit/df9b5bca7311489748ab100dfc51080841c3f196 This also allows the dfhack build to proceed without network access (once all submodules have been fetched), which at least some Linux distributions, like Fedora, require. By default DOWNLOAD_RUBY is set to ON, so this should not change the behavior of default builds. I tested that when DOWNLOAD_RUBY is set to OFF, dfhack still launches and that the Ruby plugin still functions, e.g. by running ```rb_eval puts('Hello world.')``` in the dfhack console. --- plugins/ruby/CMakeLists.txt | 104 +++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/plugins/ruby/CMakeLists.txt b/plugins/ruby/CMakeLists.txt index 6b5e62c66..f1ef12ac5 100644 --- a/plugins/ruby/CMakeLists.txt +++ b/plugins/ruby/CMakeLists.txt @@ -1,52 +1,59 @@ -IF (APPLE) - SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/osx${DFHACK_BUILD_ARCH}/libruby.dylib) - SET(RUBYLIB_INSTALL_NAME "libruby.dylib") - IF(${DFHACK_BUILD_ARCH} STREQUAL 64) - # MESSAGE("No ruby lib for 64-bit OS X yet") - ELSE() - DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/osx32-libruby187.dylib.gz" - "gz" - ${RUBYLIB}.gz - "e9bc4263557e652121b055a46abb4f97" - ${RUBYLIB} - "3ee5356759f764a440be5b5b44649826") - ENDIF() -ELSEIF(UNIX) - SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/linux${DFHACK_BUILD_ARCH}/libruby.so) - SET(RUBYLIB_INSTALL_NAME "libruby.so") - IF(${DFHACK_BUILD_ARCH} STREQUAL 64) - DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/linux64-libruby187.so.gz" - "gz" - ${RUBYLIB}.gz - "8eb757bb9ada08608914d8ca8906c427" - ${RUBYLIB} - "e8c36a06f031cfbf02def28169bb5f1f") - ELSE() - DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/linux32-libruby187.so.gz" - "gz" - ${RUBYLIB}.gz - "2d06f5069ff07ea934ecd40db55a4ac5" - ${RUBYLIB} - "b00d8d7086cb39f6fde793f9d89cb2d7") - ENDIF() -ELSE() - SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/win${DFHACK_BUILD_ARCH}/libruby.dll) - SET(RUBYLIB_INSTALL_NAME "libruby.dll") - IF(${DFHACK_BUILD_ARCH} STREQUAL 64) - DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win64-libruby200.dll.gz" - "gz" - ${RUBYLIB}.gz - "81db54a8b8b3090c94c6ae2147d30b8f" - ${RUBYLIB} - "8a8564418aebddef3dfee1e96690e713") +# Allow build system to turn off downloading of libruby.so. +OPTION(DOWNLOAD_RUBY "Download prebuilt libruby.so for ruby plugin." ON) + +IF (DOWNLOAD_RUBY) + + IF (APPLE) + SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/osx${DFHACK_BUILD_ARCH}/libruby.dylib) + SET(RUBYLIB_INSTALL_NAME "libruby.dylib") + IF(${DFHACK_BUILD_ARCH} STREQUAL 64) + # MESSAGE("No ruby lib for 64-bit OS X yet") + ELSE() + DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/osx32-libruby187.dylib.gz" + "gz" + ${RUBYLIB}.gz + "e9bc4263557e652121b055a46abb4f97" + ${RUBYLIB} + "3ee5356759f764a440be5b5b44649826") + ENDIF() + ELSEIF(UNIX) + SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/linux${DFHACK_BUILD_ARCH}/libruby.so) + SET(RUBYLIB_INSTALL_NAME "libruby.so") + IF(${DFHACK_BUILD_ARCH} STREQUAL 64) + DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/linux64-libruby187.so.gz" + "gz" + ${RUBYLIB}.gz + "8eb757bb9ada08608914d8ca8906c427" + ${RUBYLIB} + "e8c36a06f031cfbf02def28169bb5f1f") + ELSE() + DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/linux32-libruby187.so.gz" + "gz" + ${RUBYLIB}.gz + "2d06f5069ff07ea934ecd40db55a4ac5" + ${RUBYLIB} + "b00d8d7086cb39f6fde793f9d89cb2d7") + ENDIF() ELSE() - DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-libruby187.dll.gz" - "gz" - ${RUBYLIB}.gz - "ffc0f1b5b33748e2a36128e90c97f6b2" - ${RUBYLIB} - "482c1c418f4ee1a5f04203eee1cda0ef") + SET(RUBYLIB ${CMAKE_CURRENT_SOURCE_DIR}/win${DFHACK_BUILD_ARCH}/libruby.dll) + SET(RUBYLIB_INSTALL_NAME "libruby.dll") + IF(${DFHACK_BUILD_ARCH} STREQUAL 64) + DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win64-libruby200.dll.gz" + "gz" + ${RUBYLIB}.gz + "81db54a8b8b3090c94c6ae2147d30b8f" + ${RUBYLIB} + "8a8564418aebddef3dfee1e96690e713") + ELSE() + DOWNLOAD_FILE_UNZIP("https://github.com/DFHack/dfhack-bin/releases/download/0.43.05/win32-libruby187.dll.gz" + "gz" + ${RUBYLIB}.gz + "ffc0f1b5b33748e2a36128e90c97f6b2" + ${RUBYLIB} + "482c1c418f4ee1a5f04203eee1cda0ef") + ENDIF() ENDIF() + ENDIF() IF (APPLE OR UNIX) @@ -73,7 +80,8 @@ ADD_DEPENDENCIES(ruby ruby-autogen-rb) IF(EXISTS ${RUBYLIB}) INSTALL(FILES ${RUBYLIB} DESTINATION ${DFHACK_LIBRARY_DESTINATION} RENAME ${RUBYLIB_INSTALL_NAME}) ELSE() - IF(NOT(APPLE AND ${DFHACK_BUILD_ARCH} STREQUAL 64)) + # Only fire this warning if DOWNLOAD_RUBY was set. + IF(NOT(APPLE AND ${DFHACK_BUILD_ARCH} STREQUAL 64) AND DOWNLOAD_RUBY) MESSAGE(WARNING "Ruby library not found at ${RUBYLIB} - will not be installed") ENDIF() ENDIF() From cc02ced0ac854ce60d3320b426af4fa9b97d5629 Mon Sep 17 00:00:00 2001 From: Quietust Date: Sat, 21 Jan 2017 15:16:06 -0600 Subject: [PATCH 309/413] Fix RTTI in Win64 - offsets are relative to the current module (e.g. the DLL), so it needs to be looked up explicitly --- library/Process-windows.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/Process-windows.cpp b/library/Process-windows.cpp index cb2e16bd2..3a1da0ac4 100644 --- a/library/Process-windows.cpp +++ b/library/Process-windows.cpp @@ -342,12 +342,14 @@ int Process::adjustOffset(int offset, bool to_file) return -1; } - string Process::doReadClassName (void * vptr) { char * rtti = readPtr((char *)vptr - sizeof(void*)); #ifdef DFHACK64 - char * typeinfo = d->base + readDWord(rtti + 0xC); + void *base; + if (!RtlPcToFileHeader(rtti, &base)) + return "dummy"; + char * typeinfo = (char *)base + readDWord(rtti + 0xC); string raw = readCString(typeinfo + 0x10+4); // skips the .?AV #else char * typeinfo = readPtr(rtti + 0xC); From c659b885b6ab5d6e71a0e5650b7882f99066445e Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 25 Jan 2017 23:06:03 +0530 Subject: [PATCH 310/413] Start a plugin to rename generated creatures to have sensible IDs --- plugins/CMakeLists.txt | 1 + plugins/generated-creature-renamer.cpp | 79 ++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 plugins/generated-creature-renamer.cpp diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 4611009c3..6b1f80634 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -122,6 +122,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(follow follow.cpp) DFHACK_PLUGIN(forceequip forceequip.cpp) DFHACK_PLUGIN(fortplan fortplan.cpp LINK_LIBRARIES buildingplan-lib) + DFHACK_PLUGIN(generated-creature-renamer generated-creature-renamer.cpp) DFHACK_PLUGIN(getplants getplants.cpp) DFHACK_PLUGIN(hotkeys hotkeys.cpp) DFHACK_PLUGIN(infiniteSky infiniteSky.cpp) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp new file mode 100644 index 000000000..8c2fe20ef --- /dev/null +++ b/plugins/generated-creature-renamer.cpp @@ -0,0 +1,79 @@ +#include "Console.h" +#include "Core.h" +#include "DataDefs.h" +#include "Export.h" +#include "PluginManager.h" +#include "df/world.h" +#include "df/world_raws.h" +#include "df/creature_raw.h" +#include "df/caste_raw.h" + +//#include "df/world.h" + +using namespace DFHack; + +DFHACK_PLUGIN("rename_creatures"); +REQUIRE_GLOBAL(world); + +command_result rename_creatures (color_ostream &out, std::vector & parameters); + +DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) +{ + commands.push_back(PluginCommand( + "rename_creatures", + "Renames generated creature tags to something friendlier to modders", + rename_creatures, + false, //allow non-interactive use + "longHelpString" + )); + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown (color_ostream &out) +{ + return CR_OK; +} + +std::string descriptors[] = { "blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", +"damselfly", "stonefly", "earwig", "grasshopper", "cricket", "stick insect", "cockroach", "termite", +"mantis", "louse", "thrips", "aphid", "cicada", "assassin bug", "wasp", "hornet", "tiger beetle", +"ladybug", "weevil", "darkling beetle", "click beetle", "firefly", "scarab beetle", "stag beetle", +"dung beetle", "rhinoceros beetle", "rove beetle", "snakefly", "lacewing", "antlion larva", +"mosquito", "flea", "scorpionfly", "caddisfly", "butterfly", "moth", "caterpillar", "maggot", +"spider", "tarantula", "scorpion", "tick", "mite", "shrimp", "lobster", "crab", "nematode", +"snail", "slug", "earthworm", "leech", "bristleworm", "ribbon worm", "flat worm", "toad", "frog", +"salamander", "newt", "alligator", "crocodile", "lizard", "chameleon", "iguana", "gecko", "skink", +"gila monster", "monitor", "serpent", "viper", "rattlesnake", "cobra", "python", "anaconda", "turtle", +"tortoise", "pterosaur", "dimetrodon", "sauropod", "theropod", "iguanodont", "hadrosaurid", "stegosaurid", +"ceratopsid", "ankylosaurid", "duck", "goose", "swan", "turkey", "grouse", "chicken", "quail", "pheasant", +"gull", "loon", "grebe", "albatross", "petrel", "penguin", "pelican", "stork", "vulture", "flamingo", +"falcon", "kestrel", "condor", "osprey", "buzzard", "eagle", "harrier", "kite", "crane", "dove", +"pigeon", "parrot", "cockatoo", "cuckoo", "nightjar", "swift", "hummingbird", "kingfisher", +"hornbill", "quetzal", "toucan", "woodpecker", "lyrebird", "thornbill", "honeyeater", "oriole", +"fantail", "shrike", "crow", "raven", "magpie", "kinglet", "lark", "swallow", "martin", "bushtit", +"warbler", "thrush", "oxpecker", "starling", "mockingbird", "wren", "nuthatch", "sparrow", "tanager", +"cardinal", "bunting", "finch", "titmouse", "chickadee", "waxwing", "flycatcher", "opossum", "koala", +"wombat", "kangaroo", "sloth", "anteater", "armadillo", "squirrel", "marmot", "beaver", "gopher", +"mouse", "porcupine", "chinchilla", "cavy", "capybara", "rabbit", "hare", "lemur", "loris", "monkey", +"hedgehog", "shrew", "mole", "fruit bat", "wolf", "coyote", "jackal", "raccoon", "coati", +"weasel", "otter", "badger", "skunk", "bear", "panda", "panther", "mongoose", "hyena", "civet", +"walrus", "pangolin", "elephant", "mammoth", "horse", "zebra", "tapir", "rhinoceros", "warthog", +"hippopotamus", "camel", "llama", "giraffe", "deer", "moose", "antelope", "sheep", "goat", +"bison", "buffalo", "bull" }; + +command_result rename_creatures (color_ostream &out, std::vector & parameters) +{ + if (!parameters.empty()) + return CR_WRONG_USAGE; + CoreSuspender suspend; + for (int i = 0; i < world->raws.creatures.all.size(); i++) + { + auto creatureRaw = world->raws.creatures.all[i]; + if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED)) + continue; + out.print(creatureRaw->creature_id.c_str()); + out.print(creatureRaw->caste[0]->description.c_str()); + } + return CR_OK; +} + From 934d5b32bce6f880d9e3ff4b2f1bbc134421c5bb Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 26 Jan 2017 10:00:38 +0530 Subject: [PATCH 311/413] Fix creature listing and plugin name --- plugins/generated-creature-renamer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 8c2fe20ef..81816d061 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -12,7 +12,7 @@ using namespace DFHack; -DFHACK_PLUGIN("rename_creatures"); +DFHACK_PLUGIN("generated-creature-renamer"); REQUIRE_GLOBAL(world); command_result rename_creatures (color_ostream &out, std::vector & parameters); @@ -72,7 +72,9 @@ command_result rename_creatures (color_ostream &out, std::vector & if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED)) continue; out.print(creatureRaw->creature_id.c_str()); + out.print("\n"); out.print(creatureRaw->caste[0]->description.c_str()); + out.print("\n"); } return CR_OK; } From 365624453e3ee0f6b9e953ff15a523fe902a900f Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Thu, 26 Jan 2017 12:45:40 +0530 Subject: [PATCH 312/413] Finish up the generated-creature-renamer plugin. --- plugins/generated-creature-renamer.cpp | 93 +++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 81816d061..c6c7cdfec 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -7,6 +7,7 @@ #include "df/world_raws.h" #include "df/creature_raw.h" #include "df/caste_raw.h" +#include "modules/World.h" //#include "df/world.h" @@ -15,26 +16,34 @@ using namespace DFHack; DFHACK_PLUGIN("generated-creature-renamer"); REQUIRE_GLOBAL(world); -command_result rename_creatures (color_ostream &out, std::vector & parameters); +command_result rename_creatures(color_ostream &out, std::vector & parameters); +command_result list_creatures(color_ostream &out, std::vector & parameters); -DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) +DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( - "rename_creatures", + "rename-generated", "Renames generated creature tags to something friendlier to modders", rename_creatures, false, //allow non-interactive use - "longHelpString" + "Renames generated creature tags to something friendlier to modders" + )); + commands.push_back(PluginCommand( + "list-generated", + "Prints a list of generated creature tokens. Use \"list-generated detailed\" to show descriptions.", + list_creatures, + false, //allow non-interactive use + "Prints a list of generated creature tokens. Use \"list-generated detailed\" to show descriptions." )); return CR_OK; } -DFhackCExport command_result plugin_shutdown (color_ostream &out) +DFhackCExport command_result plugin_shutdown(color_ostream &out) { return CR_OK; } -std::string descriptors[] = { "blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", +std::string descriptors[221] = { "blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", "damselfly", "stonefly", "earwig", "grasshopper", "cricket", "stick insect", "cockroach", "termite", "mantis", "louse", "thrips", "aphid", "cicada", "assassin bug", "wasp", "hornet", "tiger beetle", "ladybug", "weevil", "darkling beetle", "click beetle", "firefly", "scarab beetle", "stag beetle", @@ -48,7 +57,7 @@ std::string descriptors[] = { "blob", "quadruped", "humanoid", "silverfish", "ma "ceratopsid", "ankylosaurid", "duck", "goose", "swan", "turkey", "grouse", "chicken", "quail", "pheasant", "gull", "loon", "grebe", "albatross", "petrel", "penguin", "pelican", "stork", "vulture", "flamingo", "falcon", "kestrel", "condor", "osprey", "buzzard", "eagle", "harrier", "kite", "crane", "dove", -"pigeon", "parrot", "cockatoo", "cuckoo", "nightjar", "swift", "hummingbird", "kingfisher", +"pigeon", "parrot", "cockatoo", "cuckoo", "nightjar", "swift", "hummingbird", "kingfisher", "hornbill", "quetzal", "toucan", "woodpecker", "lyrebird", "thornbill", "honeyeater", "oriole", "fantail", "shrike", "crow", "raven", "magpie", "kinglet", "lark", "swallow", "martin", "bushtit", "warbler", "thrush", "oxpecker", "starling", "mockingbird", "wren", "nuthatch", "sparrow", "tanager", @@ -61,21 +70,83 @@ std::string descriptors[] = { "blob", "quadruped", "humanoid", "silverfish", "ma "hippopotamus", "camel", "llama", "giraffe", "deer", "moose", "antelope", "sheep", "goat", "bison", "buffalo", "bull" }; -command_result rename_creatures (color_ostream &out, std::vector & parameters) +command_result rename_creatures(color_ostream &out, std::vector & parameters) { if (!parameters.empty()) return CR_WRONG_USAGE; CoreSuspender suspend; + + int descriptorCount[221] = { 0 }; + + if (World::GetPersistentData("AlreadyRenamedCreatures").isValid()) + { + return CR_OK; + } + + for (int i = 0; i < world->raws.creatures.all.size(); i++) + { + auto creatureRaw = world->raws.creatures.all[i]; + if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED)) + continue; + size_t minPos = std::string::npos; + size_t foundIndex = std::string::npos; + + for (size_t j = 0; j < 221; j++) + { + size_t pos = creatureRaw->caste[0]->description.find(descriptors[j]); + if (pos < minPos) + { + minPos = pos; + foundIndex = j; + } + } + + if (foundIndex < std::string::npos) + { + size_t digitPos = creatureRaw->creature_id.find_first_of("0123456789"); + if (digitPos > creatureRaw->creature_id.length()) + digitPos = creatureRaw->creature_id.length(); + + creatureRaw->creature_id.replace(digitPos, std::string::npos, descriptors[foundIndex]); + + if (descriptorCount[foundIndex] > 0) + { + creatureRaw->creature_id.append(std::to_string(descriptorCount[foundIndex])); + } + + descriptorCount[foundIndex]++; + } + } + World::AddPersistentData("AlreadyRenamedCreatures"); + + return CR_OK; +} + +command_result list_creatures(color_ostream &out, std::vector & parameters) +{ + bool detailed = false; + if (!parameters.empty()) + { + if (parameters.size() > 1) + return CR_WRONG_USAGE; + if(parameters[0].compare("detailed") != 0) + return CR_WRONG_USAGE; + detailed = true; + } + + CoreSuspender suspend; for (int i = 0; i < world->raws.creatures.all.size(); i++) { auto creatureRaw = world->raws.creatures.all[i]; if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED)) continue; out.print(creatureRaw->creature_id.c_str()); - out.print("\n"); - out.print(creatureRaw->caste[0]->description.c_str()); + if (detailed) + { + out.print("\t"); + out.print(creatureRaw->caste[0]->description.c_str()); + } out.print("\n"); } - return CR_OK; } From 24a653f77be87aa83a8efece28245e282c7b73a8 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Thu, 26 Jan 2017 12:50:37 +0530 Subject: [PATCH 313/413] added ants and apes to the list. --- plugins/generated-creature-renamer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index c6c7cdfec..20e861c83 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -43,7 +43,8 @@ DFhackCExport command_result plugin_shutdown(color_ostream &out) return CR_OK; } -std::string descriptors[221] = { "blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", +#define NUM_DESC 223 +std::string descriptors[NUM_DESC] = { "blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", "damselfly", "stonefly", "earwig", "grasshopper", "cricket", "stick insect", "cockroach", "termite", "mantis", "louse", "thrips", "aphid", "cicada", "assassin bug", "wasp", "hornet", "tiger beetle", "ladybug", "weevil", "darkling beetle", "click beetle", "firefly", "scarab beetle", "stag beetle", @@ -68,7 +69,7 @@ std::string descriptors[221] = { "blob", "quadruped", "humanoid", "silverfish", "weasel", "otter", "badger", "skunk", "bear", "panda", "panther", "mongoose", "hyena", "civet", "walrus", "pangolin", "elephant", "mammoth", "horse", "zebra", "tapir", "rhinoceros", "warthog", "hippopotamus", "camel", "llama", "giraffe", "deer", "moose", "antelope", "sheep", "goat", -"bison", "buffalo", "bull" }; +"bison", "buffalo", "bull", "ape", "ant" }; command_result rename_creatures(color_ostream &out, std::vector & parameters) { @@ -76,7 +77,7 @@ command_result rename_creatures(color_ostream &out, std::vector & return CR_WRONG_USAGE; CoreSuspender suspend; - int descriptorCount[221] = { 0 }; + int descriptorCount[NUM_DESC] = { 0 }; if (World::GetPersistentData("AlreadyRenamedCreatures").isValid()) { @@ -91,7 +92,7 @@ command_result rename_creatures(color_ostream &out, std::vector & size_t minPos = std::string::npos; size_t foundIndex = std::string::npos; - for (size_t j = 0; j < 221; j++) + for (size_t j = 0; j < NUM_DESC; j++) { size_t pos = creatureRaw->caste[0]->description.find(descriptors[j]); if (pos < minPos) From c3c3f37b0660d301a6008d85ef3a6db9247b2030 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Thu, 26 Jan 2017 15:58:43 +0530 Subject: [PATCH 314/413] Added more descriptor types, and made it run on world load. --- dfhack.init-example | 3 + plugins/generated-creature-renamer.cpp | 144 +++++++++++++------------ 2 files changed, 78 insertions(+), 69 deletions(-) diff --git a/dfhack.init-example b/dfhack.init-example index 169d40046..a0dd220e1 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -233,6 +233,9 @@ enable \ # enable mouse controls and sand indicator in embark screen embark-tools enable sticky sand mouse +# Renames generated creatures to reflect the template used to generate them. +enable generated-creature-renamer + ########### # Scripts # ########### diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 20e861c83..1a738cce4 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -16,18 +16,10 @@ using namespace DFHack; DFHACK_PLUGIN("generated-creature-renamer"); REQUIRE_GLOBAL(world); -command_result rename_creatures(color_ostream &out, std::vector & parameters); command_result list_creatures(color_ostream &out, std::vector & parameters); DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand( - "rename-generated", - "Renames generated creature tags to something friendlier to modders", - rename_creatures, - false, //allow non-interactive use - "Renames generated creature tags to something friendlier to modders" - )); commands.push_back(PluginCommand( "list-generated", "Prints a list of generated creature tokens. Use \"list-generated detailed\" to show descriptions.", @@ -43,82 +35,96 @@ DFhackCExport command_result plugin_shutdown(color_ostream &out) return CR_OK; } -#define NUM_DESC 223 -std::string descriptors[NUM_DESC] = { "blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", -"damselfly", "stonefly", "earwig", "grasshopper", "cricket", "stick insect", "cockroach", "termite", -"mantis", "louse", "thrips", "aphid", "cicada", "assassin bug", "wasp", "hornet", "tiger beetle", -"ladybug", "weevil", "darkling beetle", "click beetle", "firefly", "scarab beetle", "stag beetle", -"dung beetle", "rhinoceros beetle", "rove beetle", "snakefly", "lacewing", "antlion larva", -"mosquito", "flea", "scorpionfly", "caddisfly", "butterfly", "moth", "caterpillar", "maggot", -"spider", "tarantula", "scorpion", "tick", "mite", "shrimp", "lobster", "crab", "nematode", -"snail", "slug", "earthworm", "leech", "bristleworm", "ribbon worm", "flat worm", "toad", "frog", -"salamander", "newt", "alligator", "crocodile", "lizard", "chameleon", "iguana", "gecko", "skink", -"gila monster", "monitor", "serpent", "viper", "rattlesnake", "cobra", "python", "anaconda", "turtle", -"tortoise", "pterosaur", "dimetrodon", "sauropod", "theropod", "iguanodont", "hadrosaurid", "stegosaurid", -"ceratopsid", "ankylosaurid", "duck", "goose", "swan", "turkey", "grouse", "chicken", "quail", "pheasant", -"gull", "loon", "grebe", "albatross", "petrel", "penguin", "pelican", "stork", "vulture", "flamingo", -"falcon", "kestrel", "condor", "osprey", "buzzard", "eagle", "harrier", "kite", "crane", "dove", -"pigeon", "parrot", "cockatoo", "cuckoo", "nightjar", "swift", "hummingbird", "kingfisher", -"hornbill", "quetzal", "toucan", "woodpecker", "lyrebird", "thornbill", "honeyeater", "oriole", -"fantail", "shrike", "crow", "raven", "magpie", "kinglet", "lark", "swallow", "martin", "bushtit", -"warbler", "thrush", "oxpecker", "starling", "mockingbird", "wren", "nuthatch", "sparrow", "tanager", -"cardinal", "bunting", "finch", "titmouse", "chickadee", "waxwing", "flycatcher", "opossum", "koala", -"wombat", "kangaroo", "sloth", "anteater", "armadillo", "squirrel", "marmot", "beaver", "gopher", -"mouse", "porcupine", "chinchilla", "cavy", "capybara", "rabbit", "hare", "lemur", "loris", "monkey", -"hedgehog", "shrew", "mole", "fruit bat", "wolf", "coyote", "jackal", "raccoon", "coati", -"weasel", "otter", "badger", "skunk", "bear", "panda", "panther", "mongoose", "hyena", "civet", -"walrus", "pangolin", "elephant", "mammoth", "horse", "zebra", "tapir", "rhinoceros", "warthog", -"hippopotamus", "camel", "llama", "giraffe", "deer", "moose", "antelope", "sheep", "goat", -"bison", "buffalo", "bull", "ape", "ant" }; - -command_result rename_creatures(color_ostream &out, std::vector & parameters) -{ - if (!parameters.empty()) - return CR_WRONG_USAGE; - CoreSuspender suspend; +DFHACK_PLUGIN_IS_ENABLED(is_enabled); - int descriptorCount[NUM_DESC] = { 0 }; +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) +{ + is_enabled = enable; + return CR_OK; +} - if (World::GetPersistentData("AlreadyRenamedCreatures").isValid()) - { +#define NUM_DESC 227 +std::string descriptors[NUM_DESC] = { " blob", " quadruped", " humanoid", " silverfish", " mayfly", " dragonfly", +" damselfly", " stonefly", " earwig", " grasshopper", " cricket", " stick insect", " cockroach", " termite", +" mantis", " louse", " thrips", " aphid", " cicada", " assassin bug", " wasp", " hornet", " tiger beetle", +" ladybug", " weevil", " darkling beetle", " click beetle", " firefly", " scarab beetle", " stag beetle", +" dung beetle", " rhinoceros beetle", " rove beetle", " snakefly", " lacewing", " antlion larva", +" mosquito", " flea", " scorpionfly", " caddisfly", " butterfly", " moth", " caterpillar", " maggot", +" spider", " tarantula", " scorpion", " tick", " mite", " shrimp", " lobster", " crab", " nematode", +" snail", " slug", " earthworm", " leech", " bristleworm", " ribbon worm", " flat worm", " toad", " frog", +" salamander", " newt", " alligator", " crocodile", " lizard", " chameleon", " iguana", " gecko", " skink", +" gila monster", " monitor", " serpent", " viper", " rattlesnake", " cobra", " python", " anaconda", " turtle", +" tortoise", " pterosaur", " dimetrodon", " sauropod", " theropod", " iguanodont", " hadrosaurid", " stegosaurid", +" ceratopsid", " ankylosaurid", " duck", " goose", " swan", " turkey", " grouse", " chicken", " quail", " pheasant", +" gull", " loon", " grebe", " albatross", " petrel", " penguin", " pelican", " stork", " vulture", " flamingo", +" falcon", " kestrel", " condor", " osprey", " buzzard", " eagle", " harrier", " kite", " crane", " dove", +" pigeon", " parrot", " cockatoo", " cuckoo", " nightjar", " swift", " hummingbird", " kingfisher", +" hornbill", " quetzal", " toucan", " woodpecker", " lyrebird", " thornbill", " honeyeater", " oriole", +" fantail", " shrike", " crow", " raven", " magpie", " kinglet", " lark", " swallow", " martin", " bushtit", +" warbler", " thrush", " oxpecker", " starling", " mockingbird", " wren", " nuthatch", " sparrow", " tanager", +" cardinal", " bunting", " finch", " titmouse", " chickadee", " waxwing", " flycatcher", " opossum", " koala", +" wombat", " kangaroo", " sloth", " anteater", " armadillo", " squirrel", " marmot", " beaver", " gopher", +" mouse", " porcupine", " chinchilla", " cavy", " capybara", " rabbit", " hare", " lemur", " loris", " monkey", +" hedgehog", " shrew", " mole", " fruit bat", " wolf", " coyote", " jackal", " raccoon", " coati", +" weasel", " otter", " badger", " skunk", " bear", " panda", " panther", " mongoose", " hyena", " civet", +" walrus", " pangolin", " elephant", " mammoth", " horse", " zebra", " tapir", " rhinoceros", " warthog", +" hippopotamus", " camel", " llama", " giraffe", " deer", " moose", " antelope", " sheep", " goat", +" bison", " buffalo", " bull", " ape", " ant", " bat", " owl", " pig", " bee" }; + + +DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) +{ + if (!is_enabled) return CR_OK; - } - - for (int i = 0; i < world->raws.creatures.all.size(); i++) + switch (event) { - auto creatureRaw = world->raws.creatures.all[i]; - if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED)) - continue; - size_t minPos = std::string::npos; - size_t foundIndex = std::string::npos; + case DFHack::SC_WORLD_LOADED: + CoreSuspender suspend; - for (size_t j = 0; j < NUM_DESC; j++) + int descriptorCount[NUM_DESC] = { 0 }; + + if (World::GetPersistentData("AlreadyRenamedCreatures").isValid()) { - size_t pos = creatureRaw->caste[0]->description.find(descriptors[j]); - if (pos < minPos) - { - minPos = pos; - foundIndex = j; - } + return CR_OK; } - if (foundIndex < std::string::npos) + for (int i = 0; i < world->raws.creatures.all.size(); i++) { - size_t digitPos = creatureRaw->creature_id.find_first_of("0123456789"); - if (digitPos > creatureRaw->creature_id.length()) - digitPos = creatureRaw->creature_id.length(); + auto creatureRaw = world->raws.creatures.all[i]; + if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED)) + continue; + size_t minPos = std::string::npos; + size_t foundIndex = std::string::npos; - creatureRaw->creature_id.replace(digitPos, std::string::npos, descriptors[foundIndex]); - - if (descriptorCount[foundIndex] > 0) + for (size_t j = 0; j < NUM_DESC; j++) { - creatureRaw->creature_id.append(std::to_string(descriptorCount[foundIndex])); + size_t pos = creatureRaw->caste[0]->description.find(descriptors[j]); + if (pos < minPos) + { + minPos = pos; + foundIndex = j; + } } - descriptorCount[foundIndex]++; + if (foundIndex < std::string::npos) + { + size_t digitPos = creatureRaw->creature_id.find_first_of("0123456789"); + if (digitPos > creatureRaw->creature_id.length()) + digitPos = creatureRaw->creature_id.length(); + + creatureRaw->creature_id.replace(digitPos, std::string::npos, descriptors[foundIndex], 1, std::string::npos); + + if (descriptorCount[foundIndex] > 0) + { + creatureRaw->creature_id.append(std::to_string(descriptorCount[foundIndex])); + } + + descriptorCount[foundIndex]++; + } } + World::AddPersistentData("AlreadyRenamedCreatures"); + break; } - World::AddPersistentData("AlreadyRenamedCreatures"); return CR_OK; } From d97b0497b354927bc4f1ed79c52c9cf1d1dba002 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Thu, 2 Feb 2017 12:12:28 +0530 Subject: [PATCH 315/413] Add prosession and noble position info to units. --- plugins/proto/RemoteFortressReader.proto | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index c0ed000c7..fdfc25d99 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -322,6 +322,8 @@ message UnitDefinition optional int32 blood_max = 14; optional int32 blood_count = 15; optional UnitAppearance appearance = 16; + optional int32 profession_id = 17; + repeated string noble_positions = 18; } message UnitList From c8e6845a7fceec83cfc0d69928762c43e1673d5a Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Fri, 3 Feb 2017 10:08:35 +0530 Subject: [PATCH 316/413] Send noble positions and professions along with Units. --- .../remotefortressreader/remotefortressreader.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index d1803dc0b..3ebd2ea35 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -96,6 +96,7 @@ #include "df/world_region_details.h" #include "df/world_site.h" #include "df/world_site_realization.h" +#include "df/entity_position.h" #if DF_VERSION > 40001 #include "df/plant_growth.h" @@ -1800,6 +1801,19 @@ static command_result GetUnitList(color_ostream &stream, const EmptyMessage *in, for (int j = 0; j < unit->appearance.colors.size(); j++) appearance->add_colors(unit->appearance.colors[j]); appearance->set_size_modifier(unit->appearance.size_modifier); + + send_unit->set_profession_id(unit->profession); + + std::vector pvec; + + if (Units::getNoblePositions(&pvec, unit)) + { + for (int j = 0; j < pvec.size(); j++) + { + auto noble_positon = pvec[j]; + send_unit->add_noble_positions(noble_positon.position->code); + } + } } return CR_OK; } From f65a9810996d9d20d2423ab534cb04c495c905d5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 4 Feb 2017 14:46:38 -0500 Subject: [PATCH 317/413] Fix indentation --- plugins/proto/RemoteFortressReader.proto | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index fdfc25d99..af25c9a4b 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -322,8 +322,8 @@ message UnitDefinition optional int32 blood_max = 14; optional int32 blood_count = 15; optional UnitAppearance appearance = 16; - optional int32 profession_id = 17; - repeated string noble_positions = 18; + optional int32 profession_id = 17; + repeated string noble_positions = 18; } message UnitList @@ -756,4 +756,4 @@ message DigCommand message SingleBool { optional bool Value = 1; -} \ No newline at end of file +} From a8f48331886d2f2327fddb1c88a8e04ef54d2979 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 4 Feb 2017 14:49:09 -0500 Subject: [PATCH 318/413] internal_memscan: add extra check --- library/LuaApi.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index b8a6fe53d..39404e9be 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2557,6 +2557,9 @@ static int internal_memscan(lua_State *L) for (int i = 0; i <= hcount; i++) { uint8_t *p = haystack + i*hstep; + if (p + nsize > haystack + (hcount * hstep)) { + break; + } if (memcmp(p, needle, nsize) == 0) { lua_pushinteger(L, i); lua_pushinteger(L, (lua_Integer)p); From 7823d78cd91210ae1e648be038b6a92a6f658391 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 4 Feb 2017 14:49:21 -0500 Subject: [PATCH 319/413] Update xml and embark-tools field name --- library/xml | 2 +- plugins/embark-tools.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 34331ef67..fc2570c6c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 34331ef67f3d163f4ab66121449a8217eb1cfb47 +Subproject commit fc2570c6c0179fcdf48610f0e3eaef7f84908da7 diff --git a/plugins/embark-tools.cpp b/plugins/embark-tools.cpp index d2bdf4909..274f8cad7 100644 --- a/plugins/embark-tools.cpp +++ b/plugins/embark-tools.cpp @@ -128,7 +128,7 @@ public: if (input->count(df::interface_key::SETUP_EMBARK)) { cancel = true; - screen->in_embark_normal = 1; + screen->in_embark_only_warning = 1; } }; }; From 34988e53b9022e27c1f4412f403b57b987561270 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 5 Feb 2017 22:03:06 -0500 Subject: [PATCH 320/413] Update supported keys in keybinding help text --- library/Core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Core.cpp b/library/Core.cpp index 6afe907aa..b1bf67973 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1043,7 +1043,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v << " keybinding set [@context] \"cmdline\" \"cmdline\"..." << endl << " keybinding add [@context] \"cmdline\" \"cmdline\"..." << endl << "Later adds, and earlier items within one command have priority." << endl - << "Supported keys: [Ctrl-][Alt-][Shift-](A-Z, or F1-F9, or Enter)." << endl + << "Supported keys: [Ctrl-][Alt-][Shift-](A-Z, 0-9, F1-F12, or Enter)." << endl << "Context may be used to limit the scope of the binding, by" << endl << "requiring the current context to have a certain prefix." << endl << "Current UI context is: " From f2164d27c9d939407a4f814c1da2d5e39aceb72b Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 5 Feb 2017 22:11:35 -0500 Subject: [PATCH 321/413] ls: List scripts outside of hack/scripts Closes #412 --- library/Core.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index b1bf67973..642da61ea 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -279,19 +279,24 @@ static void listScripts(PluginManager *plug_mgr, std::map &pset, std::vector files; Filesystem::listdir(path, files); + path += '/'; for (size_t i = 0; i < files.size(); i++) { if (hasEnding(files[i], ".lua")) { - std::string help = getScriptHelp(path + files[i], "--"); - - pset[prefix + files[i].substr(0, files[i].size()-4)] = help; + string help = getScriptHelp(path + files[i], "--"); + string key = prefix + files[i].substr(0, files[i].size()-4); + if (pset.find(key) == pset.end()) { + pset[key] = help; + } } else if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() && hasEnding(files[i], ".rb")) { - std::string help = getScriptHelp(path + files[i], "#"); - - pset[prefix + files[i].substr(0, files[i].size()-3)] = help; + string help = getScriptHelp(path + files[i], "#"); + string key = prefix + files[i].substr(0, files[i].size()-3); + if (pset.find(key) == pset.end()) { + pset[key] = help; + } } else if (all && !files[i].empty() && files[i][0] != '.') { @@ -300,6 +305,14 @@ static void listScripts(PluginManager *plug_mgr, std::map &pset, } } +static void listAllScripts(map &pset, bool all) +{ + vector paths; + Core::getInstance().getScriptPaths(&paths); + for (string path : paths) + listScripts(Core::getInstance().getPluginManager(), pset, path, all); +} + namespace { struct ScriptArgs { const string *pcmd; @@ -418,7 +431,7 @@ static bool try_autocomplete(color_ostream &con, const std::string &first, std:: bool all = (first.find('/') != std::string::npos); std::map scripts; - listScripts(plug_mgr, scripts, Core::getInstance().getHackPath() + "scripts/", all); + listAllScripts(scripts, all); for (auto iter = scripts.begin(); iter != scripts.end(); ++iter) if (iter->first.substr(0, first.size()) == first) possible.push_back(iter->first); @@ -907,7 +920,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v con.reset_color(); } std::map scripts; - listScripts(plug_mgr, scripts, getHackPath() + "scripts/", all); + listAllScripts(scripts, all); if (!scripts.empty()) { con.print("\nscripts:\n"); From f94cc47be0ec9257ac9bd245590e9a7f6dc21b3f Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 5 Feb 2017 22:12:10 -0500 Subject: [PATCH 322/413] Update scripts (devel/find-offsets, season-palette) --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 20eb2146f..76ee1ec38 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 20eb2146fb93912b07034f3192dde1cf95a9ec7f +Subproject commit 76ee1ec38bf56fce0e48404520ce5e0ebe22702b From b18bd72c05db76d3a33742fec10488986a246cd2 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Mon, 6 Feb 2017 10:12:20 +0530 Subject: [PATCH 323/413] Replace tab with spaces. --- plugins/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 6b1f80634..f7586f03d 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -122,7 +122,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(follow follow.cpp) DFHACK_PLUGIN(forceequip forceequip.cpp) DFHACK_PLUGIN(fortplan fortplan.cpp LINK_LIBRARIES buildingplan-lib) - DFHACK_PLUGIN(generated-creature-renamer generated-creature-renamer.cpp) + DFHACK_PLUGIN(generated-creature-renamer generated-creature-renamer.cpp) DFHACK_PLUGIN(getplants getplants.cpp) DFHACK_PLUGIN(hotkeys hotkeys.cpp) DFHACK_PLUGIN(infiniteSky infiniteSky.cpp) From 6e75840d911f2f481ad498d13730deffa6a56418 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Mon, 6 Feb 2017 10:18:14 +0530 Subject: [PATCH 324/413] Don't start creature-renamer automatically. --- dfhack.init-example | 3 --- 1 file changed, 3 deletions(-) diff --git a/dfhack.init-example b/dfhack.init-example index a0dd220e1..169d40046 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -233,9 +233,6 @@ enable \ # enable mouse controls and sand indicator in embark screen embark-tools enable sticky sand mouse -# Renames generated creatures to reflect the template used to generate them. -enable generated-creature-renamer - ########### # Scripts # ########### From 1aef1d1b98f0b2e78a1bc519d0f952ea7472c51b Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Mon, 6 Feb 2017 10:42:10 +0530 Subject: [PATCH 325/413] use STD::Vector instead of a C array, and set version properly. --- plugins/generated-creature-renamer.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 1a738cce4..8f82f0e63 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -16,6 +16,8 @@ using namespace DFHack; DFHACK_PLUGIN("generated-creature-renamer"); REQUIRE_GLOBAL(world); +#define RENAMER_VERSION 1 + command_result list_creatures(color_ostream &out, std::vector & parameters); DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) @@ -43,8 +45,7 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) return CR_OK; } -#define NUM_DESC 227 -std::string descriptors[NUM_DESC] = { " blob", " quadruped", " humanoid", " silverfish", " mayfly", " dragonfly", +std::vector descriptors = { " blob", " quadruped", " humanoid", " silverfish", " mayfly", " dragonfly", " damselfly", " stonefly", " earwig", " grasshopper", " cricket", " stick insect", " cockroach", " termite", " mantis", " louse", " thrips", " aphid", " cicada", " assassin bug", " wasp", " hornet", " tiger beetle", " ladybug", " weevil", " darkling beetle", " click beetle", " firefly", " scarab beetle", " stag beetle", @@ -81,9 +82,10 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan case DFHack::SC_WORLD_LOADED: CoreSuspender suspend; - int descriptorCount[NUM_DESC] = { 0 }; + std::vector descriptorCount = std::vector(descriptors.size()); - if (World::GetPersistentData("AlreadyRenamedCreatures").isValid()) + auto version = World::GetPersistentData("AlreadyRenamedCreatures"); + if (version.isValid() && version.ival(1) >= RENAMER_VERSION) { return CR_OK; } @@ -96,7 +98,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan size_t minPos = std::string::npos; size_t foundIndex = std::string::npos; - for (size_t j = 0; j < NUM_DESC; j++) + for (size_t j = 0; j < descriptors.size(); j++) { size_t pos = creatureRaw->caste[0]->description.find(descriptors[j]); if (pos < minPos) @@ -122,7 +124,8 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan descriptorCount[foundIndex]++; } } - World::AddPersistentData("AlreadyRenamedCreatures"); + version = World::AddPersistentData("AlreadyRenamedCreatures"); + version.ival(1) = RENAMER_VERSION; break; } From 5b83c6fe685dc82dc35c228fea9014942949ff5d Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Mon, 6 Feb 2017 10:49:22 +0530 Subject: [PATCH 326/413] Add spaces to search string programmatically. --- plugins/generated-creature-renamer.cpp | 54 +++++++++++++------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 8f82f0e63..caace087a 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -45,32 +45,32 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) return CR_OK; } -std::vector descriptors = { " blob", " quadruped", " humanoid", " silverfish", " mayfly", " dragonfly", -" damselfly", " stonefly", " earwig", " grasshopper", " cricket", " stick insect", " cockroach", " termite", -" mantis", " louse", " thrips", " aphid", " cicada", " assassin bug", " wasp", " hornet", " tiger beetle", -" ladybug", " weevil", " darkling beetle", " click beetle", " firefly", " scarab beetle", " stag beetle", -" dung beetle", " rhinoceros beetle", " rove beetle", " snakefly", " lacewing", " antlion larva", -" mosquito", " flea", " scorpionfly", " caddisfly", " butterfly", " moth", " caterpillar", " maggot", -" spider", " tarantula", " scorpion", " tick", " mite", " shrimp", " lobster", " crab", " nematode", -" snail", " slug", " earthworm", " leech", " bristleworm", " ribbon worm", " flat worm", " toad", " frog", -" salamander", " newt", " alligator", " crocodile", " lizard", " chameleon", " iguana", " gecko", " skink", -" gila monster", " monitor", " serpent", " viper", " rattlesnake", " cobra", " python", " anaconda", " turtle", -" tortoise", " pterosaur", " dimetrodon", " sauropod", " theropod", " iguanodont", " hadrosaurid", " stegosaurid", -" ceratopsid", " ankylosaurid", " duck", " goose", " swan", " turkey", " grouse", " chicken", " quail", " pheasant", -" gull", " loon", " grebe", " albatross", " petrel", " penguin", " pelican", " stork", " vulture", " flamingo", -" falcon", " kestrel", " condor", " osprey", " buzzard", " eagle", " harrier", " kite", " crane", " dove", -" pigeon", " parrot", " cockatoo", " cuckoo", " nightjar", " swift", " hummingbird", " kingfisher", -" hornbill", " quetzal", " toucan", " woodpecker", " lyrebird", " thornbill", " honeyeater", " oriole", -" fantail", " shrike", " crow", " raven", " magpie", " kinglet", " lark", " swallow", " martin", " bushtit", -" warbler", " thrush", " oxpecker", " starling", " mockingbird", " wren", " nuthatch", " sparrow", " tanager", -" cardinal", " bunting", " finch", " titmouse", " chickadee", " waxwing", " flycatcher", " opossum", " koala", -" wombat", " kangaroo", " sloth", " anteater", " armadillo", " squirrel", " marmot", " beaver", " gopher", -" mouse", " porcupine", " chinchilla", " cavy", " capybara", " rabbit", " hare", " lemur", " loris", " monkey", -" hedgehog", " shrew", " mole", " fruit bat", " wolf", " coyote", " jackal", " raccoon", " coati", -" weasel", " otter", " badger", " skunk", " bear", " panda", " panther", " mongoose", " hyena", " civet", -" walrus", " pangolin", " elephant", " mammoth", " horse", " zebra", " tapir", " rhinoceros", " warthog", -" hippopotamus", " camel", " llama", " giraffe", " deer", " moose", " antelope", " sheep", " goat", -" bison", " buffalo", " bull", " ape", " ant", " bat", " owl", " pig", " bee" }; +std::vector descriptors = { "blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", +"damselfly", "stonefly", "earwig", "grasshopper", "cricket", "stick insect", "cockroach", "termite", +"mantis", "louse", "thrips", "aphid", "cicada", "assassin bug", "wasp", "hornet", "tiger beetle", +"ladybug", "weevil", "darkling beetle", "click beetle", "firefly", "scarab beetle", "stag beetle", +"dung beetle", "rhinoceros beetle", "rove beetle", "snakefly", "lacewing", "antlion larva", +"mosquito", "flea", "scorpionfly", "caddisfly", "butterfly", "moth", "caterpillar", "maggot", +"spider", "tarantula", "scorpion", "tick", "mite", "shrimp", "lobster", "crab", "nematode", +"snail", "slug", "earthworm", "leech", "bristleworm", "ribbon worm", "flat worm", "toad", "frog", +"salamander", "newt", "alligator", "crocodile", "lizard", "chameleon", "iguana", "gecko", "skink", +"gila monster", "monitor", "serpent", "viper", "rattlesnake", "cobra", "python", "anaconda", "turtle", +"tortoise", "pterosaur", "dimetrodon", "sauropod", "theropod", "iguanodont", "hadrosaurid", "stegosaurid", +"ceratopsid", "ankylosaurid", "duck", "goose", "swan", "turkey", "grouse", "chicken", "quail", "pheasant", +"gull", "loon", "grebe", "albatross", "petrel", "penguin", "pelican", "stork", "vulture", "flamingo", +"falcon", "kestrel", "condor", "osprey", "buzzard", "eagle", "harrier", "kite", "crane", "dove", +"pigeon", "parrot", "cockatoo", "cuckoo", "nightjar", "swift", "hummingbird", "kingfisher", +"hornbill", "quetzal", "toucan", "woodpecker", "lyrebird", "thornbill", "honeyeater", "oriole", +"fantail", "shrike", "crow", "raven", "magpie", "kinglet", "lark", "swallow", "martin", "bushtit", +"warbler", "thrush", "oxpecker", "starling", "mockingbird", "wren", "nuthatch", "sparrow", "tanager", +"cardinal", "bunting", "finch", "titmouse", "chickadee", "waxwing", "flycatcher", "opossum", "koala", +"wombat", "kangaroo", "sloth", "anteater", "armadillo", "squirrel", "marmot", "beaver", "gopher", +"mouse", "porcupine", "chinchilla", "cavy", "capybara", "rabbit", "hare", "lemur", "loris", "monkey", +"hedgehog", "shrew", "mole", "fruit bat", "wolf", "coyote", "jackal", "raccoon", "coati", +"weasel", "otter", "badger", "skunk", "bear", "panda", "panther", "mongoose", "hyena", "civet", +"walrus", "pangolin", "elephant", "mammoth", "horse", "zebra", "tapir", "rhinoceros", "warthog", +"hippopotamus", "camel", "llama", "giraffe", "deer", "moose", "antelope", "sheep", "goat", +"bison", "buffalo", "bull", "ape", "ant", "bat", "owl", "pig", "bee"}; DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) @@ -100,7 +100,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan for (size_t j = 0; j < descriptors.size(); j++) { - size_t pos = creatureRaw->caste[0]->description.find(descriptors[j]); + size_t pos = creatureRaw->caste[0]->description.find(" " + descriptors[j]); if (pos < minPos) { minPos = pos; From 64e217132e41957c51347280bece3697e02a81d9 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Mon, 6 Feb 2017 10:50:18 +0530 Subject: [PATCH 327/413] Don't offset the raplacement by 1 since there's no space now. --- plugins/generated-creature-renamer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index caace087a..7e0f2c309 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -114,7 +114,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan if (digitPos > creatureRaw->creature_id.length()) digitPos = creatureRaw->creature_id.length(); - creatureRaw->creature_id.replace(digitPos, std::string::npos, descriptors[foundIndex], 1, std::string::npos); + creatureRaw->creature_id.replace(digitPos, std::string::npos, descriptors[foundIndex]); if (descriptorCount[foundIndex] > 0) { From 68faca09ee03726e8408253dcc08a02d6a9a3baf Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Tue, 7 Feb 2017 10:27:57 +0530 Subject: [PATCH 328/413] Added missing base types given by toady, and reorganized the list to look better. --- plugins/generated-creature-renamer.cpp | 58 ++++++++++++++------------ 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 7e0f2c309..1d0b98f58 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -45,32 +45,38 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) return CR_OK; } -std::vector descriptors = { "blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", -"damselfly", "stonefly", "earwig", "grasshopper", "cricket", "stick insect", "cockroach", "termite", -"mantis", "louse", "thrips", "aphid", "cicada", "assassin bug", "wasp", "hornet", "tiger beetle", -"ladybug", "weevil", "darkling beetle", "click beetle", "firefly", "scarab beetle", "stag beetle", -"dung beetle", "rhinoceros beetle", "rove beetle", "snakefly", "lacewing", "antlion larva", -"mosquito", "flea", "scorpionfly", "caddisfly", "butterfly", "moth", "caterpillar", "maggot", -"spider", "tarantula", "scorpion", "tick", "mite", "shrimp", "lobster", "crab", "nematode", -"snail", "slug", "earthworm", "leech", "bristleworm", "ribbon worm", "flat worm", "toad", "frog", -"salamander", "newt", "alligator", "crocodile", "lizard", "chameleon", "iguana", "gecko", "skink", -"gila monster", "monitor", "serpent", "viper", "rattlesnake", "cobra", "python", "anaconda", "turtle", -"tortoise", "pterosaur", "dimetrodon", "sauropod", "theropod", "iguanodont", "hadrosaurid", "stegosaurid", -"ceratopsid", "ankylosaurid", "duck", "goose", "swan", "turkey", "grouse", "chicken", "quail", "pheasant", -"gull", "loon", "grebe", "albatross", "petrel", "penguin", "pelican", "stork", "vulture", "flamingo", -"falcon", "kestrel", "condor", "osprey", "buzzard", "eagle", "harrier", "kite", "crane", "dove", -"pigeon", "parrot", "cockatoo", "cuckoo", "nightjar", "swift", "hummingbird", "kingfisher", -"hornbill", "quetzal", "toucan", "woodpecker", "lyrebird", "thornbill", "honeyeater", "oriole", -"fantail", "shrike", "crow", "raven", "magpie", "kinglet", "lark", "swallow", "martin", "bushtit", -"warbler", "thrush", "oxpecker", "starling", "mockingbird", "wren", "nuthatch", "sparrow", "tanager", -"cardinal", "bunting", "finch", "titmouse", "chickadee", "waxwing", "flycatcher", "opossum", "koala", -"wombat", "kangaroo", "sloth", "anteater", "armadillo", "squirrel", "marmot", "beaver", "gopher", -"mouse", "porcupine", "chinchilla", "cavy", "capybara", "rabbit", "hare", "lemur", "loris", "monkey", -"hedgehog", "shrew", "mole", "fruit bat", "wolf", "coyote", "jackal", "raccoon", "coati", -"weasel", "otter", "badger", "skunk", "bear", "panda", "panther", "mongoose", "hyena", "civet", -"walrus", "pangolin", "elephant", "mammoth", "horse", "zebra", "tapir", "rhinoceros", "warthog", -"hippopotamus", "camel", "llama", "giraffe", "deer", "moose", "antelope", "sheep", "goat", -"bison", "buffalo", "bull", "ape", "ant", "bat", "owl", "pig", "bee"}; +std::vector descriptors = { + "blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", "damselfly", "stonefly", + "earwig", "grasshopper", "cricket", "stick insect", "cockroach", "termite", "mantis", "louse", + "thrips", "aphid", "cicada", "assassin bug", "wasp", "hornet", "tiger beetle", "ladybug", + "weevil", "darkling beetle", "click beetle", "firefly", "scarab beetle", "stag beetle", "dung beetle", "rhinoceros beetle", + "rove beetle", "snakefly", "lacewing", "antlion larva", "mosquito", "flea", "scorpionfly", "caddisfly", + "butterfly", "moth", "caterpillar", "maggot", "spider", "tarantula", "scorpion", "tick", + "mite", "shrimp", "lobster", "crab", "nematode", "snail", "slug", "earthworm", + "leech", "bristleworm", "ribbon worm", "flat worm", "toad", "frog", "salamander", "newt", + "alligator", "crocodile", "lizard", "chameleon", "iguana", "gecko", "skink", "gila monster", + "monitor", "serpent", "viper", "rattlesnake", "cobra", "python", "anaconda", "turtle", + "tortoise", "pterosaur", "dimetrodon", "sauropod", "theropod", "iguanodont", "hadrosaurid", "stegosaurid", + "ceratopsid", "ankylosaurid", "duck", "goose", "swan", "turkey", "grouse", "chicken", + "quail", "pheasant", "gull", "loon", "grebe", "albatross", "petrel", "penguin", + "pelican", "stork", "vulture", "flamingo", "falcon", "kestrel", "condor", "osprey", + "buzzard", "eagle", "harrier", "kite", "crane", "dove", "pigeon", "parrot", + "cockatoo", "cuckoo", "nightjar", "swift", "hummingbird", "kingfisher", "hornbill", "quetzal", + "toucan", "woodpecker", "lyrebird", "thornbill", "honeyeater", "oriole", "fantail", "shrike", + "crow", "raven", "magpie", "kinglet", "lark", "swallow", "martin", "bushtit", + "warbler", "thrush", "oxpecker", "starling", "mockingbird", "wren", "nuthatch", "sparrow", + "tanager", "cardinal", "bunting", "finch", "titmouse", "chickadee", "waxwing", "flycatcher", + "opossum", "koala", "wombat", "kangaroo", "sloth", "anteater", "armadillo", "squirrel", + "marmot", "beaver", "gopher", "mouse", "porcupine", "chinchilla", "cavy", "capybara", + "rabbit", "hare", "lemur", "loris", "monkey", "hedgehog", "shrew", "mole", + "fruit bat", "wolf", "coyote", "jackal", "raccoon", "coati", "weasel", "otter", + "badger", "skunk", "bear", "panda", "panther", "mongoose", "hyena", "civet", + "walrus", "pangolin", "elephant", "mammoth", "horse", "zebra", "tapir", "rhinoceros", + "warthog", "hippopotamus", "camel", "llama", "giraffe", "deer", "moose", "antelope", + "sheep", "goat", "bison", "buffalo", "bull", "ape", "ant", "bat", + "owl", "pig", "bee", "fly", "hawk", "jay", "rat", "fox", + "cat", "ass", "elk" +}; DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) From f9b296884c728ea416a799505e4d30d1e7ee2ce1 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Tue, 7 Feb 2017 11:01:42 +0530 Subject: [PATCH 329/413] Made the creature renamer work more than once on the same save, and changed the format of the resulting names. --- plugins/generated-creature-renamer.cpp | 51 +++++++++++++++++++------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 1d0b98f58..9463773b2 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -16,7 +16,7 @@ using namespace DFHack; DFHACK_PLUGIN("generated-creature-renamer"); REQUIRE_GLOBAL(world); -#define RENAMER_VERSION 1 +#define RENAMER_VERSION 2 command_result list_creatures(color_ostream &out, std::vector & parameters); @@ -78,6 +78,14 @@ std::vector descriptors = { "cat", "ass", "elk" }; +std::vector prefixes = { + "FORGOTTEN_BEAST_", + "TITAN_", + "DEMON_", + "NIGHT_CREATURE_", + "HF" +}; + DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { @@ -102,7 +110,19 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED)) continue; size_t minPos = std::string::npos; - size_t foundIndex = std::string::npos; + size_t foundIndex = -1; + size_t prefixIndex = -1; + + for (rsize_t j = 0; j < prefixes.size(); j++) + { + if (creatureRaw->creature_id.compare(0, prefixes[j].length(), prefixes[j]) == 0) + { + prefixIndex = j; + } + } + + if (prefixIndex < 0) + continue; //unrecognized generaed type. for (size_t j = 0; j < descriptors.size(); j++) { @@ -114,21 +134,26 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan } } - if (foundIndex < std::string::npos) - { - size_t digitPos = creatureRaw->creature_id.find_first_of("0123456789"); - if (digitPos > creatureRaw->creature_id.length()) - digitPos = creatureRaw->creature_id.length(); + if (foundIndex < 0) + continue; //can't find a match. - creatureRaw->creature_id.replace(digitPos, std::string::npos, descriptors[foundIndex]); + auto descriptor = descriptors[foundIndex]; - if (descriptorCount[foundIndex] > 0) - { - creatureRaw->creature_id.append(std::to_string(descriptorCount[foundIndex])); - } + for (int j = 0; j < descriptor.size(); j++) + { + if (descriptor[j] == ' ') + descriptor[j] = '_'; + else + descriptor[j] = toupper(descriptor[j]); + } + + creatureRaw->creature_id = prefixes[prefixIndex] + descriptor; - descriptorCount[foundIndex]++; + if (descriptorCount[foundIndex] > 0) + { + creatureRaw->creature_id.append("_" + std::to_string(descriptorCount[foundIndex])); } + descriptorCount[foundIndex]++; } version = World::AddPersistentData("AlreadyRenamedCreatures"); version.ival(1) = RENAMER_VERSION; From b151ad7c750f4bdc4e0b69240a98d854843615c6 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Tue, 7 Feb 2017 11:09:39 +0530 Subject: [PATCH 330/413] always make sure the name prefix has an underscore at the end of it. --- plugins/generated-creature-renamer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 9463773b2..df7b5c0d3 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -16,7 +16,7 @@ using namespace DFHack; DFHACK_PLUGIN("generated-creature-renamer"); REQUIRE_GLOBAL(world); -#define RENAMER_VERSION 2 +#define RENAMER_VERSION 3 command_result list_creatures(color_ostream &out, std::vector & parameters); @@ -147,6 +147,10 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan descriptor[j] = toupper(descriptor[j]); } + auto prefix = prefixes[prefixIndex]; + if (prefix[prefix.length() - 1] != '_') + prefix.append("_"); + creatureRaw->creature_id = prefixes[prefixIndex] + descriptor; if (descriptorCount[foundIndex] > 0) From 10bbd3cb39ff1cf97f14329f60de9bed0a735ff7 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Tue, 7 Feb 2017 11:19:45 +0530 Subject: [PATCH 331/413] Added a function to spit out a generated graphics pack file. Not done yet. --- plugins/generated-creature-renamer.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index df7b5c0d3..e6cf8723f 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -19,6 +19,7 @@ REQUIRE_GLOBAL(world); #define RENAMER_VERSION 3 command_result list_creatures(color_ostream &out, std::vector & parameters); +command_result save_generated_raw(color_ostream &out, std::vector & parameters); DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { @@ -29,7 +30,13 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector & pa } } +command_result save_generated_raw(color_ostream &out, std::vector & parameters) +{ + + return CR_OK; +} From 873feaee2b04e1d27a48253b5ee616ced0521a82 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Tue, 7 Feb 2017 15:57:35 +0530 Subject: [PATCH 332/413] Added a function to the creature renamer to save a graphics pack file to set graphics for all the generated creatures. --- plugins/generated-creature-renamer.cpp | 177 +++++++++++++++++-------- 1 file changed, 121 insertions(+), 56 deletions(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index e6cf8723f..5eb030d44 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -8,6 +8,7 @@ #include "df/creature_raw.h" #include "df/caste_raw.h" #include "modules/World.h" +#include "MemAccess.h" //#include "df/world.h" @@ -25,17 +26,17 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector descriptorCount = std::vector(descriptors.size()); + + auto version = World::GetPersistentData("AlreadyRenamedCreatures"); + if (version.isValid() && version.ival(1) >= RENAMER_VERSION) { - case DFHack::SC_WORLD_LOADED: - CoreSuspender suspend; + return CR_OK; + } - std::vector descriptorCount = std::vector(descriptors.size()); + int creatureCount = 0; - auto version = World::GetPersistentData("AlreadyRenamedCreatures"); - if (version.isValid() && version.ival(1) >= RENAMER_VERSION) - { - return CR_OK; - } + for (int i = 0; i < world->raws.creatures.all.size(); i++) + { + auto creatureRaw = world->raws.creatures.all[i]; + if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED)) + continue; + size_t minPos = std::string::npos; + size_t foundIndex = -1; + size_t prefixIndex = -1; - for (int i = 0; i < world->raws.creatures.all.size(); i++) + for (rsize_t j = 0; j < prefixes.size(); j++) { - auto creatureRaw = world->raws.creatures.all[i]; - if (!creatureRaw->flags.is_set(df::enums::creature_raw_flags::GENERATED)) - continue; - size_t minPos = std::string::npos; - size_t foundIndex = -1; - size_t prefixIndex = -1; - - for (rsize_t j = 0; j < prefixes.size(); j++) + if (creatureRaw->creature_id.compare(0, prefixes[j].length(), prefixes[j]) == 0) { - if (creatureRaw->creature_id.compare(0, prefixes[j].length(), prefixes[j]) == 0) - { - prefixIndex = j; - } + prefixIndex = j; } + } - if (prefixIndex < 0) - continue; //unrecognized generaed type. + if (prefixIndex < 0) + continue; //unrecognized generaed type. - for (size_t j = 0; j < descriptors.size(); j++) + for (size_t j = 0; j < descriptors.size(); j++) + { + size_t pos = creatureRaw->caste[0]->description.find(" " + descriptors[j]); + if (pos < minPos) { - size_t pos = creatureRaw->caste[0]->description.find(" " + descriptors[j]); - if (pos < minPos) - { - minPos = pos; - foundIndex = j; - } + minPos = pos; + foundIndex = j; } + } - if (foundIndex < 0) - continue; //can't find a match. + if (foundIndex < 0) + continue; //can't find a match. - auto descriptor = descriptors[foundIndex]; + auto descriptor = descriptors[foundIndex]; - for (int j = 0; j < descriptor.size(); j++) - { - if (descriptor[j] == ' ') - descriptor[j] = '_'; - else - descriptor[j] = toupper(descriptor[j]); - } + for (int j = 0; j < descriptor.size(); j++) + { + if (descriptor[j] == ' ') + descriptor[j] = '_'; + else + descriptor[j] = toupper(descriptor[j]); + } - auto prefix = prefixes[prefixIndex]; - if (prefix[prefix.length() - 1] != '_') - prefix.append("_"); + auto prefix = prefixes[prefixIndex]; + if (prefix[prefix.length() - 1] != '_') + prefix.append("_"); - creatureRaw->creature_id = prefixes[prefixIndex] + descriptor; + creatureRaw->creature_id = prefixes[prefixIndex] + descriptor; - if (descriptorCount[foundIndex] > 0) - { - creatureRaw->creature_id.append("_" + std::to_string(descriptorCount[foundIndex])); - } - descriptorCount[foundIndex]++; + if (descriptorCount[foundIndex] > 0) + { + creatureRaw->creature_id.append("_" + std::to_string(descriptorCount[foundIndex])); } - version = World::AddPersistentData("AlreadyRenamedCreatures"); - version.ival(1) = RENAMER_VERSION; - break; + descriptorCount[foundIndex]++; + creatureCount++; } + version = World::AddPersistentData("AlreadyRenamedCreatures"); + version.ival(1) = RENAMER_VERSION; + + out << "Renamed " << creatureCount << " generated creatures to have sensible names." << endl; + + return CR_OK; } @@ -200,10 +207,68 @@ command_result list_creatures(color_ostream &out, std::vector & pa } out.print("\n"); } + return CR_OK; } command_result save_generated_raw(color_ostream &out, std::vector & parameters) { +#ifdef LINUX_BUILD + std::string pathSep = "/"; +#else + std::string pathSep = "\\"; +#endif + int pageWidth = 16; + int pageHeight = (descriptors.size() / pageWidth) + ((descriptors.size() % pageWidth > 0) ? 1 : 0); + int tileWidth = 24; + int tileHeight = 24; + std::string fileName = "graphics_procedural_creatures"; + std::string pageName = "PROCEDURAL_FRIENDLY"; + int repeats = 128; + + std::ofstream outputFile(fileName + ".txt", std::ios::out | std::ios::trunc); + + outputFile << fileName << endl << endl; + + outputFile << "[OBJECT:GRAPHICS]" << endl << endl; + + outputFile << "[TILE_PAGE:" << pageName << "]" << endl; + outputFile << " [FILE:procedural_friendly.png]" << endl; + outputFile << " [TILE_DIM:" << tileWidth << ":" << tileHeight << "]" << endl; + outputFile << " [PAGE_DIM:" << pageWidth << ":" << pageHeight << "]" << endl << endl; + + for (size_t descIndex = 0; descIndex < descriptors.size(); descIndex++) + { + for (size_t prefIndex = 0; prefIndex < prefixes.size(); prefIndex++) + { + for (size_t rep = 0; rep < repeats; rep++) + { + auto descriptor = descriptors[descIndex]; + + for (int j = 0; j < descriptor.size(); j++) + { + if (descriptor[j] == ' ') + descriptor[j] = '_'; + else + descriptor[j] = toupper(descriptor[j]); + } + + auto prefix = prefixes[prefIndex]; + if (prefix[prefix.length() - 1] != '_') + prefix.append("_"); + + std::string token = prefix + descriptor; + if (rep > 0) + token.append("_" + std::to_string(rep)); + + outputFile << "[CREATURE_GRAPHICS:" << token << "]" << endl; + outputFile << " [DEFAULT:" << pageName << ":" << descIndex % pageWidth << ":" << descIndex / pageWidth << ":ADD_COLOR]" << endl; + } + outputFile << endl; + } + outputFile << endl; + } + + outputFile.close(); return CR_OK; } From 2c19f6b237f555aaf5de0abf6a08043aa8bf1024 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Wed, 8 Feb 2017 10:34:11 +0530 Subject: [PATCH 333/413] remove rsize_t --- plugins/generated-creature-renamer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 5eb030d44..13f0f9a6f 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -124,7 +124,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan size_t foundIndex = -1; size_t prefixIndex = -1; - for (rsize_t j = 0; j < prefixes.size(); j++) + for (size_t j = 0; j < prefixes.size(); j++) { if (creatureRaw->creature_id.compare(0, prefixes[j].length(), prefixes[j]) == 0) { From 0d8decd7eccbab575334646bcd9f67a2e795b0f4 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Wed, 8 Feb 2017 10:54:42 +0530 Subject: [PATCH 334/413] Remove trailing whitespaces. --- plugins/generated-creature-renamer.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/generated-creature-renamer.cpp b/plugins/generated-creature-renamer.cpp index 13f0f9a6f..49444eaf4 100644 --- a/plugins/generated-creature-renamer.cpp +++ b/plugins/generated-creature-renamer.cpp @@ -57,32 +57,32 @@ std::vector descriptors = { "blob", "quadruped", "humanoid", "silverfish", "mayfly", "dragonfly", "damselfly", "stonefly", "earwig", "grasshopper", "cricket", "stick insect", "cockroach", "termite", "mantis", "louse", "thrips", "aphid", "cicada", "assassin bug", "wasp", "hornet", "tiger beetle", "ladybug", - "weevil", "darkling beetle", "click beetle", "firefly", "scarab beetle", "stag beetle", "dung beetle", "rhinoceros beetle", - "rove beetle", "snakefly", "lacewing", "antlion larva", "mosquito", "flea", "scorpionfly", "caddisfly", + "weevil", "darkling beetle", "click beetle", "firefly", "scarab beetle", "stag beetle", "dung beetle", "rhinoceros beetle", + "rove beetle", "snakefly", "lacewing", "antlion larva", "mosquito", "flea", "scorpionfly", "caddisfly", "butterfly", "moth", "caterpillar", "maggot", "spider", "tarantula", "scorpion", "tick", "mite", "shrimp", "lobster", "crab", "nematode", "snail", "slug", "earthworm", "leech", "bristleworm", "ribbon worm", "flat worm", "toad", "frog", "salamander", "newt", - "alligator", "crocodile", "lizard", "chameleon", "iguana", "gecko", "skink", "gila monster", + "alligator", "crocodile", "lizard", "chameleon", "iguana", "gecko", "skink", "gila monster", "monitor", "serpent", "viper", "rattlesnake", "cobra", "python", "anaconda", "turtle", "tortoise", "pterosaur", "dimetrodon", "sauropod", "theropod", "iguanodont", "hadrosaurid", "stegosaurid", - "ceratopsid", "ankylosaurid", "duck", "goose", "swan", "turkey", "grouse", "chicken", + "ceratopsid", "ankylosaurid", "duck", "goose", "swan", "turkey", "grouse", "chicken", "quail", "pheasant", "gull", "loon", "grebe", "albatross", "petrel", "penguin", "pelican", "stork", "vulture", "flamingo", "falcon", "kestrel", "condor", "osprey", "buzzard", "eagle", "harrier", "kite", "crane", "dove", "pigeon", "parrot", "cockatoo", "cuckoo", "nightjar", "swift", "hummingbird", "kingfisher", "hornbill", "quetzal", - "toucan", "woodpecker", "lyrebird", "thornbill", "honeyeater", "oriole", "fantail", "shrike", + "toucan", "woodpecker", "lyrebird", "thornbill", "honeyeater", "oriole", "fantail", "shrike", "crow", "raven", "magpie", "kinglet", "lark", "swallow", "martin", "bushtit", "warbler", "thrush", "oxpecker", "starling", "mockingbird", "wren", "nuthatch", "sparrow", "tanager", "cardinal", "bunting", "finch", "titmouse", "chickadee", "waxwing", "flycatcher", "opossum", "koala", "wombat", "kangaroo", "sloth", "anteater", "armadillo", "squirrel", - "marmot", "beaver", "gopher", "mouse", "porcupine", "chinchilla", "cavy", "capybara", - "rabbit", "hare", "lemur", "loris", "monkey", "hedgehog", "shrew", "mole", + "marmot", "beaver", "gopher", "mouse", "porcupine", "chinchilla", "cavy", "capybara", + "rabbit", "hare", "lemur", "loris", "monkey", "hedgehog", "shrew", "mole", "fruit bat", "wolf", "coyote", "jackal", "raccoon", "coati", "weasel", "otter", "badger", "skunk", "bear", "panda", "panther", "mongoose", "hyena", "civet", "walrus", "pangolin", "elephant", "mammoth", "horse", "zebra", "tapir", "rhinoceros", - "warthog", "hippopotamus", "camel", "llama", "giraffe", "deer", "moose", "antelope", + "warthog", "hippopotamus", "camel", "llama", "giraffe", "deer", "moose", "antelope", "sheep", "goat", "bison", "buffalo", "bull", "ape", "ant", "bat", - "owl", "pig", "bee", "fly", "hawk", "jay", "rat", "fox", + "owl", "pig", "bee", "fly", "hawk", "jay", "rat", "fox", "cat", "ass", "elk" }; From c68faaae378ba5fec6dbe7127b1ec79a38584536 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Fri, 10 Feb 2017 15:30:48 +0530 Subject: [PATCH 335/413] Add basic documentation for the generated-creature-renamer plugin. --- docs/Plugins.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index b3e68459d..b34b41da9 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -2453,6 +2453,24 @@ armor onto a war animal or to add unusual items (such as crowns) to any unit. For more information run ``forceequip help``. See also `modtools/equip-item`. +.. _generated-creature-renamer: + +generated-creature-renamer +========================== +Automatically renames generated creatures, such as forgotten beasts, titans, +etc, to have raw token names that match the description given in-game. + +The `list-generated` command can be used to list the token names of all +generated creatures in a given save, with an optional `detailed` argument +to show the accompanying description. + +The `save-generated-raws` command will save a sample creature graphics file in +the Dwarf Fortress root directory, to use as a start for making a graphics set +for generated creatures using the new names that they get with this plugin. + +The new names are saved with the save, and the plugin, when enabled, only runs once +per save, unless there's an update. + .. _lair: lair From f89678c47259ac3b06c15af8f5165f7d86f12816 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 11 Feb 2017 15:07:48 -0500 Subject: [PATCH 336/413] Fix backticks --- docs/Plugins.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index b34b41da9..9e7498cee 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -2460,11 +2460,11 @@ generated-creature-renamer Automatically renames generated creatures, such as forgotten beasts, titans, etc, to have raw token names that match the description given in-game. -The `list-generated` command can be used to list the token names of all -generated creatures in a given save, with an optional `detailed` argument +The ``list-generated`` command can be used to list the token names of all +generated creatures in a given save, with an optional ``detailed`` argument to show the accompanying description. -The `save-generated-raws` command will save a sample creature graphics file in +The ``save-generated-raws`` command will save a sample creature graphics file in the Dwarf Fortress root directory, to use as a start for making a graphics set for generated creatures using the new names that they get with this plugin. From b110355b53778d2ffa5a509bcb84ab433ea40502 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 11 Feb 2017 15:09:46 -0500 Subject: [PATCH 337/413] Add missing space --- docs/Plugins.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 9e7498cee..e2b829020 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -2540,7 +2540,7 @@ Options: :-unit: Make the strange mood strike the selected unit instead of picking one randomly. Unit eligibility is still enforced. :-type : Force the mood to be of a particular type instead of choosing randomly based on happiness. - Valid values for Tare "fey", "secretive", "possessed", "fell", and "macabre". + Valid values for T 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", From a10d4ae226db6f1f7c562f06b2cfd1804db03b81 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 11 Feb 2017 16:53:50 -0500 Subject: [PATCH 338/413] Add viewscreen::feed_key method --- library/include/df/custom/viewscreen.methods.inc | 5 +++++ library/xml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/library/include/df/custom/viewscreen.methods.inc b/library/include/df/custom/viewscreen.methods.inc index c5d277716..b1f07242e 100644 --- a/library/include/df/custom/viewscreen.methods.inc +++ b/library/include/df/custom/viewscreen.methods.inc @@ -1 +1,6 @@ friend struct df::interfacest; +void feed_key(df::interface_key key) { + std::set input; + input.insert(key); + feed(&input); +} diff --git a/library/xml b/library/xml index fc2570c6c..e60c4259a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit fc2570c6c0179fcdf48610f0e3eaef7f84908da7 +Subproject commit e60c4259ab9ea9326af42173024a3b3e40fe6688 From 8b27ed5f1c5ae0b6f991621caaa69545d1f134eb Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 11 Feb 2017 17:07:49 -0500 Subject: [PATCH 339/413] Update changelog --- NEWS.rst | 8 ++++++++ docs/NEWS-dev.rst | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 2fdbfc561..4229da17f 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -64,6 +64,7 @@ Ruby New Plugins ----------- - `dwarfvet` enables animal caretaking +- `generated-creature-renamer`: Renames generated creature IDs for use with graphics packs - `labormanager` (formerly autolabor2): a more advanced alternative to `autolabor` - `misery`: re-added and updated for the 0.4x series - `title-folder`: shows DF folder name in window title bar when enabled @@ -80,6 +81,7 @@ Fixes ----- - The DF path on OS X can now contain spaces and ``:`` characters - Buildings::setOwner() changes now persist properly when saved +- ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable - `add-thought`: fixed support for emotion names - `autofarm`: Made surface farms detect local biome - `devel/find-offsets`: fixed a crash when vtables used by globals aren't available @@ -88,6 +90,10 @@ Fixes - Fixed crash when selecting a profession from an empty list - Custom professions are now sorted alphabetically more reliably +- `modtools/create-unit`: stopped permanently overwriting the creature creation + menu in arena mode +- `title-version`: now hidden when loading an arena + Misc Improvements ----------------- - Documented all default keybindings (from :file:`dfhack.init-example`) in the @@ -101,6 +107,8 @@ Misc Improvements - site towers, world buildings - surface material +- `title-version`: Added a prerelease indicator + DFHack 0.43.03-r1 ================= diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 9920e3433..2efc9bf2a 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -37,6 +37,35 @@ Development Changelog .. contents:: :depth: 2 +DFHack 0.43.05-beta1 +==================== + +Fixes +----- +- Fixed various crashes on 64-bit Windows related to DFHack screens, notably `manipulator` +- ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable +- `modtools/create-unit`: stopped permanently overwriting the creature creation + menu in arena mode +- `season-palette`: fixed an issue where only part of the screen was redrawn + after changing the color scheme +- `title-version`: now hidden when loading an arena + +Structures +---------- +- ``file_compressorst``: fixed field sizes on x64 +- ``ui_sidebar_menus.command_line``: fixed field sizes on x64 +- ``viewscreen_layer_arena_creaturest``: identified more fields +- ``world.math``: identified +- ``world.murky_pools``: identified + +Additions/Removals +------------------ +- `generated-creature-renamer`: Renames generated creature IDs for use with graphics packs + +Other Changes +------------- +- `title-version`: Added a prerelease indicator + DFHack 0.43.05-alpha4 ===================== From 2fdd4d96b623611c92a66cb2fe9b8b28e8ab8309 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 11 Feb 2017 20:24:51 -0500 Subject: [PATCH 340/413] Add more XML changes to NEWS-dev --- docs/NEWS-dev.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 2efc9bf2a..df74735c0 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -43,6 +43,7 @@ DFHack 0.43.05-beta1 Fixes ----- - Fixed various crashes on 64-bit Windows related to DFHack screens, notably `manipulator` +- Fixed addresses of next_id globals on 64-bit Linux (fixes an `automaterial`/box-select crash) - ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable - `modtools/create-unit`: stopped permanently overwriting the creature creation menu in arena mode @@ -53,7 +54,9 @@ Fixes Structures ---------- - ``file_compressorst``: fixed field sizes on x64 +- ``historical_entity``: fixed alignment on x64 - ``ui_sidebar_menus.command_line``: fixed field sizes on x64 +- ``viewscreen_choose_start_sitest``: added 3 missing fields, renamed ``in_embark_only_warning`` - ``viewscreen_layer_arena_creaturest``: identified more fields - ``world.math``: identified - ``world.murky_pools``: identified From 33060c7d0e2432fe31c62f35234bd96250055388 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 11 Feb 2017 20:48:37 -0500 Subject: [PATCH 341/413] Bump to beta1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3602655b4..c7c0835a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,7 @@ endif() # set up versioning. set(DF_VERSION "0.43.05") -SET(DFHACK_RELEASE "alpha4") +SET(DFHACK_RELEASE "beta1") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 19695b4ee7e8b370c8ce53aa2dcd399e1e9ca94d Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 17 Feb 2017 22:53:48 -0500 Subject: [PATCH 342/413] EventManager/eventful: Pass building ID pointers to event handlers Previously, there was some disagreement over whether event handlers such as Buildings::updateBuildings() took building pointers or building IDs shoved into pointers. It turned out to be the latter, which, unfortunately, did not compile on x64. Passing building IDs isn't possible in all cases, because building event handlers can be called for recently-deleted buildings too. Pointers to building IDs do work reliably, though. Fixes #1003 --- library/modules/Buildings.cpp | 92 ++++++++++++++++---------------- library/modules/EventManager.cpp | 6 +-- plugins/eventful.cpp | 6 +-- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 9d672cd58..55f0869a4 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -1182,52 +1182,52 @@ void Buildings::clearBuildings(color_ostream& out) { void Buildings::updateBuildings(color_ostream& out, void* ptr) { - // int32_t id = (int32_t)ptr; - // auto building = df::building::find(id); - - // if (building) - // { - // // Already cached -> weird, so bail out - // if (corner1.count(id)) - // return; - // // Civzones cannot be cached because they can - // // overlap each other and normal buildings. - // if (!building->isSettingOccupancy()) - // return; - - // df::coord p1(min(building->x1, building->x2), min(building->y1,building->y2), building->z); - // df::coord p2(max(building->x1, building->x2), max(building->y1,building->y2), building->z); - - // corner1[id] = p1; - // corner2[id] = p2; - - // for ( int32_t x = p1.x; x <= p2.x; x++ ) { - // for ( int32_t y = p1.y; y <= p2.y; y++ ) { - // df::coord pt(x,y,building->z); - // if (containsTile(building, pt, false)) - // locationToBuilding[pt] = id; - // } - // } - // } - // else if (corner1.count(id)) - // { - // //existing building: destroy it - // df::coord p1 = corner1[id]; - // df::coord p2 = corner2[id]; - - // for ( int32_t x = p1.x; x <= p2.x; x++ ) { - // for ( int32_t y = p1.y; y <= p2.y; y++ ) { - // df::coord pt(x,y,p1.z); - - // auto cur = locationToBuilding.find(pt); - // if (cur != locationToBuilding.end() && cur->second == id) - // locationToBuilding.erase(cur); - // } - // } - - // corner1.erase(id); - // corner2.erase(id); - // } + int32_t id = *((int32_t*)ptr); + auto building = df::building::find(id); + + if (building) + { + // Already cached -> weird, so bail out + if (corner1.count(id)) + return; + // Civzones cannot be cached because they can + // overlap each other and normal buildings. + if (!building->isSettingOccupancy()) + return; + + df::coord p1(min(building->x1, building->x2), min(building->y1,building->y2), building->z); + df::coord p2(max(building->x1, building->x2), max(building->y1,building->y2), building->z); + + corner1[id] = p1; + corner2[id] = p2; + + for ( int32_t x = p1.x; x <= p2.x; x++ ) { + for ( int32_t y = p1.y; y <= p2.y; y++ ) { + df::coord pt(x,y,building->z); + if (containsTile(building, pt, false)) + locationToBuilding[pt] = id; + } + } + } + else if (corner1.count(id)) + { + //existing building: destroy it + df::coord p1 = corner1[id]; + df::coord p2 = corner2[id]; + + for ( int32_t x = p1.x; x <= p2.x; x++ ) { + for ( int32_t y = p1.y; y <= p2.y; y++ ) { + df::coord pt(x,y,p1.z); + + auto cur = locationToBuilding.find(pt); + if (cur != locationToBuilding.end() && cur->second == id) + locationToBuilding.erase(cur); + } + } + + corner1.erase(id); + corner2.erase(id); + } } void Buildings::getStockpileContents(df::building_stockpilest *stockpile, std::vector *items) diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index dfb978022..e2baf9bfb 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -273,7 +273,7 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event } for ( size_t a = 0; a < df::global::world->buildings.all.size(); a++ ) { df::building* b = df::global::world->buildings.all[a]; - Buildings::updateBuildings(out, (void*)b); + Buildings::updateBuildings(out, (void*)&(b->id)); buildings.insert(b->id); } lastSyndromeTime = -1; @@ -609,7 +609,7 @@ static void manageBuildingEvent(color_ostream& out) { buildings.insert(a); for ( auto b = copy.begin(); b != copy.end(); b++ ) { EventHandler bob = (*b).second; - bob.eventHandler(out, (void*)intptr_t(a)); + bob.eventHandler(out, (void*)&a); } } nextBuilding = *df::global::building_next_id; @@ -625,7 +625,7 @@ static void manageBuildingEvent(color_ostream& out) { for ( auto b = copy.begin(); b != copy.end(); b++ ) { EventHandler bob = (*b).second; - bob.eventHandler(out, (void*)intptr_t(id)); + bob.eventHandler(out, (void*)&id); } a = buildings.erase(a); } diff --git a/plugins/eventful.cpp b/plugins/eventful.cpp index 14f1ec26e..365542314 100644 --- a/plugins/eventful.cpp +++ b/plugins/eventful.cpp @@ -183,8 +183,8 @@ void ev_mng_invasion(color_ostream& out, void* ptr) } static void ev_mng_building(color_ostream& out, void* ptr) { - int32_t myId=*(int32_t*)&ptr; - onBuildingCreatedDestroyed(out,myId); + int32_t id = *((int32_t*)ptr); + onBuildingCreatedDestroyed(out, id); } static void ev_mng_inventory(color_ostream& out, void* ptr) { @@ -289,7 +289,7 @@ IMPLEMENT_VMETHOD_INTERPOSE(furnace_hook, fillSidebarMenu); struct product_hook : item_product { typedef item_product interpose_base; - + DEFINE_VMETHOD_INTERPOSE( void, produce, (df::unit *unit, From c21b7bf9419d98b7adcbf156fe226dd16eec01de Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 1 Mar 2017 15:56:50 -0500 Subject: [PATCH 343/413] Add a Painter:key_string() method --- library/lua/gui.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 603c7ab44..b83691acf 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -354,6 +354,10 @@ function Painter:key(code,pen,...) ) end +function Painter:key_string(code, text, ...) + return self:key(code):string(': '):string(text, ...) +end + -------------------------- -- Abstract view object -- -------------------------- From 13cdc38b2f462efadee204b51fe541ca8683fd68 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 1 Mar 2017 15:57:09 -0500 Subject: [PATCH 344/413] Update scripts/gui/extended-status (new bed queueing feature) --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 76ee1ec38..a05e51095 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 76ee1ec38bf56fce0e48404520ce5e0ebe22702b +Subproject commit a05e51095d9d571213aa33caffb5912468a3e6dc From 43a58f8d85aa61d4994f0bc7352d7bf6e3356de0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 1 Mar 2017 20:29:46 -0500 Subject: [PATCH 345/413] Remove obsolete settings from Windows build scripts, plus misc. updates - Added BUILD_DOCS=1 to release scripts - Removed "breakfast" scripts, which used the same settings as "all", plus a release version override, which is rarely used (if at all) and can be done separately. --- build/win32/generate-MSVC-all-breakfast.bat | 9 --------- build/win32/generate-MSVC-all.bat | 2 +- build/win32/generate-MSVC-minimal.bat | 2 +- build/win32/generate-MSVC-release.bat | 2 +- build/win64/generate-MSVC-all-breakfast.bat | 9 --------- build/win64/generate-MSVC-all.bat | 2 +- build/win64/generate-MSVC-minimal.bat | 2 +- build/win64/generate-MSVC-release.bat | 2 +- 8 files changed, 6 insertions(+), 24 deletions(-) delete mode 100644 build/win32/generate-MSVC-all-breakfast.bat delete mode 100644 build/win64/generate-MSVC-all-breakfast.bat diff --git a/build/win32/generate-MSVC-all-breakfast.bat b/build/win32/generate-MSVC-all-breakfast.bat deleted file mode 100644 index ac26c4f75..000000000 --- a/build/win32/generate-MSVC-all-breakfast.bat +++ /dev/null @@ -1,9 +0,0 @@ -@echo off -IF EXIST DF_PATH.txt SET /P _DF_PATH= Date: Wed, 1 Mar 2017 20:35:27 -0500 Subject: [PATCH 346/413] Update Windows build instructions for 0.43.05 --- docs/Compile.rst | 60 ++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index ac324a9f7..ebf6936c5 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -100,6 +100,9 @@ change, so specifying it explicitly is a good idea. cmake .. -DDFHACK_BUILD_ARCH=64 +Note that the scripts in the "build" folder on Windows will set the architecture +automatically. + Other settings -------------- There are a variety of other settings which you can find in CMakeCache.txt in @@ -355,47 +358,34 @@ Dependencies ------------ You will need the following: -* Microsoft Visual Studio 2010 SP1, with the C++ language +* Microsoft Visual Studio 2015, with the C++ language * Git * CMake * Perl with XML::LibXML and XML::LibXSLT * It is recommended to install StrawberryPerl, which includes both. -Microsoft Visual Studio 2010 SP1 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -DFHack has to be compiled with the Microsoft Visual C++ 2010 SP1 toolchain; later -versions won't work against Dwarf Fortress due to ABI and STL incompatibilities. - -At present, the only way to obtain the MSVC C++ 2010 toolchain is to install a -full copy of Microsoft Visual Studio 2010 SP1. The free Express version is sufficient. - -You can grab it from `Microsoft's site `_. - -You should also install the Visual Studio 2010 SP1 update. +* Python (for documentation; optional, except for release builds) -You can confirm whether you have SP1 by opening the Visual Studio 2010 IDE -and selecting About from the Help menu. If you have SP1 it will have *SP1Rel* -at the end of the version number, for example: *Version 10.0.40219.1 SP1Rel* - -Use of pre-SP1 releases has been reported to cause issues and is therefore not -supported by DFHack. Please ensure you are using SP1 before raising any Issues. - -If your Windows Update is configured to receive updates for all Microsoft -Products, not just Windows, you will receive the SP1 update automatically -through Windows Update (you will probably need to trigger a manual check.) +Microsoft Visual Studio 2015 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +DFHack has to be compiled with the Microsoft Visual C++ 2015 toolchain; other +versions won't work against Dwarf Fortress due to ABI and STL incompatibilities. -If not, you can download it directly `from this Microsoft Download link `_. +At present, the only way to obtain the MSVC C++ 2015 toolchain is to install a +full copy of Microsoft Visual Studio 2015. The free Community version is +sufficient. Additional dependencies: installing with the Chocolatey Package Manager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The remainder of dependencies - Git, CMake and StrawberryPerl - can be most -easily installed using the Chocolatey Package Manger. Chocolatey is a + +The remainder of dependencies - Git, CMake, StrawberryPerl, and Python - can be +most easily installed using the Chocolatey Package Manger. Chocolatey is a \*nix-style package manager for Windows. It's fast, small (8-20MB on disk) and very capable. Think "``apt-get`` for Windows." -Chocolatey is a preferred way of installing the required dependencies -as it's quicker, less effort and will install known-good utilities +Chocolatey is a recommended way of installing the required dependencies +as it's quicker, requires less effort, and will install known-good utilities guaranteed to have the correct setup (especially PATH). To install Chocolatey and the required dependencies: @@ -482,8 +472,10 @@ install XML::LibXML and XML::LibXSLT for it using CPAN. Build ----- -There are several different batch files in the ``build`` folder along -with a script that's used for picking the DF path. +There are several different batch files in the ``win32`` and ``win64`` +subfolders in the ``build`` folder, along with a script that's used for picking +the DF path. Use the subfolder corresponding to the architecture that you want +to build for. First, run ``set_df_path.vbs`` and point the dialog that pops up at a suitable DF installation which is of the appropriate version for the DFHack @@ -501,6 +493,9 @@ solution file(s): in, then hit configure, then generate. More options can appear after the configure step. * ``minimal`` will create a minimal solution with just the bare necessities - the main library and standard plugins. +* ``release`` will create a solution with everything that should be included in + release builds of DFHack. Note that this includes documentation, which requires + Python. Then you can either open the solution with MSVC or use one of the msbuild scripts: @@ -548,9 +543,10 @@ files as detailed above. Building/installing from the Visual Studio IDE: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -After running the CMake generate script you will have a new folder called VC2010. -Open the file ``dfhack.sln`` inside that folder. If you have multiple versions of -Visual Studio installed, make sure you open with Visual Studio 2010. +After running the CMake generate script you will have a new folder called VC2015 +or VC2015_32, depending on the architecture you specified. Open the file +``dfhack.sln`` inside that folder. If you have multiple versions of Visual +Studio installed, make sure you open with Visual Studio 2015. The first thing you must then do is change the build type. It defaults to Debug, but this cannot be used on Windows. Debug is not binary-compatible with DF. From b675f0fd3c62e26b90a44619da696001f2c1ad52 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 1 Mar 2017 20:44:47 -0500 Subject: [PATCH 347/413] Move old git note to bottom of compilation docs --- docs/Compile.rst | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index ebf6936c5..647dbb30b 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -31,6 +31,8 @@ To get the latest development code (develop branch), clone as above and then:: git checkout develop git submodule update +Generally, you should only need to clone DFHack once. + **Important note regarding submodule update and changing branches**: You must run ``git submodule update`` every time you change branches, @@ -39,17 +41,9 @@ If a submodule only exists on the newer branch, you also need to run ``git submodule update --init``. Failure to do this may result in strange build errors or "not a known DF version" errors. -**Important note regarding very old git versions** +**More notes**: -If you are using git 1.8.0 or older, and cloned DFHack before commit 85a920d -(around DFHack v0.43.03-alpha1), you may run into fatal git errors when updating -submodules after switching branches. This is due to those versions of git being -unable to handle our change from "scripts/3rdparty/name" submodules to a single -"scripts" submodule. This may be fixable by renaming .git/modules/scripts to -something else and re-running ``git submodule update --init`` on the branch with -the single scripts submodule (and running it again when switching back to the -one with multiple submodules, if necessary), but it is usually much simpler to -upgrade your git version. +* `note-old-git-and-dfhack` Contributing to DFHack ====================== @@ -670,3 +664,21 @@ Chocolatey as outlined in the `Windows section `:: Then close that Admin ``cmd.exe``, re-open another Admin ``cmd.exe``, and run:: pip install sphinx + +Misc. Notes +=========== + +.. _note-old-git-and-dfhack: + +Note on using very old git versions with pre-0.43.03 DFHack versions +-------------------------------------------------------------------- + +If you are using git 1.8.0 or older, and cloned DFHack before commit 85a920d +(around DFHack v0.43.03-alpha1), you may run into fatal git errors when updating +submodules after switching branches. This is due to those versions of git being +unable to handle our change from "scripts/3rdparty/name" submodules to a single +"scripts" submodule. This may be fixable by renaming .git/modules/scripts to +something else and re-running ``git submodule update --init`` on the branch with +the single scripts submodule (and running it again when switching back to the +one with multiple submodules, if necessary), but it is usually much simpler to +upgrade your git version. From 0cc51f8d69f299a2170eb2385ceb18d4df4afb6a Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 1 Mar 2017 21:29:17 -0500 Subject: [PATCH 348/413] Add support for downloading files in advance, useful for offline builds Also document this in Compile.rst - there have been complaints about the fact that DFHack downloads files at build time not being documented at all. --- CMake/DownloadFile.cmake | 21 +++++++++++++++++++++ CMake/downloads/.gitignore | 3 +++ CMake/downloads/README.txt | 3 +++ docs/Compile.rst | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 CMake/downloads/.gitignore create mode 100644 CMake/downloads/README.txt diff --git a/CMake/DownloadFile.cmake b/CMake/DownloadFile.cmake index 8f9938f90..fe9e4e05e 100644 --- a/CMake/DownloadFile.cmake +++ b/CMake/DownloadFile.cmake @@ -9,10 +9,31 @@ function(file_md5_if_exists FILE VAR) endif() endfunction() +function(search_downloads FILE_MD5 VAR) + set(${VAR} "" PARENT_SCOPE) + file(GLOB FILES ${CMAKE_SOURCE_DIR}/CMake/downloads/*) + foreach(FILE ${FILES}) + file(MD5 "${FILE}" CUR_MD5) + if("${CUR_MD5}" STREQUAL "${FILE_MD5}") + set(${VAR} ${FILE} PARENT_SCOPE) + return() + endif() + endforeach() +endfunction() + function(download_file URL DEST EXPECTED_MD5) get_filename_component(FILENAME "${URL}" NAME) file_md5_if_exists("${DEST}" CUR_MD5) + search_downloads(${EXPECTED_MD5} DLPATH) + if(NOT("${DLPATH}" STREQUAL "")) + message("* Copying ${FILENAME} from ${DLPATH}") + execute_process(COMMAND "${CMAKE_COMMAND}" -E copy + "${DLPATH}" + "${DEST}") + return() + endif() + if(NOT "${EXPECTED_MD5}" STREQUAL "${CUR_MD5}") message("* Downloading ${FILENAME}") file(DOWNLOAD "${URL}" "${DEST}" EXPECTED_MD5 "${EXPECTED_MD5}" SHOW_PROGRESS) diff --git a/CMake/downloads/.gitignore b/CMake/downloads/.gitignore new file mode 100644 index 000000000..ff7b252fe --- /dev/null +++ b/CMake/downloads/.gitignore @@ -0,0 +1,3 @@ +* +!README.txt +!.gitignore diff --git a/CMake/downloads/README.txt b/CMake/downloads/README.txt new file mode 100644 index 000000000..40b504725 --- /dev/null +++ b/CMake/downloads/README.txt @@ -0,0 +1,3 @@ +This folder exists as an alternate location for downloaded files. Files will +ordinarily not be downloaded here, but CMake will look for them here anyway to +facilitate offline builds. diff --git a/docs/Compile.rst b/docs/Compile.rst index 647dbb30b..c69d1de29 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -43,6 +43,7 @@ build errors or "not a known DF version" errors. **More notes**: +* `note-offline-builds` - read this if your build machine may not have an internet connection! * `note-old-git-and-dfhack` Contributing to DFHack @@ -668,6 +669,37 @@ Then close that Admin ``cmd.exe``, re-open another Admin ``cmd.exe``, and run:: Misc. Notes =========== +.. _note-offline-builds: + +Note on building DFHack offline +------------------------------- + +As of 0.43.05, DFHack downloads several files during the build process, depending +on your target OS and architecture. If your build machine's internet connection +is unreliable, or nonexistent, you can download these files in advance. + +First, you must locate the files you will need. These can be found in the +`dfhack-bin repo `_. Look for the +most recent version number *before or equal to* the DF version which you are +building for. For example, suppose "0.43.05" and "0.43.07" are listed. You should +choose "0.43.05" if you are building for 0.43.05 or 0.43.06, and "0.43.07" if +you are building for 0.43.07 or 0.43.08. + +Then, download all of the files you need, and save them to ``/CMake/downloads/``. The destination filename you choose +does not matter, as long as the files end up in the ``CMake/downloads`` folder. +You need to download all of the files for the architecture(s) you are building +for. For example, if you are building for 32-bit Linux and 64-bit Windows, +download all files starting with ``linux32`` and ``win64``. GitHub should sort +files alphabetically, so all the files you need should be next to each other. + +It is recommended that you create a build folder and run CMake to verify that +you have downloaded everything at this point, assuming your download machine has +CMake installed. This involves running a "generate" batch script on Windows, or +a command starting with ``cmake ..`` on Linux and OS X. CMake should +automatically locate files that you placed in ``CMake/downloads``, and use them +instead of attempting to download them. + .. _note-old-git-and-dfhack: Note on using very old git versions with pre-0.43.03 DFHack versions From 15759808e5a33da4fff2521a51039f2e4abf8da7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 2 Mar 2017 14:04:14 -0500 Subject: [PATCH 349/413] Fix "plug" output width for generated-creature-renamer --- library/Core.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 642da61ea..198e49df4 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -931,8 +931,8 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v } else if (builtin == "plug") { - const char *header_format = "%25s %10s %4s %8s\n"; - const char *row_format = "%25s %10s %4i %8s\n"; + const char *header_format = "%30s %10s %4s %8s\n"; + const char *row_format = "%30s %10s %4i %8s\n"; con.print(header_format, "Name", "State", "Cmds", "Enabled"); plug_mgr->refresh(); From 334817fa1be79a9f529433ade677a39e08b34c30 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 2 Mar 2017 14:04:34 -0500 Subject: [PATCH 350/413] Add Lua API functions to determine architecture --- library/LuaApi.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 39404e9be..a2446c78a 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1386,6 +1386,16 @@ static std::string getOSType() } } +static int getArchitecture() +{ + return sizeof(void*) * 8; +} + +static std::string getArchitectureName() +{ + return getArchitecture() == 64 ? "x86_64" : "x86"; +} + static std::string getDFVersion() { return Core::getInstance().vinfo->getVersion(); } static uint32_t getTickCount() { return Core::getInstance().p->getTickCount(); } @@ -1403,6 +1413,8 @@ static std::string df2console(std::string s) { return DF2CONSOLE(s); } static const LuaWrapper::FunctionReg dfhack_module[] = { WRAP(getOSType), + WRAP(getArchitecture), + WRAP(getArchitectureName), WRAP(getDFVersion), WRAP(getDFPath), WRAP(getTickCount), From d53c00d726811ed2649d754f42be679a52b09162 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 2 Mar 2017 14:05:08 -0500 Subject: [PATCH 351/413] Update scripts (add install-info) --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index a05e51095..7e8daa168 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit a05e51095d9d571213aa33caffb5912468a3e6dc +Subproject commit 7e8daa16822cc67f8e84adab7607694b622fe434 From 67f39316ce6e105fc99efd957693782b02ed199c Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 2 Mar 2017 14:05:34 -0500 Subject: [PATCH 352/413] Update xml (assorted viewscreen changes) --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index e60c4259a..a292304c6 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e60c4259ab9ea9326af42173024a3b3e40fe6688 +Subproject commit a292304c6097a499dfa749d5cc8ab24e69e004f5 From 38702febf7077842158c376a4b088288c616f3c4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 14 Mar 2017 00:24:05 -0400 Subject: [PATCH 353/413] Use LUA_(C)PATH_VAR instead of LUA_(C)PATH in luaconf.h This was apparently changed at some point around Lua 5.3, so a custom LUA_PATH environment variable could prevent DFHack from initializing. --- depends/lua/include/luaconf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/lua/include/luaconf.h b/depends/lua/include/luaconf.h index ce96b4747..051d2a944 100644 --- a/depends/lua/include/luaconf.h +++ b/depends/lua/include/luaconf.h @@ -200,8 +200,8 @@ LUA_CDIR"?.so;" "./?.so" #endif /* } */ -#define LUA_PATH "DFHACK_LUA_PATH" -#define LUA_CPATH "DFHACK_LUA_CPATH" +#define LUA_PATH_VAR "DFHACK_LUA_PATH" +#define LUA_CPATH_VAR "DFHACK_LUA_CPATH" /* @@ LUA_DIRSEP is the directory separator (for submodules). From e60d8de5fe04459120eb1c511dbf8f362f03257e Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 18 Mar 2017 00:25:46 +0530 Subject: [PATCH 354/413] Fix array out of bounds errors in remotefortressreader that were crashing linux. --- .../remotefortressreader.cpp | 78 ++++++++++++++----- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 3ebd2ea35..1f23cf0e1 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -2584,25 +2584,65 @@ static void CopyLocalMap(df::world_data * worldData, df::world_region_details* w auto south = riverTile->mutable_south(); auto west = riverTile->mutable_west(); - north->set_active(worldRegionDetails->rivers_vertical.active[xx][yy]); - north->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy]); - north->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy]); - north->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy]); - - south->set_active(worldRegionDetails->rivers_vertical.active[xx][yy + 1]); - south->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy + 1]); - south->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy + 1]); - south->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy + 1]); - - west->set_active(worldRegionDetails->rivers_horizontal.active[xx][yy]); - west->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx][yy]); - west->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx][yy]); - west->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx][yy]); - - east->set_active(worldRegionDetails->rivers_horizontal.active[xx + 1][yy]); - east->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx + 1][yy]); - east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); - east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); + if (xx < 16) + { + north->set_active(worldRegionDetails->rivers_vertical.active[xx][yy]); + north->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy]); + north->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy]); + north->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy]); + } + else + { + north->set_active(0); + north->set_elevation(100); + north->set_min_pos(-30000); + north->set_max_pos(-30000); + } + + if (yy < 16 && xx < 16) + { + south->set_active(worldRegionDetails->rivers_vertical.active[xx][yy + 1]); + south->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy + 1]); + south->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy + 1]); + south->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy + 1]); + } + else + { + south->set_active(0); + south->set_elevation(100); + south->set_min_pos(-30000); + south->set_max_pos(-30000); + } + + if (yy < 16) + { + west->set_active(worldRegionDetails->rivers_horizontal.active[xx][yy]); + west->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx][yy]); + west->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx][yy]); + west->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx][yy]); + } + else + { + west->set_active(0); + west->set_elevation(100); + west->set_min_pos(-30000); + west->set_max_pos(-30000); + } + + if (xx < 16 && yy < 16) + { + east->set_active(worldRegionDetails->rivers_horizontal.active[xx + 1][yy]); + east->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx + 1][yy]); + east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); + east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); + } + else + { + east->set_active(0); + east->set_elevation(100); + east->set_min_pos(-30000); + east->set_max_pos(-30000); + } } auto regionMap = worldData->region_map[pos_x][pos_y]; From 50a022d81bee885bb7181bc96e74236ae0604bc9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 18 Mar 2017 00:31:15 -0400 Subject: [PATCH 355/413] download_file(): avoid copying files if the correct file already exists --- CMake/DownloadFile.cmake | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CMake/DownloadFile.cmake b/CMake/DownloadFile.cmake index fe9e4e05e..5a10cca2f 100644 --- a/CMake/DownloadFile.cmake +++ b/CMake/DownloadFile.cmake @@ -25,16 +25,16 @@ function(download_file URL DEST EXPECTED_MD5) get_filename_component(FILENAME "${URL}" NAME) file_md5_if_exists("${DEST}" CUR_MD5) - search_downloads(${EXPECTED_MD5} DLPATH) - if(NOT("${DLPATH}" STREQUAL "")) - message("* Copying ${FILENAME} from ${DLPATH}") - execute_process(COMMAND "${CMAKE_COMMAND}" -E copy - "${DLPATH}" - "${DEST}") - return() - endif() - if(NOT "${EXPECTED_MD5}" STREQUAL "${CUR_MD5}") + search_downloads(${EXPECTED_MD5} DLPATH) + if(NOT("${DLPATH}" STREQUAL "")) + message("* Copying ${FILENAME} from ${DLPATH}") + execute_process(COMMAND "${CMAKE_COMMAND}" -E copy + "${DLPATH}" + "${DEST}") + return() + endif() + message("* Downloading ${FILENAME}") file(DOWNLOAD "${URL}" "${DEST}" EXPECTED_MD5 "${EXPECTED_MD5}" SHOW_PROGRESS) endif() From f17e9d36620978793a5daa08ac747ca7ea45373c Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 18 Mar 2017 00:31:25 -0400 Subject: [PATCH 356/413] title-folder: fix SDL path on OS X The Stonesense install script appears to do strange things which cause DF to load SDL.framework/Versions/A/SDL instead of SDL.framework/SDL. Once the former is loaded, loading the latter and calling SDL_WM_* functions from it will fail. A better solution would be to remove parts of the Stonesense fix-libs-*.sh script(s) that are causing this, since they don't appear to be needed, or use dlsym() to find the already-opened library/symbols. --- plugins/title-folder.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/title-folder.cpp b/plugins/title-folder.cpp index 205f7225a..eae381b95 100644 --- a/plugins/title-folder.cpp +++ b/plugins/title-folder.cpp @@ -16,6 +16,7 @@ static std::string original_title; static DFLibrary *sdl_handle = NULL; static const std::vector sdl_libs { "SDLreal.dll", + "SDL.framework/Versions/A/SDL", "SDL.framework/SDL", "libSDL-1.2.so.0" }; From 85e0daf15efd60b7b9dd0fc43ac2ea3ab5b1c02a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 18 Mar 2017 00:34:07 -0400 Subject: [PATCH 357/413] stonesense: basic 64-bit OS X support --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 416bc28f2..1925760b2 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 416bc28f2e25d06e7da28a5643b8a849aefddbf5 +Subproject commit 1925760b2f611d246d1715a2e3cfb591a02ef00b From 400d22cb760d2f41b011184d6acd2324848e03fd Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 18 Mar 2017 00:35:16 -0400 Subject: [PATCH 358/413] Update xml (ui_advmode_menu and ui_unit_view_mode) --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index a292304c6..8727ebd74 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit a292304c6097a499dfa749d5cc8ab24e69e004f5 +Subproject commit 8727ebd74a3f5d90e34a08266a3719e0cd5817d9 From a35d5493a44ce8e64093a8065b57f8bbad6e9d77 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 18 Mar 2017 17:49:54 -0400 Subject: [PATCH 359/413] Update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 7e8daa168..cf367974b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 7e8daa16822cc67f8e84adab7607694b622fe434 +Subproject commit cf367974b5e1513d454b2988d45122e98cd28f52 From fa1adbbac4b3c1312587440684729652f89b3b73 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 18 Mar 2017 17:55:39 -0400 Subject: [PATCH 360/413] Allow lua integer writes to accept anything that can be converted to an integer May address #1044 --- library/LuaTypes.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index f281afe86..5b5a174fa 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -122,10 +122,11 @@ void df::integer_identity_base::lua_read(lua_State *state, int fname_idx, void * void df::integer_identity_base::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) { - if (!lua_isinteger(state, val_index)) + int is_num = 0; + auto value = lua_tointegerx(state, val_index, &is_num); + if (!is_num) field_error(state, fname_idx, "integer expected", "write"); - - write(ptr, lua_tointeger(state, val_index)); + write(ptr, value); } void df::float_identity_base::lua_read(lua_State *state, int fname_idx, void *ptr) From aea76b7ef3c895f36a90ac7d64e7b592a3612ba5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 18 Mar 2017 17:56:06 -0400 Subject: [PATCH 361/413] stockflow: make sure that manager order amounts are integers Fixes #1044 --- plugins/lua/stockflow.lua | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/plugins/lua/stockflow.lua b/plugins/lua/stockflow.lua index dd83e65d9..fcaca0ecd 100644 --- a/plugins/lua/stockflow.lua +++ b/plugins/lua/stockflow.lua @@ -140,12 +140,12 @@ function collect_orders() stockpile = stockpile, entry = entry, } - + found = true break end end - + if not found then print("Unmatched stockflow entry for stockpile #"..stockpile.stockpile_number..": "..entry.value.." ("..order_number..")") end @@ -174,7 +174,7 @@ function reaction_entry(reactions, job_type, values, name) -- We could warn about it; in any case, don't add it to the list. return end - + local order = df.manager_order:new() -- These defaults differ from the newly created order's. order:assign{ @@ -420,7 +420,7 @@ function collect_reactions() local name = string.gsub(reaction.name, "^.", string.upper) reaction_entry(result, job_types.CustomReaction, {reaction_name = reaction.code}, name) end - + -- Reactions generated by the game. for _, reaction in ipairs(df.global.world.raws.reactions) do if reaction.source_enid == entity.id then @@ -751,7 +751,7 @@ function collect_reactions() {job_types.MakeBracelet, "Make", "Bracelet"}, {job_types.MakeEarring, "Make", "Earring"}, }, mat) - + if not mat.cloth then material_reactions(result, { {job_types.MakeCrown, "Make", "Crown"}, @@ -759,7 +759,7 @@ function collect_reactions() {job_types.MakeRing, "Make", "Ring"}, {job_types.MakeGem, "Make Large", "Gem"}, }, mat) - + if not mat.short then material_reactions(result, { {job_types.MakeScepter, "Make", "Scepter"}, @@ -798,29 +798,29 @@ screen = gui.FramedScreen { function screen:onRenderBody(dc) -- Emulates the built-in manager screen. - + if not (self.page_size == self.frame_rect.height - ExtraLines) then -- The screen size has changed. self:refilter() end - + -- Top instruction line. dc:seek(1, 1):string("Type in parts of the name to narrow your search. ", COLOR_WHITE) dc:key("LEAVESCREEN"):string(" to abort.", COLOR_WHITE) - + -- Search term, if any. dc:seek(1, FirstRow + self.page_size + 1):string(self.search_string, COLOR_LIGHTCYAN) - + -- Bottom instruction line. dc:seek(1, FirstRow + self.page_size + 2) dc:key("STANDARDSCROLL_UP"):key("STANDARDSCROLL_DOWN") dc:key("STANDARDSCROLL_PAGEUP"):key("STANDARDSCROLL_PAGEDOWN") dc:key("STANDARDSCROLL_LEFT"):key("STANDARDSCROLL_RIGHT") dc:string(": Select", COLOR_WHITE) - + dc:seek(CenterCol, FirstRow + self.page_size + 2) dc:key("SETUPGAME_SAVE_PROFILE_ABORT"):string(": No order", COLOR_WHITE) - + -- Reaction lines. for _, item in ipairs(self.displayed) do dc:seek(item.x, item.y):string(item.name, item.color) @@ -954,7 +954,7 @@ function screen:refilter() -- * Yellow: At least one word starts with at least one search term -- * Grey: Each search term is found in the middle of a word self.page_size = self.frame_rect.height - ExtraLines - + local filtered = {} local needles = splitstring(self.search_string, " ") for key, value in ipairs(reaction_list) do @@ -1094,6 +1094,7 @@ end -- Place a new copy of the order onto the manager's queue. function create_orders(order, amount) local new_order = order:new() + amount = math.floor(amount) new_order.amount_left = amount new_order.amount_total = amount -- Todo: Create in a validated state if the fortress is small enough? From 5ea964b9cf15c970d09dd9b05bdd40e83b93b287 Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 25 Mar 2017 22:23:40 +0530 Subject: [PATCH 362/413] Send building items with buildings. --- plugins/proto/RemoteFortressReader.proto | 7 + plugins/remotefortressreader/CMakeLists.txt | 3 +- .../remotefortressreader/building_reader.cpp | 529 ++++++++++++++++++ .../remotefortressreader/building_reader.h | 9 + .../remotefortressreader.cpp | 527 +---------------- 5 files changed, 554 insertions(+), 521 deletions(-) create mode 100644 plugins/remotefortressreader/building_reader.cpp create mode 100644 plugins/remotefortressreader/building_reader.h diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index af25c9a4b..d8a0b0a61 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -150,6 +150,12 @@ message BuildingExtents repeated int32 extents = 5; } +message BuildingItem +{ + optional Item item = 1; + optional int32 mode = 2; +} + message BuildingInstance { required int32 index = 1; @@ -165,6 +171,7 @@ message BuildingInstance optional bool is_room = 11; optional BuildingExtents room = 12; optional BuildingDirection direction = 13; //Doesn't mean anything for most buildings + repeated BuildingItem items = 14; } message RiverEdge diff --git a/plugins/remotefortressreader/CMakeLists.txt b/plugins/remotefortressreader/CMakeLists.txt index 0b84d8905..b9f120059 100644 --- a/plugins/remotefortressreader/CMakeLists.txt +++ b/plugins/remotefortressreader/CMakeLists.txt @@ -2,10 +2,11 @@ PROJECT (remotefortressreader) # A list of source files SET(PROJECT_SRCS remotefortressreader.cpp + building_reader.cpp ) # A list of headers SET(PROJECT_HDRS - + building_reader.h ) #proto files to include. SET(PROJECT_PROTO diff --git a/plugins/remotefortressreader/building_reader.cpp b/plugins/remotefortressreader/building_reader.cpp new file mode 100644 index 000000000..1a49a7c02 --- /dev/null +++ b/plugins/remotefortressreader/building_reader.cpp @@ -0,0 +1,529 @@ +#include "building_reader.h" +#include "DataDefs.h" + +#include "df/building_axle_horizontalst.h" +#include "df/building_bridgest.h" +#include "df/building_def_furnacest.h" +#include "df/building_def_workshopst.h" +#include "df/building_rollersst.h" +#include "df/building_screw_pumpst.h" +#include "df/building_siegeenginest.h" +#include "df/building_water_wheelst.h" +#include "df/building_wellst.h" +#include "df/building_windmillst.h" +#include "df/world.h" + + +#include "modules/Buildings.h" + + +using namespace DFHack; +using namespace df::enums; +using namespace RemoteFortressReader; +using namespace std; + +DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const DFHack::EmptyMessage *in, RemoteFortressReader::BuildingList *out) +{ + FOR_ENUM_ITEMS(building_type, bt) + { + BuildingDefinition * bld = out->add_building_list(); + bld->mutable_building_type()->set_building_type(bt); + bld->mutable_building_type()->set_building_subtype(-1); + bld->mutable_building_type()->set_building_custom(-1); + bld->set_id(ENUM_KEY_STR(building_type, bt)); + + switch (bt) + { + case df::enums::building_type::NONE: + break; + case df::enums::building_type::Chair: + break; + case df::enums::building_type::Bed: + break; + case df::enums::building_type::Table: + break; + case df::enums::building_type::Coffin: + break; + case df::enums::building_type::FarmPlot: + break; + case df::enums::building_type::Furnace: + FOR_ENUM_ITEMS(furnace_type, st) + { + bld = out->add_building_list(); + bld->mutable_building_type()->set_building_type(bt); + bld->mutable_building_type()->set_building_subtype(st); + bld->mutable_building_type()->set_building_custom(-1); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(furnace_type, st)); + + if (st == furnace_type::Custom) + { + for (int i = 0; i < df::global::world->raws.buildings.furnaces.size(); i++) + { + auto cust = df::global::world->raws.buildings.furnaces[i]; + + bld = out->add_building_list(); + bld->mutable_building_type()->set_building_type(bt); + bld->mutable_building_type()->set_building_subtype(st); + bld->mutable_building_type()->set_building_custom(cust->id); + bld->set_id(cust->code); + bld->set_name(cust->name); + } + } + } + break; + case df::enums::building_type::TradeDepot: + break; + case df::enums::building_type::Shop: + FOR_ENUM_ITEMS(shop_type, st) + { + bld = out->add_building_list(); + bld->mutable_building_type()->set_building_type(bt); + bld->mutable_building_type()->set_building_subtype(st); + bld->mutable_building_type()->set_building_custom(-1); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(shop_type, st)); + + } + break; + case df::enums::building_type::Door: + break; + case df::enums::building_type::Floodgate: + break; + case df::enums::building_type::Box: + break; + case df::enums::building_type::Weaponrack: + break; + case df::enums::building_type::Armorstand: + break; + case df::enums::building_type::Workshop: + FOR_ENUM_ITEMS(workshop_type, st) + { + bld = out->add_building_list(); + bld->mutable_building_type()->set_building_type(bt); + bld->mutable_building_type()->set_building_subtype(st); + bld->mutable_building_type()->set_building_custom(-1); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(workshop_type, st)); + + if (st == workshop_type::Custom) + { + for (int i = 0; i < df::global::world->raws.buildings.workshops.size(); i++) + { + auto cust = df::global::world->raws.buildings.workshops[i]; + + bld = out->add_building_list(); + bld->mutable_building_type()->set_building_type(bt); + bld->mutable_building_type()->set_building_subtype(st); + bld->mutable_building_type()->set_building_custom(cust->id); + bld->set_id(cust->code); + bld->set_name(cust->name); + } + } + } + break; + case df::enums::building_type::Cabinet: + break; + case df::enums::building_type::Statue: + break; + case df::enums::building_type::WindowGlass: + break; + case df::enums::building_type::WindowGem: + break; + case df::enums::building_type::Well: + break; + case df::enums::building_type::Bridge: + break; + case df::enums::building_type::RoadDirt: + break; + case df::enums::building_type::RoadPaved: + break; + case df::enums::building_type::SiegeEngine: + FOR_ENUM_ITEMS(siegeengine_type, st) + { + bld = out->add_building_list(); + bld->mutable_building_type()->set_building_type(bt); + bld->mutable_building_type()->set_building_subtype(st); + bld->mutable_building_type()->set_building_custom(-1); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(siegeengine_type, st)); + + } + break; + case df::enums::building_type::Trap: + FOR_ENUM_ITEMS(trap_type, st) + { + bld = out->add_building_list(); + bld->mutable_building_type()->set_building_type(bt); + bld->mutable_building_type()->set_building_subtype(st); + bld->mutable_building_type()->set_building_custom(-1); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(trap_type, st)); + + } + break; + case df::enums::building_type::AnimalTrap: + break; + case df::enums::building_type::Support: + break; + case df::enums::building_type::ArcheryTarget: + break; + case df::enums::building_type::Chain: + break; + case df::enums::building_type::Cage: + break; + case df::enums::building_type::Stockpile: + break; + case df::enums::building_type::Civzone: + FOR_ENUM_ITEMS(civzone_type, st) + { + bld = out->add_building_list(); + bld->mutable_building_type()->set_building_type(bt); + bld->mutable_building_type()->set_building_subtype(st); + bld->mutable_building_type()->set_building_custom(-1); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(civzone_type, st)); + + } + break; + case df::enums::building_type::Weapon: + break; + case df::enums::building_type::Wagon: + break; + case df::enums::building_type::ScrewPump: + break; + case df::enums::building_type::Construction: + FOR_ENUM_ITEMS(construction_type, st) + { + bld = out->add_building_list(); + bld->mutable_building_type()->set_building_type(bt); + bld->mutable_building_type()->set_building_subtype(st); + bld->mutable_building_type()->set_building_custom(-1); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(construction_type, st)); + + } + break; + case df::enums::building_type::Hatch: + break; + case df::enums::building_type::GrateWall: + break; + case df::enums::building_type::GrateFloor: + break; + case df::enums::building_type::BarsVertical: + break; + case df::enums::building_type::BarsFloor: + break; + case df::enums::building_type::GearAssembly: + break; + case df::enums::building_type::AxleHorizontal: + break; + case df::enums::building_type::AxleVertical: + break; + case df::enums::building_type::WaterWheel: + break; + case df::enums::building_type::Windmill: + break; + case df::enums::building_type::TractionBench: + break; + case df::enums::building_type::Slab: + break; + case df::enums::building_type::Nest: + break; + case df::enums::building_type::NestBox: + break; + case df::enums::building_type::Hive: + break; + case df::enums::building_type::Rollers: + break; + default: + break; + } + } + return CR_OK; +} + + +void CopyBuilding(int buildingIndex, RemoteFortressReader::BuildingInstance * remote_build) +{ + df::building * local_build = df::global::world->buildings.all[buildingIndex]; + remote_build->set_index(buildingIndex); + int minZ = local_build->z; + if (local_build->getType() == df::enums::building_type::Well) + { + df::building_wellst * well_building = virtual_cast(local_build); + if (well_building) + minZ = well_building->bucket_z; + } + remote_build->set_pos_x_min(local_build->x1); + remote_build->set_pos_y_min(local_build->y1); + remote_build->set_pos_z_min(minZ); + + remote_build->set_pos_x_max(local_build->x2); + remote_build->set_pos_y_max(local_build->y2); + remote_build->set_pos_z_max(local_build->z); + + auto buildingType = remote_build->mutable_building_type(); + auto type = local_build->getType(); + buildingType->set_building_type(type); + buildingType->set_building_subtype(local_build->getSubtype()); + buildingType->set_building_custom(local_build->getCustomType()); + + auto material = remote_build->mutable_material(); + material->set_mat_type(local_build->mat_type); + material->set_mat_index(local_build->mat_index); + + remote_build->set_building_flags(local_build->flags.whole); + remote_build->set_is_room(local_build->is_room); + if (local_build->is_room || local_build->getType() == df::enums::building_type::Civzone || local_build->getType() == df::enums::building_type::Stockpile) + { + auto room = remote_build->mutable_room(); + room->set_pos_x(local_build->room.x); + room->set_pos_y(local_build->room.y); + room->set_width(local_build->room.width); + room->set_height(local_build->room.height); + for (int i = 0; i < (local_build->room.width * local_build->room.height); i++) + { + room->add_extents(local_build->room.extents[i]); + } + } + + + switch (type) + { + case df::enums::building_type::NONE: + break; + case df::enums::building_type::Chair: + break; + case df::enums::building_type::Bed: + break; + case df::enums::building_type::Table: + break; + case df::enums::building_type::Coffin: + break; + case df::enums::building_type::FarmPlot: + break; + case df::enums::building_type::Furnace: + break; + case df::enums::building_type::TradeDepot: + break; + case df::enums::building_type::Shop: + break; + case df::enums::building_type::Door: + break; + case df::enums::building_type::Floodgate: + break; + case df::enums::building_type::Box: + break; + case df::enums::building_type::Weaponrack: + break; + case df::enums::building_type::Armorstand: + break; + case df::enums::building_type::Workshop: + break; + case df::enums::building_type::Cabinet: + break; + case df::enums::building_type::Statue: + break; + case df::enums::building_type::WindowGlass: + break; + case df::enums::building_type::WindowGem: + break; + case df::enums::building_type::Well: + break; + case df::enums::building_type::Bridge: + { + auto actual = strict_virtual_cast(local_build); + if (actual) + { + auto direction = actual->direction; + switch (direction) + { + case df::building_bridgest::Retracting: + break; + case df::building_bridgest::Left: + remote_build->set_direction(WEST); + break; + case df::building_bridgest::Right: + remote_build->set_direction(EAST); + break; + case df::building_bridgest::Up: + remote_build->set_direction(NORTH); + break; + case df::building_bridgest::Down: + remote_build->set_direction(SOUTH); + break; + default: + break; + } + } + } + break; + case df::enums::building_type::RoadDirt: + break; + case df::enums::building_type::RoadPaved: + break; + case df::enums::building_type::SiegeEngine: + { + auto actual = strict_virtual_cast(local_build); + if (actual) + { + auto facing = actual->facing; + switch (facing) + { + case df::building_siegeenginest::Left: + remote_build->set_direction(WEST); + break; + case df::building_siegeenginest::Up: + remote_build->set_direction(NORTH); + break; + case df::building_siegeenginest::Right: + remote_build->set_direction(EAST); + break; + case df::building_siegeenginest::Down: + remote_build->set_direction(SOUTH); + break; + default: + break; + } + } + } + break; + case df::enums::building_type::Trap: + break; + case df::enums::building_type::AnimalTrap: + break; + case df::enums::building_type::Support: + break; + case df::enums::building_type::ArcheryTarget: + break; + case df::enums::building_type::Chain: + break; + case df::enums::building_type::Cage: + break; + case df::enums::building_type::Stockpile: + break; + case df::enums::building_type::Civzone: + break; + case df::enums::building_type::Weapon: + break; + case df::enums::building_type::Wagon: + break; + case df::enums::building_type::ScrewPump: + { + auto actual = strict_virtual_cast(local_build); + if (actual) + { + auto direction = actual->direction; + switch (direction) + { + case df::enums::screw_pump_direction::FromNorth: + remote_build->set_direction(NORTH); + break; + case df::enums::screw_pump_direction::FromEast: + remote_build->set_direction(EAST); + break; + case df::enums::screw_pump_direction::FromSouth: + remote_build->set_direction(SOUTH); + break; + case df::enums::screw_pump_direction::FromWest: + remote_build->set_direction(WEST); + break; + default: + break; + } + } + } + break; + case df::enums::building_type::Construction: + break; + case df::enums::building_type::Hatch: + break; + case df::enums::building_type::GrateWall: + break; + case df::enums::building_type::GrateFloor: + break; + case df::enums::building_type::BarsVertical: + break; + case df::enums::building_type::BarsFloor: + break; + case df::enums::building_type::GearAssembly: + break; + case df::enums::building_type::AxleHorizontal: + { + auto actual = strict_virtual_cast(local_build); + if (actual) + { + if (actual->is_vertical) + remote_build->set_direction(NORTH); + else + remote_build->set_direction(EAST); + } + } + break; + case df::enums::building_type::AxleVertical: + break; + case df::enums::building_type::WaterWheel: + { + auto actual = strict_virtual_cast(local_build); + if (actual) + { + if (actual->is_vertical) + remote_build->set_direction(NORTH); + else + remote_build->set_direction(EAST); + } + } + break; + case df::enums::building_type::Windmill: + { + auto actual = strict_virtual_cast(local_build); + if (actual) + { + if (actual->orient_x < 0) + remote_build->set_direction(WEST); + else if (actual->orient_x > 0) + remote_build->set_direction(EAST); + else if (actual->orient_y < 0) + remote_build->set_direction(NORTH); + else if (actual->orient_y > 0) + remote_build->set_direction(SOUTH); + else + remote_build->set_direction(WEST); + } + } + break; + case df::enums::building_type::TractionBench: + break; + case df::enums::building_type::Slab: + break; + case df::enums::building_type::Nest: + break; + case df::enums::building_type::NestBox: + break; + case df::enums::building_type::Hive: + break; + case df::enums::building_type::Rollers: + { + auto actual = strict_virtual_cast(local_build); + if (actual) + { + auto direction = actual->direction; + switch (direction) + { + case df::enums::screw_pump_direction::FromNorth: + remote_build->set_direction(NORTH); + break; + case df::enums::screw_pump_direction::FromEast: + remote_build->set_direction(EAST); + break; + case df::enums::screw_pump_direction::FromSouth: + remote_build->set_direction(SOUTH); + break; + case df::enums::screw_pump_direction::FromWest: + remote_build->set_direction(WEST); + break; + default: + break; + } + } + } + break; + default: + break; + } +} + diff --git a/plugins/remotefortressreader/building_reader.h b/plugins/remotefortressreader/building_reader.h new file mode 100644 index 000000000..6b789359b --- /dev/null +++ b/plugins/remotefortressreader/building_reader.h @@ -0,0 +1,9 @@ +#ifndef BUILDING_READER_H +#define BUILDING_READER_H +#include "RemoteClient.h" +#include "RemoteFortressReader.pb.h" + +DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const DFHack::EmptyMessage *in, RemoteFortressReader::BuildingList *out); +void CopyBuilding(int buildingIndex, RemoteFortressReader::BuildingInstance * remote_build); + +#endif \ No newline at end of file diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 1f23cf0e1..8274b7db5 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -17,7 +17,6 @@ #include "SDL_keyboard.h" #include "TileTypes.h" -#include "modules/Buildings.h" #include "modules/Gui.h" #include "modules/Items.h" #include "modules/MapCache.h" @@ -35,17 +34,9 @@ #include "df/body_part_layer_raw.h" #include "df/body_part_raw.h" #include "df/bp_appearance_modifier.h" -#include "df/building_axle_horizontalst.h" -#include "df/building_bridgest.h" -#include "df/building_def_furnacest.h" -#include "df/building_def_workshopst.h" -#include "df/building_rollersst.h" -#include "df/building_screw_pumpst.h" -#include "df/building_siegeenginest.h" -#include "df/building_water_wheelst.h" -#include "df/building_wellst.h" -#include "df/building_windmillst.h" #include "df/builtin_mats.h" +#include "df/building_wellst.h" + #include "df/caste_raw.h" #include "df/caste_raw.h" #include "df/color_modifier_raw.h" @@ -105,6 +96,8 @@ #include "df/plant_tree_tile.h" #endif +#include "building_reader.h" + using namespace DFHack; using namespace df::enums; using namespace RemoteFortressReader; @@ -135,7 +128,6 @@ static command_result GetViewInfo(color_ostream &stream, const EmptyMessage *in, static command_result GetMapInfo(color_ostream &stream, const EmptyMessage *in, MapInfo *out); static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage *in); static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, MaterialList *out); -static command_result GetBuildingDefList(color_ostream &stream, const EmptyMessage *in, BuildingList *out); static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, WorldMap *out); static command_result GetWorldMapNew(color_ostream &stream, const EmptyMessage *in, WorldMap *out); static command_result GetWorldMapCenter(color_ostream &stream, const EmptyMessage *in, WorldMap *out); @@ -312,296 +304,6 @@ void ConvertDFColorDescriptor(int16_t index, RemoteFortressReader::ColorDefiniti out->set_blue(color->blue * 255); } -void CopyBuilding(int buildingIndex, RemoteFortressReader::BuildingInstance * remote_build) -{ - df::building * local_build = df::global::world->buildings.all[buildingIndex]; - remote_build->set_index(buildingIndex); - int minZ = local_build->z; - if (local_build->getType() == df::enums::building_type::Well) - { - df::building_wellst * well_building = virtual_cast(local_build); - if (well_building) - minZ = well_building->bucket_z; - } - remote_build->set_pos_x_min(local_build->x1); - remote_build->set_pos_y_min(local_build->y1); - remote_build->set_pos_z_min(minZ); - - remote_build->set_pos_x_max(local_build->x2); - remote_build->set_pos_y_max(local_build->y2); - remote_build->set_pos_z_max(local_build->z); - - auto buildingType = remote_build->mutable_building_type(); - auto type = local_build->getType(); - buildingType->set_building_type(type); - buildingType->set_building_subtype(local_build->getSubtype()); - buildingType->set_building_custom(local_build->getCustomType()); - - auto material = remote_build->mutable_material(); - material->set_mat_type(local_build->mat_type); - material->set_mat_index(local_build->mat_index); - - remote_build->set_building_flags(local_build->flags.whole); - remote_build->set_is_room(local_build->is_room); - if (local_build->is_room || local_build->getType() == df::enums::building_type::Civzone || local_build->getType() == df::enums::building_type::Stockpile) - { - auto room = remote_build->mutable_room(); - room->set_pos_x(local_build->room.x); - room->set_pos_y(local_build->room.y); - room->set_width(local_build->room.width); - room->set_height(local_build->room.height); - for (int i = 0; i < (local_build->room.width * local_build->room.height); i++) - { - room->add_extents(local_build->room.extents[i]); - } - } - - - switch (type) - { - case df::enums::building_type::NONE: - break; - case df::enums::building_type::Chair: - break; - case df::enums::building_type::Bed: - break; - case df::enums::building_type::Table: - break; - case df::enums::building_type::Coffin: - break; - case df::enums::building_type::FarmPlot: - break; - case df::enums::building_type::Furnace: - break; - case df::enums::building_type::TradeDepot: - break; - case df::enums::building_type::Shop: - break; - case df::enums::building_type::Door: - break; - case df::enums::building_type::Floodgate: - break; - case df::enums::building_type::Box: - break; - case df::enums::building_type::Weaponrack: - break; - case df::enums::building_type::Armorstand: - break; - case df::enums::building_type::Workshop: - break; - case df::enums::building_type::Cabinet: - break; - case df::enums::building_type::Statue: - break; - case df::enums::building_type::WindowGlass: - break; - case df::enums::building_type::WindowGem: - break; - case df::enums::building_type::Well: - break; - case df::enums::building_type::Bridge: - { - auto actual = strict_virtual_cast(local_build); - if (actual) - { - auto direction = actual->direction; - switch (direction) - { - case df::building_bridgest::Retracting: - break; - case df::building_bridgest::Left: - remote_build->set_direction(WEST); - break; - case df::building_bridgest::Right: - remote_build->set_direction(EAST); - break; - case df::building_bridgest::Up: - remote_build->set_direction(NORTH); - break; - case df::building_bridgest::Down: - remote_build->set_direction(SOUTH); - break; - default: - break; - } - } - } - break; - case df::enums::building_type::RoadDirt: - break; - case df::enums::building_type::RoadPaved: - break; - case df::enums::building_type::SiegeEngine: - { - auto actual = strict_virtual_cast(local_build); - if (actual) - { - auto facing = actual->facing; - switch (facing) - { - case df::building_siegeenginest::Left: - remote_build->set_direction(WEST); - break; - case df::building_siegeenginest::Up: - remote_build->set_direction(NORTH); - break; - case df::building_siegeenginest::Right: - remote_build->set_direction(EAST); - break; - case df::building_siegeenginest::Down: - remote_build->set_direction(SOUTH); - break; - default: - break; - } - } - } - break; - case df::enums::building_type::Trap: - break; - case df::enums::building_type::AnimalTrap: - break; - case df::enums::building_type::Support: - break; - case df::enums::building_type::ArcheryTarget: - break; - case df::enums::building_type::Chain: - break; - case df::enums::building_type::Cage: - break; - case df::enums::building_type::Stockpile: - break; - case df::enums::building_type::Civzone: - break; - case df::enums::building_type::Weapon: - break; - case df::enums::building_type::Wagon: - break; - case df::enums::building_type::ScrewPump: - { - auto actual = strict_virtual_cast(local_build); - if (actual) - { - auto direction = actual->direction; - switch (direction) - { - case df::enums::screw_pump_direction::FromNorth: - remote_build->set_direction(NORTH); - break; - case df::enums::screw_pump_direction::FromEast: - remote_build->set_direction(EAST); - break; - case df::enums::screw_pump_direction::FromSouth: - remote_build->set_direction(SOUTH); - break; - case df::enums::screw_pump_direction::FromWest: - remote_build->set_direction(WEST); - break; - default: - break; - } - } - } - break; - case df::enums::building_type::Construction: - break; - case df::enums::building_type::Hatch: - break; - case df::enums::building_type::GrateWall: - break; - case df::enums::building_type::GrateFloor: - break; - case df::enums::building_type::BarsVertical: - break; - case df::enums::building_type::BarsFloor: - break; - case df::enums::building_type::GearAssembly: - break; - case df::enums::building_type::AxleHorizontal: - { - auto actual = strict_virtual_cast(local_build); - if (actual) - { - if(actual->is_vertical) - remote_build->set_direction(NORTH); - else - remote_build->set_direction(EAST); - } - } - break; - case df::enums::building_type::AxleVertical: - break; - case df::enums::building_type::WaterWheel: - { - auto actual = strict_virtual_cast(local_build); - if (actual) - { - if (actual->is_vertical) - remote_build->set_direction(NORTH); - else - remote_build->set_direction(EAST); - } - } - break; - case df::enums::building_type::Windmill: - { - auto actual = strict_virtual_cast(local_build); - if (actual) - { - if (actual->orient_x < 0) - remote_build->set_direction(WEST); - else if (actual->orient_x > 0) - remote_build->set_direction(EAST); - else if (actual->orient_y < 0) - remote_build->set_direction(NORTH); - else if (actual->orient_y > 0) - remote_build->set_direction(SOUTH); - else - remote_build->set_direction(WEST); - } - } - break; - case df::enums::building_type::TractionBench: - break; - case df::enums::building_type::Slab: - break; - case df::enums::building_type::Nest: - break; - case df::enums::building_type::NestBox: - break; - case df::enums::building_type::Hive: - break; - case df::enums::building_type::Rollers: - { - auto actual = strict_virtual_cast(local_build); - if (actual) - { - auto direction = actual->direction; - switch (direction) - { - case df::enums::screw_pump_direction::FromNorth: - remote_build->set_direction(NORTH); - break; - case df::enums::screw_pump_direction::FromEast: - remote_build->set_direction(EAST); - break; - case df::enums::screw_pump_direction::FromSouth: - remote_build->set_direction(SOUTH); - break; - case df::enums::screw_pump_direction::FromWest: - remote_build->set_direction(WEST); - break; - default: - break; - } - } - } - break; - default: - break; - } -} - RemoteFortressReader::TiletypeMaterial TranslateMaterial(df::tiletype_material material) { switch (material) @@ -1469,10 +1171,9 @@ void CopyBuildings(df::map_block * DfBlock, RemoteFortressReader::MapBlock * Net { for (int i = 0; i < actualBuilding->contained_items.size(); i++) { - if (isItemChanged(actualBuilding->contained_items[i]->item->id)) - { - CopyItem(NetBlock->add_items(), actualBuilding->contained_items[i]->item); - } + auto buildingItem = out_bld->add_items(); + buildingItem->set_mode(actualBuilding->contained_items[i]->use_mode); + CopyItem(buildingItem->mutable_item(), actualBuilding->contained_items[i]->item); } } } @@ -1869,220 +1570,6 @@ static command_result GetMapInfo(color_ostream &stream, const EmptyMessage *in, return CR_OK; } -static command_result GetBuildingDefList(color_ostream &stream, const EmptyMessage *in, BuildingList *out) -{ - FOR_ENUM_ITEMS(building_type, bt) - { - BuildingDefinition * bld = out->add_building_list(); - bld->mutable_building_type()->set_building_type(bt); - bld->mutable_building_type()->set_building_subtype(-1); - bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt)); - - switch (bt) - { - case df::enums::building_type::NONE: - break; - case df::enums::building_type::Chair: - break; - case df::enums::building_type::Bed: - break; - case df::enums::building_type::Table: - break; - case df::enums::building_type::Coffin: - break; - case df::enums::building_type::FarmPlot: - break; - case df::enums::building_type::Furnace: - FOR_ENUM_ITEMS(furnace_type, st) - { - bld = out->add_building_list(); - bld->mutable_building_type()->set_building_type(bt); - bld->mutable_building_type()->set_building_subtype(st); - bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(furnace_type, st)); - - if (st == furnace_type::Custom) - { - for (int i = 0; i < world->raws.buildings.furnaces.size(); i++) - { - auto cust = world->raws.buildings.furnaces[i]; - - bld = out->add_building_list(); - bld->mutable_building_type()->set_building_type(bt); - bld->mutable_building_type()->set_building_subtype(st); - bld->mutable_building_type()->set_building_custom(cust->id); - bld->set_id(cust->code); - bld->set_name(cust->name); - } - } - } - break; - case df::enums::building_type::TradeDepot: - break; - case df::enums::building_type::Shop: - FOR_ENUM_ITEMS(shop_type, st) - { - bld = out->add_building_list(); - bld->mutable_building_type()->set_building_type(bt); - bld->mutable_building_type()->set_building_subtype(st); - bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(shop_type, st)); - - } - break; - case df::enums::building_type::Door: - break; - case df::enums::building_type::Floodgate: - break; - case df::enums::building_type::Box: - break; - case df::enums::building_type::Weaponrack: - break; - case df::enums::building_type::Armorstand: - break; - case df::enums::building_type::Workshop: - FOR_ENUM_ITEMS(workshop_type, st) - { - bld = out->add_building_list(); - bld->mutable_building_type()->set_building_type(bt); - bld->mutable_building_type()->set_building_subtype(st); - bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(workshop_type, st)); - - if (st == workshop_type::Custom) - { - for (int i = 0; i < world->raws.buildings.workshops.size(); i++) - { - auto cust = world->raws.buildings.workshops[i]; - - bld = out->add_building_list(); - bld->mutable_building_type()->set_building_type(bt); - bld->mutable_building_type()->set_building_subtype(st); - bld->mutable_building_type()->set_building_custom(cust->id); - bld->set_id(cust->code); - bld->set_name(cust->name); - } - } - } - break; - case df::enums::building_type::Cabinet: - break; - case df::enums::building_type::Statue: - break; - case df::enums::building_type::WindowGlass: - break; - case df::enums::building_type::WindowGem: - break; - case df::enums::building_type::Well: - break; - case df::enums::building_type::Bridge: - break; - case df::enums::building_type::RoadDirt: - break; - case df::enums::building_type::RoadPaved: - break; - case df::enums::building_type::SiegeEngine: - FOR_ENUM_ITEMS(siegeengine_type, st) - { - bld = out->add_building_list(); - bld->mutable_building_type()->set_building_type(bt); - bld->mutable_building_type()->set_building_subtype(st); - bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(siegeengine_type, st)); - - } - break; - case df::enums::building_type::Trap: - FOR_ENUM_ITEMS(trap_type, st) - { - bld = out->add_building_list(); - bld->mutable_building_type()->set_building_type(bt); - bld->mutable_building_type()->set_building_subtype(st); - bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(trap_type, st)); - - } - break; - case df::enums::building_type::AnimalTrap: - break; - case df::enums::building_type::Support: - break; - case df::enums::building_type::ArcheryTarget: - break; - case df::enums::building_type::Chain: - break; - case df::enums::building_type::Cage: - break; - case df::enums::building_type::Stockpile: - break; - case df::enums::building_type::Civzone: - FOR_ENUM_ITEMS(civzone_type, st) - { - bld = out->add_building_list(); - bld->mutable_building_type()->set_building_type(bt); - bld->mutable_building_type()->set_building_subtype(st); - bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(civzone_type, st)); - - } - break; - case df::enums::building_type::Weapon: - break; - case df::enums::building_type::Wagon: - break; - case df::enums::building_type::ScrewPump: - break; - case df::enums::building_type::Construction: - FOR_ENUM_ITEMS(construction_type, st) - { - bld = out->add_building_list(); - bld->mutable_building_type()->set_building_type(bt); - bld->mutable_building_type()->set_building_subtype(st); - bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(construction_type, st)); - - } - break; - case df::enums::building_type::Hatch: - break; - case df::enums::building_type::GrateWall: - break; - case df::enums::building_type::GrateFloor: - break; - case df::enums::building_type::BarsVertical: - break; - case df::enums::building_type::BarsFloor: - break; - case df::enums::building_type::GearAssembly: - break; - case df::enums::building_type::AxleHorizontal: - break; - case df::enums::building_type::AxleVertical: - break; - case df::enums::building_type::WaterWheel: - break; - case df::enums::building_type::Windmill: - break; - case df::enums::building_type::TractionBench: - break; - case df::enums::building_type::Slab: - break; - case df::enums::building_type::Nest: - break; - case df::enums::building_type::NestBox: - break; - case df::enums::building_type::Hive: - break; - case df::enums::building_type::Rollers: - break; - default: - break; - } - } - return CR_OK; -} - DFCoord GetMapCenter() { DFCoord output; From 78cb4a31b906102cece7a2f55fccab0a35bc0d7d Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 28 Mar 2017 09:50:38 -0400 Subject: [PATCH 363/413] New tweak: condition-material (fixes bug 9905) http://www.bay12games.com/dwarves/mantisbt/view.php?id=9905 --- dfhack.init-example | 3 + docs/Plugins.rst | 1 + library/xml | 2 +- plugins/tweak/tweak.cpp | 5 + plugins/tweak/tweaks/condition-material.h | 134 ++++++++++++++++++++++ 5 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 plugins/tweak/tweaks/condition-material.h diff --git a/dfhack.init-example b/dfhack.init-example index 169d40046..f8878ea0a 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -181,6 +181,9 @@ tweak farm-plot-select # Add Shift-Left/Right controls to import agreement screen tweak import-priority-category +# Fixes a crash in the work order contition material list (bug 9905). +tweak condition-material + # Misc. UI tweaks tweak block-labors # Prevents labors that can't be used from being toggled tweak civ-view-agreement diff --git a/docs/Plugins.rst b/docs/Plugins.rst index e2b829020..c81b284c3 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -272,6 +272,7 @@ Subcommands that persist until disabled or DF quits: reagents. :block-labors: Prevents labors that can't be used from being toggled :civ-view-agreement: Fixes overlapping text on the "view agreement" screen +:condition-material: Fixes a crash in the work order contition material list (:bug:`9905`). :craft-age-wear: Fixes the behavior of crafted items wearing out over time (:bug:`6003`). With this tweak, items made from cloth and leather will gain a level of wear every 20 years. diff --git a/library/xml b/library/xml index 8727ebd74..9b834c089 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 8727ebd74a3f5d90e34a08266a3719e0cd5817d9 +Subproject commit 9b834c089efb4657d43a8fa4f8f0822e8224e576 diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index 88c57fb62..1bab3ebcf 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -81,6 +81,7 @@ #include "tweaks/advmode-contained.h" #include "tweaks/block-labors.h" #include "tweaks/civ-agreement-ui.h" +#include "tweaks/condition-material.h" #include "tweaks/craft-age-wear.h" #include "tweaks/eggs-fertile.h" #include "tweaks/embark-profile-name.h" @@ -183,6 +184,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector list_entries; + std::vector list_unk1; + std::vector list_unk2; + std::vector list_unk3; + std::vector list_visible; + }; + + static std::map order_mat_data; + + static void register_screen(T_screen *scr) + { + if (order_mat_data.find(scr) != order_mat_data.end()) + { + unregister_screen(scr); + } + auto data = new T_order_mat_data; + data->list_entries = scr->list_entries; + data->list_unk1 = scr->list_unk1; + data->list_unk2 = scr->list_unk2; + data->list_unk3 = scr->list_unk3; + data->list_visible = scr->list_visible; + order_mat_data[scr] = data; + } + + static void unregister_screen(T_screen *scr) + { + if (order_mat_data.find(scr) != order_mat_data.end() && order_mat_data[scr]) + { + T_order_mat_data *data = order_mat_data[scr]; + scr->list_entries = data->list_entries; + scr->list_unk1 = data->list_unk1; + scr->list_unk2 = data->list_unk2; + scr->list_unk3 = data->list_unk3; + scr->list_visible = data->list_visible; + delete data; + order_mat_data.erase(scr); + } + } + + void apply_filter() + { + if (order_mat_data.find(this) != order_mat_data.end() && order_mat_data[this]) + { + list_idx = 0; + T_order_mat_data *data = order_mat_data[this]; + // keep the first item ("no material") around, because attempts to delete it + // result in it still being displayed first, regardless of list_entries[0] + list_entries.resize(1); + list_unk1.resize(1); + list_unk2.resize(1); + list_unk3.resize(1); + list_visible.resize(1); + // skip "no material" here + for (size_t i = 1; i < data->list_entries.size(); i++) + { + // cap it at 32767 elements to be safe + if (list_entries.size() >= INT16_MAX) + { + break; + } + std::string *s = data->list_entries[i]; + if (s->find(filter) != std::string::npos) + { + list_entries.push_back(data->list_entries[i]); + list_unk1.push_back(data->list_unk1[i]); + list_unk2.push_back(data->list_unk2[i]); + list_unk3.push_back(data->list_unk3[i]); + // this should be small enough to fit in an int16_t + list_visible.push_back(int16_t(list_entries.size() - 1)); + } + } + } + } + + DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set *input)) + { + using namespace df::enums::interface_key; + if (mode == T_mode::Material) + { + for (auto key : *input) + { + if (key == LEAVESCREEN || key == SELECT) + { + INTERPOSE_NEXT(feed)(input); + unregister_screen(this); + return; + } + else if (key == STANDARDSCROLL_UP || key == STANDARDSCROLL_DOWN || + key == STANDARDSCROLL_PAGEUP || key == STANDARDSCROLL_PAGEDOWN) + { + INTERPOSE_NEXT(feed)(input); + } + int ch = Screen::keyToChar(key); + if (ch != -1) + { + if (ch == 0) + { + if (!filter.empty()) + { + filter.erase(filter.size() - 1); + } + } + else + { + filter += tolower(char(ch)); + } + apply_filter(); + } + } + } + else + { + INTERPOSE_NEXT(feed)(input); + if (mode == T_mode::Material) + { + register_screen(this); + apply_filter(); + } + } + } +}; + +std::map condition_material_hook::order_mat_data; + +IMPLEMENT_VMETHOD_INTERPOSE(condition_material_hook, feed); From c244901c165b038abbe6d650aa5ca86076a90ad5 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 29 Mar 2017 20:22:09 +0530 Subject: [PATCH 364/413] Removed end of line space. (Sorry, travis) --- plugins/remotefortressreader/building_reader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/remotefortressreader/building_reader.cpp b/plugins/remotefortressreader/building_reader.cpp index 1a49a7c02..5d1ce6ffa 100644 --- a/plugins/remotefortressreader/building_reader.cpp +++ b/plugins/remotefortressreader/building_reader.cpp @@ -22,7 +22,7 @@ using namespace df::enums; using namespace RemoteFortressReader; using namespace std; -DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const DFHack::EmptyMessage *in, RemoteFortressReader::BuildingList *out) +DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const DFHack::EmptyMessage *in, RemoteFortressReader::BuildingList *out) { FOR_ENUM_ITEMS(building_type, bt) { From bbaf3210f159f213b59e9880f5659a714f4a9bd3 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 29 Mar 2017 21:58:12 +0530 Subject: [PATCH 365/413] Send DF version info over remoteFortressReader --- plugins/proto/RemoteFortressReader.proto | 7 +++++ .../remotefortressreader.cpp | 31 +++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index d8a0b0a61..d9bb581b3 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -764,3 +764,10 @@ message SingleBool { optional bool Value = 1; } + +message VersionInfo +{ + optional string dwarf_fortress_version = 1; + optional string dfhack_version = 2; + optional string remote_fortress_reader_version = 3; +} \ No newline at end of file diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 8274b7db5..b976ef644 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -1,4 +1,5 @@ -#define DF_VERSION 42004 +#define DF_VERSION_INT 42004 +#define RFR_VERSION "0.16.1" #include #include @@ -16,6 +17,7 @@ #include "SDL_events.h" #include "SDL_keyboard.h" #include "TileTypes.h" +#include "DFHackVersion.h" #include "modules/Gui.h" #include "modules/Items.h" @@ -89,7 +91,7 @@ #include "df/world_site_realization.h" #include "df/entity_position.h" -#if DF_VERSION > 40001 +#if DF_VERSION_INT > 40001 #include "df/plant_growth.h" #include "df/plant_growth_print.h" #include "df/plant_tree_info.h" @@ -140,6 +142,7 @@ static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEve static command_result SendDigCommand(color_ostream &stream, const DigCommand *in); static command_result SetPauseState(color_ostream & stream, const SingleBool * in); static command_result GetPauseState(color_ostream & stream, const EmptyMessage * in, SingleBool * out); +static command_result GetVersionInfo(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::VersionInfo * out); void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); @@ -377,7 +380,7 @@ RemoteFortressReader::TiletypeMaterial TranslateMaterial(df::tiletype_material m case df::enums::tiletype_material::RIVER: return RemoteFortressReader::RIVER; break; -#if DF_VERSION > 40001 +#if DF_VERSION_INT > 40001 case df::enums::tiletype_material::ROOT: return RemoteFortressReader::ROOT; break; @@ -438,7 +441,7 @@ RemoteFortressReader::TiletypeSpecial TranslateSpecial(df::tiletype_special spec case df::enums::tiletype_special::TRACK: return RemoteFortressReader::TRACK; break; -#if DF_VERSION > 40001 +#if DF_VERSION_INT > 40001 case df::enums::tiletype_special::SMOOTH_DEAD: return RemoteFortressReader::SMOOTH_DEAD; break; @@ -496,17 +499,17 @@ RemoteFortressReader::TiletypeShape TranslateShape(df::tiletype_shape shape) case df::enums::tiletype_shape::BROOK_TOP: return RemoteFortressReader::BROOK_TOP; break; -#if DF_VERSION > 40001 +#if DF_VERSION_INT > 40001 case df::enums::tiletype_shape::BRANCH: return RemoteFortressReader::BRANCH; break; #endif -#if DF_VERSION < 40001 +#if DF_VERSION_INT < 40001 case df::enums::tiletype_shape::TREE: return RemoteFortressReader::TREE_SHAPE; break; #endif -#if DF_VERSION > 40001 +#if DF_VERSION_INT > 40001 case df::enums::tiletype_shape::TRUNK_BRANCH: return RemoteFortressReader::TRUNK_BRANCH; @@ -898,7 +901,7 @@ static command_result GetGrowthList(color_ostream &stream, const EmptyMessage *i basePlant->set_name(pp->name); basePlant->mutable_mat_pair()->set_mat_type(-1); basePlant->mutable_mat_pair()->set_mat_index(i); -#if DF_VERSION > 40001 +#if DF_VERSION_INT > 40001 for (int g = 0; g < pp->growths.size(); g++) { df::plant_growth* growth = pp->growths[g]; @@ -1423,7 +1426,7 @@ static command_result GetPlantList(color_ostream &stream, const BlockRequest *in int max_y = in->max_y() / 3; int max_z = in->max_z(); -#if DF_VERSION < 40001 +#if DF_VERSION_INT < 40001 //plants are gotten differently here #else for (int xx = min_x; xx < max_x; xx++) @@ -2564,4 +2567,12 @@ static command_result GetPauseState(color_ostream &stream, const EmptyMessage *i { out->set_value(World::ReadPauseState()); return CR_OK; -} \ No newline at end of file +} + +command_result GetVersionInfo(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::VersionInfo * out) +{ + out->set_dfhack_version(DFHACK_VERSION); + out->set_dwarf_fortress_version(DF_VERSION); + out->set_remote_fortress_reader_version(RFR_VERSION); + return command_result(); +} From 7c626ba3c25494d08c10f0c4af183cb32c9acae3 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 29 Mar 2017 22:05:49 +0530 Subject: [PATCH 366/413] Actually add the versionInfo function to the RPC list. --- plugins/remotefortressreader/remotefortressreader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index b976ef644..866dd8d42 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -250,6 +250,7 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("SendDigCommand", SendDigCommand); svc->addFunction("SetPauseState", SetPauseState); svc->addFunction("GetPauseState", GetPauseState); + svc->addFunction("GetVersionInfo", GetVersionInfo); return svc; } From 06225dd896562901ecc275493aae81bda2e3c751 Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Thu, 30 Mar 2017 16:23:14 +0530 Subject: [PATCH 367/413] Send building items and items kept in buildings separately. --- .../remotefortressreader.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 866dd8d42..507bd5349 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -1170,14 +1170,22 @@ void CopyBuildings(df::map_block * DfBlock, RemoteFortressReader::MapBlock * Net continue; auto out_bld = NetBlock->add_buildings(); CopyBuilding(i, out_bld); - df::building_actual* actualBuilding = strict_virtual_cast(bld); + df::building_actual* actualBuilding = virtual_cast(bld); if (actualBuilding) { for (int i = 0; i < actualBuilding->contained_items.size(); i++) { - auto buildingItem = out_bld->add_items(); - buildingItem->set_mode(actualBuilding->contained_items[i]->use_mode); - CopyItem(buildingItem->mutable_item(), actualBuilding->contained_items[i]->item); + if (actualBuilding->contained_items[i]->use_mode == 0) + { + if (isItemChanged(actualBuilding->contained_items[i]->item->id)) + CopyItem(NetBlock->add_items(), actualBuilding->contained_items[i]->item); + } + else + { + auto buildingItem = out_bld->add_items(); + buildingItem->set_mode(actualBuilding->contained_items[i]->use_mode); + CopyItem(buildingItem->mutable_item(), actualBuilding->contained_items[i]->item); + } } } } From 9edfeb5b8c719782727fc13663411b420c93c246 Mon Sep 17 00:00:00 2001 From: Paul Fenwick Date: Mon, 27 Mar 2017 10:59:09 +1100 Subject: [PATCH 368/413] README.md: Fix broken markdown links and header. Github's markdown parser does not permit newlines between link titles and link text. This change removes the newlines, resulting in a less pleasing source, but one which renders when viewed on github. Github also requires a space between the '#' and text of headings, so we fix that, too. --- README.md | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 50769e0c5..c3d51c4d1 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,10 @@ -#DFHack Readme +# DFHack Readme -[![Build Status](https://travis-ci.org/DFHack/dfhack.svg?branch=develop)] -(https://travis-ci.org/DFHack/dfhack) -[![Documentation Status](https://readthedocs.org/projects/dfhack/badge)] -(https://dfhack.readthedocs.org) -[![License](https://img.shields.io/badge/license-ZLib-blue.svg)] -(https://en.wikipedia.org/wiki/Zlib_License) -[![Github Issues](http://githubbadges.herokuapp.com/DFHack/dfhack/issues)] -(https://github.com/DFHack/dfhack/issues) -[![Open Pulls](http://githubbadges.herokuapp.com/DFHack/dfhack/pulls)] -(https://github.com/DFHack/dfhack/pulls) +[![Build Status](https://travis-ci.org/DFHack/dfhack.svg?branch=develop)](https://travis-ci.org/DFHack/dfhack) +[![Documentation Status](https://readthedocs.org/projects/dfhack/badge)](https://dfhack.readthedocs.org) +[![License](https://img.shields.io/badge/license-ZLib-blue.svg)](https://en.wikipedia.org/wiki/Zlib_License) +[![Github Issues](http://githubbadges.herokuapp.com/DFHack/dfhack/issues)](https://github.com/DFHack/dfhack/issues) +[![Open Pulls](http://githubbadges.herokuapp.com/DFHack/dfhack/pulls)](https://github.com/DFHack/dfhack/pulls) DFHack is a Dwarf Fortress memory access library, distributed with scripts and plugins implementing a wide variety of useful functions and tools. @@ -19,6 +14,6 @@ from the README.html page in the DFHack distribution, or as raw text in the `./d If you're an end-user, modder, or interested in contributing to DFHack - go read those docs. -If that's unclear or you need more help, try [the Bay12 forums thread] -(http://www.bay12forums.com/smf/index.php?topic=139553) or the #dfhack IRC -channel on freenode. +If that's unclear or you need more help, try +[the Bay12 forums thread](http://www.bay12forums.com/smf/index.php?topic=139553) +or the #dfhack IRC channel on freenode. From 93a977bf5c5cdda5f2a1efeb2cb45fba9dc3e494 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 30 Mar 2017 23:57:55 -0400 Subject: [PATCH 369/413] Add @pjf to Authors.rst Ref #1074 --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index c606fbe38..39f2a0301 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -75,6 +75,7 @@ Nick Rart nickrart comestible Nikolay Amiantov abbradar nocico nocico Omniclasm +Paul Fenwick pjf PeridexisErrant PeridexisErrant Petr Mrázek peterix potato From e36e4fa1c16cdf9f0398a43e2be09ba8efb49daa Mon Sep 17 00:00:00 2001 From: Japa Illo Date: Wed, 5 Apr 2017 15:35:48 +0530 Subject: [PATCH 370/413] Support archery target rotation in RemoteFortressReader --- .../remotefortressreader/building_reader.cpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/plugins/remotefortressreader/building_reader.cpp b/plugins/remotefortressreader/building_reader.cpp index 5d1ce6ffa..4e31e0360 100644 --- a/plugins/remotefortressreader/building_reader.cpp +++ b/plugins/remotefortressreader/building_reader.cpp @@ -1,6 +1,7 @@ #include "building_reader.h" #include "DataDefs.h" +#include "df/building_archerytargetst.h" #include "df/building_axle_horizontalst.h" #include "df/building_bridgest.h" #include "df/building_def_furnacest.h" @@ -389,6 +390,30 @@ void CopyBuilding(int buildingIndex, RemoteFortressReader::BuildingInstance * re case df::enums::building_type::Support: break; case df::enums::building_type::ArcheryTarget: + { + auto actual = strict_virtual_cast(local_build); + if (actual) + { + auto facing = actual->archery_direction; + switch (facing) + { + case df::building_archerytargetst::TopToBottom: + remote_build->set_direction(NORTH); + break; + case df::building_archerytargetst::BottomToTop: + remote_build->set_direction(SOUTH); + break; + case df::building_archerytargetst::LeftToRight: + remote_build->set_direction(WEST); + break; + case df::building_archerytargetst::RightToLeft: + remote_build->set_direction(EAST); + break; + default: + break; + } + } + } break; case df::enums::building_type::Chain: break; From 06737644cdfb23445f0b98bc11783c0a1f36555b Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 19 Apr 2017 13:31:25 -0400 Subject: [PATCH 371/413] new tweak: hotkey-clear --- dfhack.init-example | 3 +++ docs/Plugins.rst | 1 + plugins/tweak/tweak.cpp | 6 +++++ plugins/tweak/tweaks/hotkey-clear.h | 41 +++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 plugins/tweak/tweaks/hotkey-clear.h diff --git a/dfhack.init-example b/dfhack.init-example index f8878ea0a..a6fd6ffba 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -184,6 +184,9 @@ tweak import-priority-category # Fixes a crash in the work order contition material list (bug 9905). tweak condition-material +# Adds an option to clear currently-bound hotkeys +tweak hotkey-clear + # Misc. UI tweaks tweak block-labors # Prevents labors that can't be used from being toggled tweak civ-view-agreement diff --git a/docs/Plugins.rst b/docs/Plugins.rst index c81b284c3..568688a53 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -287,6 +287,7 @@ Subcommands that persist until disabled or DF quits: the current item (fully, in case of a stack), and scroll down one line. :fps-min: Fixes the in-game minimum FPS setting :hide-priority: Adds an option to hide designation priority indicators +:hotkey-clear: Adds an option to clear currently-bound hotkeys (in the :kbd:`H` menu) :import-priority-category: Allows changing the priority of all goods in a category when discussing an import agreement with the liaison diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index 1bab3ebcf..a9ef091c7 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -90,6 +90,7 @@ #include "tweaks/fast-trade.h" #include "tweaks/fps-min.h" #include "tweaks/hide-priority.h" +#include "tweaks/hotkey-clear.h" #include "tweaks/import-priority-category.h" #include "tweaks/kitchen-keys.h" #include "tweaks/kitchen-prefs-color.h" @@ -205,6 +206,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector main.mode == df::ui_sidebar_mode::Hotkeys) + { + int x = 26, y = 19; + OutputHotkeyString(x, y, "Clear", df::interface_key::CUSTOM_C, false, 0, COLOR_WHITE, COLOR_LIGHTRED); + } + } + + DEFINE_VMETHOD_INTERPOSE(void, feed, (set *input)) + { + if (ui->main.mode == df::ui_sidebar_mode::Hotkeys && + input->count(df::interface_key::CUSTOM_C) && + !ui->main.in_rename_hotkey) + { + auto &hotkey = ui->main.hotkeys[ui->main.selected_hotkey]; + hotkey.name = ""; + hotkey.cmd = df::ui_hotkey::T_cmd::None; + hotkey.x = 0; + hotkey.y = 0; + hotkey.z = 0; + hotkey.unit_id = 0; + hotkey.item_id = 0; + } + else + { + INTERPOSE_NEXT(feed)(input); + } + } +}; + +IMPLEMENT_VMETHOD_INTERPOSE(hotkey_clear_hook, feed); +IMPLEMENT_VMETHOD_INTERPOSE(hotkey_clear_hook, render); From 6c616e349ca9b86fcbfe42fc624374162b628bba Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 23 Apr 2017 17:13:59 -0400 Subject: [PATCH 372/413] Update news --- NEWS.rst | 25 +++++++++++++++++++---- docs/NEWS-dev.rst | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 4229da17f..4c9b01f00 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -14,7 +14,7 @@ Internals Lua - New [Internal Commands | Plugins | Scripts | Features] + New [Internal Commands | Plugins | Scripts | Tweaks | Features] Fixes Misc Improvements Removed @@ -46,6 +46,7 @@ Internals - Several structure fixes to match 64-bit DF's memory layout - Added ``DFHack::Job::removeJob()`` function - Updated TinyXML from 2.5.3 to 2.6.2 +- Added the ability to download files manually before building Lua --- @@ -56,6 +57,7 @@ Lua - ``df.new()`` supports more types: ``char``, ``intptr_t``, ``uintptr_t``, ``long``, ``unsigned long`` - String representations of vectors and a few other containers now include their lengths - Added a ``tile-material`` module +- Added a ``Painter:key_string()`` method Ruby ---- @@ -71,33 +73,46 @@ New Plugins New Scripts ----------- +- `adv-rumors`: improves the "Bring up specific incident or rumor" menu in adventure mode - `fix/tile-occupancy`: Clears bad occupancy flags on the selected tile. +- `install-info`: Logs basic troubleshooting information about the current DFHack installation - `load-save`: loads a save non-interactively - `modtools/change-build-menu`: Edit the build mode sidebar menus - `modtools/if-entity`: Run a command if the current entity matches a given ID - `season-palette`: Swap color palettes with the changes of the seasons +New Tweaks +---------- +- `tweak condition-material `: fixes a crash in the work order condition material list +- `tweak hotkey-clear `: adds an option to clear bindings from DF hotkeys + Fixes ----- - The DF path on OS X can now contain spaces and ``:`` characters - Buildings::setOwner() changes now persist properly when saved - ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable +- Fixed ``plug`` output alignment for plugins with long names - `add-thought`: fixed support for emotion names -- `autofarm`: Made surface farms detect local biome - `devel/find-offsets`: fixed a crash when vtables used by globals aren't available - `manipulator`: - Fixed crash when selecting a profession from an empty list - Custom professions are now sorted alphabetically more reliably -- `modtools/create-unit`: stopped permanently overwriting the creature creation - menu in arena mode +- `modtools/create-unit`: + + - stopped permanently overwriting the creature creation menu in arena mode + - now uses non-English names + +- `modtools/item-trigger`: fixed errors with plant growths +- `remotefortressreader`: fixed a crash when serializing the local map - `title-version`: now hidden when loading an arena Misc Improvements ----------------- - Documented all default keybindings (from :file:`dfhack.init-example`) in the docs for the relevant commands; updates enforced by build system. +- `gui/extended-status`: added a feature to queue beds - `lua` and `gui/gm-editor` now support the same aliases (``scr``, ``unit``, etc.) - `remotefortressreader`: Added support for @@ -106,6 +121,8 @@ Misc Improvements - wall info - site towers, world buildings - surface material + - building items + - DF version info - `title-version`: Added a prerelease indicator diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index df74735c0..2be774672 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -37,6 +37,57 @@ Development Changelog .. contents:: :depth: 2 +DFHack 0.43.05-beta2 +==================== + +Fixes +----- +- Fixed Buildings::updateBuildings(), along with building creation/deletion events +- Fixed ``plug`` output alignment for plugins with long names +- Fixed a crash that happened when a ``LUA_PATH`` environment variable was set +- `add-thought`: fixed number conversion +- `gui/workflow`: fixed range editing producing the wrong results for certain numbers +- `modtools/create-unit`: now uses non-English names +- `modtools/item-trigger`: fixed errors with plant growths +- `remotefortressreader`: fixed a crash when serializing the local map +- `stockflow`: fixed an issue with non-integer manager order limits +- `title-folder`: fixed compatibility issues with certain SDL libraries on macOS + +Structures +---------- +- Added some missing renderer VTable addresses on macOS +- ``entity.resources.organic``: identified ``parchment`` +- ``entity_sell_category``: added ``Parchment`` and ``CupsMugsGoblets`` +- ``ui_advmode_menu``: added ``Build`` +- ``ui_unit_view_mode``: added ``PrefOccupation`` +- ``unit_skill``: identified ``natural_skill_lvl`` (was ``unk_1c``) +- ``viewscreen_jobmanagementst``: identified ``max_workshops`` +- ``viewscreen_overallstatusst``: made ``visible_pages`` an enum +- ``viewscreen_pricest``: identified fields +- ``viewscreen_workquota_conditionst``: gave some fields ``unk`` names + +API Changes +----------- +- Allowed the Lua API to accept integer-like floats and strings when expecting an integer +- Lua: New ``Painter:key_string()`` method +- Lua: Added ``dfhack.getArchitecture()`` and ``dfhack.getArchitectureName()`` + +Additions/Removals: +------------------- +- Added `adv-rumors` script: improves the "Bring up specific incident or rumor" menu in adventure mode +- Added `install-info` script for basic troubleshooting +- Added `tweak condition-material `: fixes a crash in the work order condition material list +- Added `tweak hotkey-clear `: adds an option to clear bindings from DF hotkeys +- `autofarm`: reverted local biome detection (from 0.43.05-alpha3) + +Other Changes +------------- +- Added a DOWNLOAD_RUBY CMake option, to allow use of a system/external ruby library +- Added the ability to download files manually before building +- `gui/extended-status`: added a feature to queue beds +- `remotefortressreader`: added building items, DF version info +- `stonesense`: Added support for 64-bit macOS and Linux + DFHack 0.43.05-beta1 ==================== From 3cfbd735dcf5db19bed18ee155c113eef161b86e Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 23 Apr 2017 17:14:22 -0400 Subject: [PATCH 373/413] Update xml, stonesense, scripts --- library/xml | 2 +- plugins/stonesense | 2 +- scripts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/xml b/library/xml index 9b834c089..f550d736d 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9b834c089efb4657d43a8fa4f8f0822e8224e576 +Subproject commit f550d736d5dc12d9218a152dc25029287567c485 diff --git a/plugins/stonesense b/plugins/stonesense index 1925760b2..00f0782bb 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 1925760b2f611d246d1715a2e3cfb591a02ef00b +Subproject commit 00f0782bbbdc1a739da163a2ac57ef350fa84ec6 diff --git a/scripts b/scripts index cf367974b..0e22223f2 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit cf367974b5e1513d454b2988d45122e98cd28f52 +Subproject commit 0e22223f2dd48314722f9d68ac95e92f059c05a9 From 22db0e4a1edb1b67deb45ef8fa5fbb220e320b4e Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 23 Apr 2017 17:23:38 -0400 Subject: [PATCH 374/413] Bump to 0.43.05-beta2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7c0835a4..615ce4e95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,7 +137,7 @@ endif() # set up versioning. set(DF_VERSION "0.43.05") -SET(DFHACK_RELEASE "beta1") +SET(DFHACK_RELEASE "beta2") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 9d5b69cb20c08a88306232380370a11439cc304c Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 23 Apr 2017 18:16:00 -0400 Subject: [PATCH 375/413] git-describe.cmake: use 8-digit git commit abbreviations The length here was previously determined automatically, and jumped from 7 to 8 recently, breaking devel/check-release. Since Git seems to think 8 characters is better now, specify it explicitly to avoid future breakages. --- library/git-describe.cmake | 4 ++-- scripts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/git-describe.cmake b/library/git-describe.cmake index 9a22617ad..3fb3095ff 100644 --- a/library/git-describe.cmake +++ b/library/git-describe.cmake @@ -1,10 +1,10 @@ -execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --long +execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=8 --long WORKING_DIRECTORY "${dfhack_SOURCE_DIR}" OUTPUT_VARIABLE DFHACK_GIT_DESCRIPTION) execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD WORKING_DIRECTORY "${dfhack_SOURCE_DIR}" OUTPUT_VARIABLE DFHACK_GIT_COMMIT) -execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --exact-match +execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=8 --exact-match WORKING_DIRECTORY "${dfhack_SOURCE_DIR}" RESULT_VARIABLE DFHACK_GIT_TAGGED_RESULT OUTPUT_QUIET ERROR_QUIET) diff --git a/scripts b/scripts index 0e22223f2..95dbacdab 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 0e22223f2dd48314722f9d68ac95e92f059c05a9 +Subproject commit 95dbacdab21ce24dbc25aacc8173d370b099bce9 From bc478039483e3bbadf9e74a222fc0656c87c606e Mon Sep 17 00:00:00 2001 From: Amostubal Date: Mon, 24 Apr 2017 07:07:08 -0500 Subject: [PATCH 376/413] fix of relations errors. There is a lot more errors in this file, mostly called unk variables... I bet they have names, I've tried to figure out what they were renamed too, but I'm not fully understanding the xml. --- library/lua/makeown.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/lua/makeown.lua b/library/lua/makeown.lua index bf3d8077c..2b16db1df 100644 --- a/library/lua/makeown.lua +++ b/library/lua/makeown.lua @@ -144,14 +144,14 @@ function make_citizen(unit) hf.caste = unit.caste hf.sex = unit.sex hf.appeared_year = dfg.cur_year - hf.born_year = unit.relations.birth_year - hf.born_seconds = unit.relations.birth_time - hf.curse_year = unit.relations.curse_year - hf.curse_seconds = unit.relations.curse_time - hf.anon_1 = unit.relations.anon_2 - hf.anon_2 = unit.relations.anon_3 - hf.old_year = unit.relations.old_year - hf.old_seconds = unit.relations.old_time + hf.born_year = unit.birth_year + hf.born_seconds = unit.birth_time + hf.curse_year = unit.curse_year + hf.curse_seconds = unit.curse_time + hf.birth_year_bias=unit.bias_birth_bias + hf.birth_time_bias=unit.birth_time_bias + hf.old_year = unit.old_year + hf.old_seconds = unit.old_time hf.died_year = -1 hf.died_seconds = -1 hf.name:assign(unit.name) @@ -299,4 +299,4 @@ end -return _ENV \ No newline at end of file +return _ENV From 71b553b3052a14e36fe0c24f8bb06e20f3b06414 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 28 Apr 2017 17:25:58 -0400 Subject: [PATCH 377/413] Add a few functions to retrieve unit social activities --- library/LuaApi.cpp | 4 ++++ library/include/modules/Units.h | 6 ++++++ library/modules/Units.cpp | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index a2446c78a..c2621699f 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -62,6 +62,8 @@ distribution. #include "MiscUtils.h" +#include "df/activity_entry.h" +#include "df/activity_event.h" #include "df/job.h" #include "df/job_item.h" #include "df/building.h" @@ -1580,6 +1582,8 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, isUndead), WRAPM(Units, isGelded), WRAPM(Units, isDomesticated), + WRAPM(Units, getMainSocialActivity), + WRAPM(Units, getMainSocialEvent), { NULL, NULL } }; diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 79b8ff18c..08baf98d6 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -41,6 +41,8 @@ distribution. namespace df { + struct activity_entry; + struct activity_event; struct nemesis_record; struct burrow; struct identity; @@ -301,6 +303,10 @@ DFHACK_EXPORT int8_t getProfessionColor(df::unit *unit, bool ignore_noble = fals DFHACK_EXPORT int8_t getCasteProfessionColor(int race, int caste, df::profession pid); DFHACK_EXPORT std::string getSquadName(df::unit *unit); + +DFHACK_EXPORT df::activity_entry *getMainSocialActivity(df::unit *unit); +DFHACK_EXPORT df::activity_event *getMainSocialEvent(df::unit *unit); + } } #endif diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 0596d529f..94b11b87e 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -48,6 +48,7 @@ using namespace std; #include "Core.h" #include "MiscUtils.h" +#include "df/activity_entry.h" #include "df/burrow.h" #include "df/caste_raw.h" #include "df/creature_raw.h" @@ -1831,6 +1832,24 @@ std::string Units::getSquadName(df::unit *unit) return Translation::TranslateName(&squad->name, true); } +df::activity_entry *Units::getMainSocialActivity(df::unit *unit) +{ + CHECK_NULL_POINTER(unit); + if (unit->social_activities.empty()) + return nullptr; + + return df::activity_entry::find(unit->social_activities[unit->social_activities.size() - 1]); +} + +df::activity_event *Units::getMainSocialEvent(df::unit *unit) +{ + CHECK_NULL_POINTER(unit); + df::activity_entry *entry = getMainSocialActivity(unit); + if (!entry || entry->events.empty()) + return nullptr; + return entry->events[entry->events.size() - 1]; +} + bool Units::isMerchant(df::unit* unit) { CHECK_NULL_POINTER(unit); From 690fec9d81fe5330fc6cecee9c3d45e776773f38 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 28 Apr 2017 17:26:20 -0400 Subject: [PATCH 378/413] manipulator: show social activities in job column --- plugins/manipulator.cpp | 49 +++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index 76b8251b5..2940b493b 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -15,8 +15,9 @@ #include #include #include - #include + +#include "df/activity_event.h" #include "df/world.h" #include "df/ui.h" #include "df/graphic.h" @@ -289,7 +290,8 @@ struct UnitInfo int active_index; string squad_effective_name; string squad_info; - string job_info; + string job_desc; + enum { IDLE, SOCIAL, JOB } job_mode; bool selected; struct { // Used for custom professions, 1-indexed @@ -363,16 +365,18 @@ bool sortBySquad (const UnitInfo *d1, const UnitInfo *d2) bool sortByJob (const UnitInfo *d1, const UnitInfo *d2) { - bool gt = false; + if (d1->job_mode != d2->job_mode) + { + if (descending) + return int(d1->job_mode) < int(d2->job_mode); + else + return int(d1->job_mode) > int(d2->job_mode); + } - if (d1->job_info == "Idle") - gt = false; - else if (d2->job_info == "Idle") - gt = true; + if (descending) + return d1->job_desc > d2->job_desc; else - gt = (d1->job_info > d2->job_info); - - return descending ? gt : !gt; + return d1->job_desc < d2->job_desc; } bool sortByStress (const UnitInfo *d1, const UnitInfo *d2) @@ -1234,9 +1238,18 @@ void viewscreen_unitlaborsst::refreshNames() cur->profession = Units::getProfessionName(unit); if (unit->job.current_job == NULL) { - cur->job_info = "Idle"; + df::activity_event *event = Units::getMainSocialEvent(unit); + if (event) { + event->getName(unit->id, &cur->job_desc); + cur->job_mode = UnitInfo::SOCIAL; + } + else { + cur->job_desc = "Idle"; + cur->job_mode = UnitInfo::IDLE; + } } else { - cur->job_info = DFHack::Job::getName(unit->job.current_job); + cur->job_desc = DFHack::Job::getName(unit->job.current_job); + cur->job_mode = UnitInfo::JOB; } if (unit->military.squad_id > -1) { cur->squad_effective_name = Units::getSquadName(unit); @@ -1283,7 +1296,7 @@ void viewscreen_unitlaborsst::calcSize() if (detail_mode == DETAIL_MODE_SQUAD) { detail_cmp = units[i]->squad_info.size(); } else if (detail_mode == DETAIL_MODE_JOB) { - detail_cmp = units[i]->job_info.size(); + detail_cmp = units[i]->job_desc.size(); } else { detail_cmp = units[i]->profession.size(); } @@ -1954,11 +1967,13 @@ void viewscreen_unitlaborsst::render() fg = 11; detail_str = cur->squad_info; } else if (detail_mode == DETAIL_MODE_JOB) { - detail_str = cur->job_info; - if (detail_str == "Idle") { - fg = 14; + detail_str = cur->job_desc; + if (cur->job_mode == UnitInfo::IDLE) { + fg = COLOR_YELLOW; + } else if (cur->job_mode == UnitInfo::SOCIAL) { + fg = COLOR_LIGHTGREEN; } else { - fg = 10; + fg = COLOR_LIGHTCYAN; } } else { fg = cur->color; From 932a49e89e9d05d084ff139fe2675620fa3fd64d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 29 Apr 2017 11:06:29 -0400 Subject: [PATCH 379/413] Re-add workflow keybindings Several users have asked to have these back, and they don't interfere with the game unless workflow is enabled. This reverts part of commit b68cff0384faa936984206c34563be9a9daeb0f7. --- dfhack.init-example | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dfhack.init-example b/dfhack.init-example index a6fd6ffba..a93585d14 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -135,6 +135,10 @@ keybinding add Alt-P@dwarfmode/Hauling/DefineStop/Cond/Guide gui/guide-path # workshop job details keybinding add Alt-A@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workshop-job +# workflow front-end +keybinding add Alt-W@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workflow +keybinding add Alt-W@overallstatus "gui/workflow status" + # autobutcher front-end keybinding add Shift-B@pet/List/Unit "gui/autobutcher" From 03f56f73154955b363cfb7affe50102517a40e8e Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 30 Apr 2017 17:06:57 -0400 Subject: [PATCH 380/413] gunzip.pl: use binary output mode Fixes an issue with LF being turned into CRLF on Windows --- depends/gunzip.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/gunzip.pl b/depends/gunzip.pl index 4a21daafd..caabad5a8 100755 --- a/depends/gunzip.pl +++ b/depends/gunzip.pl @@ -18,4 +18,4 @@ if (-f $out_file and !exists($args{'--force'})) { die "output file exists, not overwriting: \"$out_file\""; } -gunzip $in_file => $out_file or die "gunzip failed: $GunzipError\n"; +gunzip $in_file => $out_file, BinModeOut => 1 or die "gunzip failed: $GunzipError\n"; From cd5944689c433398def5141ff5ef255e02b3b519 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 30 Apr 2017 17:36:42 -0400 Subject: [PATCH 381/413] Use find_package() to find Perl, and run it earlier Previously, PERL_EXECUTABLE was set manually in library/CMakeLists.txt, which caused gunzip.pl to fail if was run before that happened. --- CMakeLists.txt | 2 ++ library/CMakeLists.txt | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 615ce4e95..186fabf4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,8 @@ IF(CMAKE_CROSSCOMPILING) INCLUDE("${DFHACK_NATIVE_BUILD_DIR}/ImportExecutables.cmake") ENDIF() +find_package(Perl REQUIRED) + # set up folder structures for IDE solutions # MSVC Express won't load solutions that use this. It also doesn't include MFC supported # Check for MFC! diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 9f8477993..7a296dbc7 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -16,8 +16,6 @@ ENDIF() include_directories (proto) include_directories (include) -SET(PERL_EXECUTABLE "perl" CACHE FILEPATH "This is the perl executable to run in the codegen step. Tweak it if you need to run a specific one.") - execute_process(COMMAND ${PERL_EXECUTABLE} xml/list.pl xml ${dfapi_SOURCE_DIR}/include/df ";" WORKING_DIRECTORY ${dfapi_SOURCE_DIR} OUTPUT_VARIABLE GENERATED_HDRS) From e3258defd7a7e5910c01a831cb3024fc85f1a1f1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 4 May 2017 14:37:14 -0400 Subject: [PATCH 382/413] Expose Gui::revealInDwarfmodeMap() to Lua Closes #1085 --- library/LuaApi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index c2621699f..0c153f91e 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1459,6 +1459,7 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = { WRAPM(Gui, showZoomAnnouncement), WRAPM(Gui, showPopupAnnouncement), WRAPM(Gui, showAutoAnnouncement), + WRAPM(Gui, revealInDwarfmodeMap), { NULL, NULL } }; From 1e469453fcf947744c35c1280890482354cb39dc Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 4 May 2017 21:47:12 -0400 Subject: [PATCH 383/413] Add Designations module, currently supporting plant/tree designations This makes it easier for tools to properly handle designating and undesignating trees for chopping and plants for gathering, which changed significantly in 0.40.20. Ref #531 (?), #656, #1014, #1018, #1030, #1076 --- library/CMakeLists.txt | 22 ++--- library/LuaApi.cpp | 14 +++ library/include/modules/Designations.h | 18 ++++ library/modules/Designations.cpp | 119 +++++++++++++++++++++++++ 4 files changed, 163 insertions(+), 10 deletions(-) create mode 100644 library/include/modules/Designations.h create mode 100644 library/modules/Designations.cpp diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 7a296dbc7..033c82053 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -113,36 +113,39 @@ SET(MODULE_HEADERS include/modules/Buildings.h include/modules/Burrows.h include/modules/Constructions.h -include/modules/Units.h +include/modules/Designations.h include/modules/Engravings.h include/modules/EventManager.h +include/modules/Filesystem.h +include/modules/Graphic.h include/modules/Gui.h include/modules/GuiHooks.h include/modules/Items.h include/modules/Job.h include/modules/kitchen.h -include/modules/Maps.h include/modules/MapCache.h +include/modules/Maps.h include/modules/Materials.h include/modules/Notes.h +include/modules/Once.h include/modules/Random.h include/modules/Renderer.h include/modules/Screen.h include/modules/Translation.h +include/modules/Units.h include/modules/Vermin.h include/modules/World.h -include/modules/Graphic.h -include/modules/Once.h -include/modules/Filesystem.h ) SET( MODULE_SOURCES modules/Buildings.cpp modules/Burrows.cpp modules/Constructions.cpp -modules/Units.cpp +modules/Designations.cpp modules/Engravings.cpp modules/EventManager.cpp +modules/Filesystem.cpp +modules/Graphic.cpp modules/Gui.cpp modules/Items.cpp modules/Job.cpp @@ -151,16 +154,15 @@ modules/MapCache.cpp modules/Maps.cpp modules/Materials.cpp modules/Notes.cpp +modules/Once.cpp modules/Random.cpp modules/Renderer.cpp modules/Screen.cpp modules/Translation.cpp +modules/Units.cpp modules/Vermin.cpp -modules/World.cpp -modules/Graphic.cpp modules/Windows.cpp -modules/Once.cpp -modules/Filesystem.cpp +modules/World.cpp ) SET(STATIC_FIELDS_FILES) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 0c153f91e..fd4ce1c02 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -56,6 +56,7 @@ distribution. #include "modules/Constructions.h" #include "modules/Random.h" #include "modules/Filesystem.h" +#include "modules/Designations.h" #include "LuaWrapper.h" #include "LuaTools.h" @@ -92,6 +93,7 @@ distribution. #include "df/itemdef.h" #include "df/enabler.h" #include "df/feature_init.h" +#include "df/plant.h" #include #include @@ -2314,6 +2316,17 @@ static const luaL_Reg dfhack_filesystem_funcs[] = { {NULL, NULL} }; +/***** Designations module *****/ + +static const LuaWrapper::FunctionReg dfhack_designations_module[] = { + WRAPM(Designations, markPlant), + WRAPM(Designations, unmarkPlant), + WRAPM(Designations, canMarkPlant), + WRAPM(Designations, canUnmarkPlant), + WRAPM(Designations, isPlantMarked), + {NULL, NULL} +}; + /***** Internal module *****/ static void *checkaddr(lua_State *L, int idx, bool allow_null = false) @@ -2792,5 +2805,6 @@ void OpenDFHackApi(lua_State *state) OpenModule(state, "constructions", dfhack_constructions_module); OpenModule(state, "screen", dfhack_screen_module, dfhack_screen_funcs); OpenModule(state, "filesystem", dfhack_filesystem_module, dfhack_filesystem_funcs); + OpenModule(state, "designations", dfhack_designations_module); OpenModule(state, "internal", dfhack_internal_module, dfhack_internal_funcs); } diff --git a/library/include/modules/Designations.h b/library/include/modules/Designations.h new file mode 100644 index 000000000..6dcf85f59 --- /dev/null +++ b/library/include/modules/Designations.h @@ -0,0 +1,18 @@ +#pragma once + +namespace df { + struct plant; +} + +namespace DFHack { + namespace Designations { + // Mark or un-mark a plant (e.g. fell trees, gather plants) + // Return value indicates whether the plant's designation was changed or not + // (This can be false if markPlant() is called on an already-designated plant, for example) + DFHACK_EXPORT bool markPlant(const df::plant *plant); + DFHACK_EXPORT bool unmarkPlant(const df::plant *plant); + DFHACK_EXPORT bool canMarkPlant(const df::plant *plant); + DFHACK_EXPORT bool canUnmarkPlant(const df::plant *plant); + DFHACK_EXPORT bool isPlantMarked(const df::plant *plant); + } +} diff --git a/library/modules/Designations.cpp b/library/modules/Designations.cpp new file mode 100644 index 000000000..8cae35d78 --- /dev/null +++ b/library/modules/Designations.cpp @@ -0,0 +1,119 @@ +#include "DataDefs.h" +#include "Error.h" + +#include "modules/Designations.h" +#include "modules/Job.h" +#include "modules/Maps.h" + +#include "df/job.h" +#include "df/map_block.h" +#include "df/plant.h" +#include "df/tile_dig_designation.h" +#include "df/world.h" + +using namespace DFHack; +using namespace df::enums; + +using df::global::world; + +static df::map_block *getPlantBlock(const df::plant *plant) +{ + if (!world) + return nullptr; + return Maps::getTileBlock(plant->pos); +} + +bool Designations::isPlantMarked(const df::plant *plant) +{ + CHECK_NULL_POINTER(plant); + + df::map_block *block = getPlantBlock(plant); + if (!block) + return false; + + if (block->designation[plant->pos.x % 16][plant->pos.y % 16].bits.dig == tile_dig_designation::Default) + return true; + + for (auto *link = world->job_list.next; link; link = link->next) + { + df::job *job = link->item; + if (!job) + continue; + if (job->job_type != job_type::FellTree && job->job_type != job_type::GatherPlants) + continue; + if (job->pos == plant->pos) + return true; + } + return false; +} + +bool Designations::canMarkPlant(const df::plant *plant) +{ + CHECK_NULL_POINTER(plant); + + if (!getPlantBlock(plant)) + return false; + + return !isPlantMarked(plant); +} + +bool Designations::markPlant(const df::plant *plant) +{ + CHECK_NULL_POINTER(plant); + + if (canMarkPlant(plant)) + { + df::map_block *block = getPlantBlock(plant); + block->designation[plant->pos.x % 16][plant->pos.y % 16].bits.dig = tile_dig_designation::Default; + block->flags.bits.designated = true; + return true; + } + else + { + return false; + } +} + +bool Designations::canUnmarkPlant(const df::plant *plant) +{ + CHECK_NULL_POINTER(plant); + + if (!getPlantBlock(plant)) + return false; + + return isPlantMarked(plant); +} + +bool Designations::unmarkPlant(const df::plant *plant) +{ + CHECK_NULL_POINTER(plant); + + if (canUnmarkPlant(plant)) + { + df::map_block *block = getPlantBlock(plant); + block->designation[plant->pos.x % 16][plant->pos.y % 16].bits.dig = tile_dig_designation::No; + block->flags.bits.designated = true; + + auto *link = world->job_list.next; + while (link) + { + auto *next = link->next; + df::job *job = link->item; + + if (!job) + continue; + if (job->job_type != job_type::FellTree && job->job_type != job_type::GatherPlants) + continue; + if (job->pos == plant->pos) + Job::removeJob(job); + + link = next; + } + + return true; + } + else + { + return false; + } +} From a527091172b978a3181e56a1eeba0a0fe858e115 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 4 May 2017 21:51:16 -0400 Subject: [PATCH 384/413] autochop: Fix marking/unmarking trees (use Designations module) Fixes #656 Fixes #1076 Closes #1030 --- plugins/autochop.cpp | 49 +++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index 73a3da24e..13ffa70ea 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -10,24 +10,26 @@ #include "DataDefs.h" #include "TileTypes.h" -#include "df/world.h" -#include "df/map_block.h" -#include "df/tile_dig_designation.h" -#include "df/plant_raw.h" -#include "df/plant.h" -#include "df/ui.h" #include "df/burrow.h" -#include "df/item_flags.h" #include "df/item.h" +#include "df/item_flags.h" #include "df/items_other_id.h" +#include "df/job.h" +#include "df/map_block.h" +#include "df/plant.h" +#include "df/plant_raw.h" +#include "df/tile_dig_designation.h" +#include "df/ui.h" #include "df/viewscreen_dwarfmodest.h" +#include "df/world.h" -#include "modules/Screen.h" -#include "modules/Maps.h" #include "modules/Burrows.h" -#include "modules/World.h" -#include "modules/MapCache.h" +#include "modules/Designations.h" #include "modules/Gui.h" +#include "modules/MapCache.h" +#include "modules/Maps.h" +#include "modules/Screen.h" +#include "modules/World.h" #include @@ -228,38 +230,33 @@ static int do_chop_designation(bool chop, bool count_only) if (!count_only && !watchedBurrows.isValidPos(plant->pos)) continue; - bool dirty = false; - if (chop && cur->designation[x][y].bits.dig == tile_dig_designation::No) + if (chop && !Designations::isPlantMarked(plant)) { if (count_only) { - ++count; + if (Designations::canMarkPlant(plant)) + count++; } else { - cur->designation[x][y].bits.dig = tile_dig_designation::Default; - dirty = true; + if (Designations::markPlant(plant)) + count++; } } - if (!chop && cur->designation[x][y].bits.dig == tile_dig_designation::Default) + if (!chop && Designations::isPlantMarked(plant)) { if (count_only) { - ++count; + if (Designations::canUnmarkPlant(plant)) + count++; } else { - cur->designation[x][y].bits.dig = tile_dig_designation::No; - dirty = true; + if (Designations::unmarkPlant(plant)) + count++; } } - - if (dirty) - { - cur->flags.bits.designated = true; - ++count; - } } return count; From d3c496cc2bf7d96475cb46871eae7233c153918c Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 May 2017 14:45:46 -0400 Subject: [PATCH 385/413] Add getSelectedPlant() and related functions Currently only works with the center tile of multi-tile trees --- docs/Lua API.rst | 4 +++ library/LuaApi.cpp | 1 + library/include/modules/Gui.h | 6 +++++ library/include/modules/Screen.h | 11 +++++--- library/lua/utils.lua | 2 ++ library/modules/Gui.cpp | 45 ++++++++++++++++++++++++++++++++ library/modules/Screen.cpp | 9 +++++++ 7 files changed, 74 insertions(+), 4 deletions(-) diff --git a/docs/Lua API.rst b/docs/Lua API.rst index 2db98abad..1c08407ae 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -921,6 +921,10 @@ Gui module Returns the building selected via :kbd:`q`, :kbd:`t`, :kbd:`k` or :kbd:`i`. +* ``dfhack.gui.getSelectedPlant([silent])`` + + Returns the plant selected via :kbd:`k`. + * ``dfhack.gui.writeToGamelog(text)`` Writes a string to :file:`gamelog.txt` without doing an announcement. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index fd4ce1c02..2a4fb64d3 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1453,6 +1453,7 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = { WRAPM(Gui, getSelectedUnit), WRAPM(Gui, getSelectedItem), WRAPM(Gui, getSelectedBuilding), + WRAPM(Gui, getSelectedPlant), WRAPM(Gui, writeToGamelog), WRAPM(Gui, makeAnnouncement), WRAPM(Gui, addCombatReport), diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h index ae53e7603..7ea4d0e48 100644 --- a/library/include/modules/Gui.h +++ b/library/include/modules/Gui.h @@ -45,6 +45,7 @@ namespace df { struct job; struct unit; struct item; + struct plant; }; /** @@ -104,6 +105,11 @@ namespace DFHack DFHACK_EXPORT df::building *getAnyBuilding(df::viewscreen *top); DFHACK_EXPORT df::building *getSelectedBuilding(color_ostream &out, bool quiet = false); + // A plant is selected, e.g. via 'k' + DFHACK_EXPORT bool any_plant_hotkey(df::viewscreen *top); + DFHACK_EXPORT df::plant *getAnyPlant(df::viewscreen *top); + DFHACK_EXPORT df::plant *getSelectedPlant(color_ostream &out, bool quiet = false); + // Low-level API that gives full control over announcements and reports DFHACK_EXPORT void writeToGamelog(std::string message); diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index 2c4a29062..4e53b0b54 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -44,6 +44,7 @@ namespace df struct item; struct unit; struct building; + struct plant; } /** @@ -326,10 +327,11 @@ namespace DFHack virtual std::string getFocusString() = 0; virtual void onShow() {}; virtual void onDismiss() {}; - virtual df::unit *getSelectedUnit() { return NULL; } - virtual df::item *getSelectedItem() { return NULL; } - virtual df::job *getSelectedJob() { return NULL; } - virtual df::building *getSelectedBuilding() { return NULL; } + virtual df::unit *getSelectedUnit() { return nullptr; } + virtual df::item *getSelectedItem() { return nullptr; } + virtual df::job *getSelectedJob() { return nullptr; } + virtual df::building *getSelectedBuilding() { return nullptr; } + virtual df::plant *getSelectedPlant() { return nullptr; } }; class DFHACK_EXPORT dfhack_lua_viewscreen : public dfhack_viewscreen { @@ -369,5 +371,6 @@ namespace DFHack virtual df::item *getSelectedItem(); virtual df::job *getSelectedJob(); virtual df::building *getSelectedBuilding(); + virtual df::plant *getSelectedPlant(); }; } diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 4800042f0..07db41808 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -635,6 +635,8 @@ function df_shortcut_var(k) return dfhack.gui.getSelectedWorkshopJob() elseif k == 'unit' then return dfhack.gui.getSelectedUnit() + elseif k == 'plant' then + return dfhack.gui.getSelectedPlant() else for g in pairs(df.global) do if g == k then diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 9a86e69ec..5ad569c5a 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -92,6 +92,7 @@ using namespace DFHack; #include "df/game_mode.h" #include "df/unit.h" #include "df/occupation.h" +#include "df/plant.h" using namespace df::enums; using df::global::gview; @@ -1120,6 +1121,50 @@ df::building *Gui::getSelectedBuilding(color_ostream &out, bool quiet) return building; } +df::plant *Gui::getAnyPlant(df::viewscreen *top) +{ + using df::global::cursor; + using df::global::ui; + using df::global::world; + + if (auto dfscreen = dfhack_viewscreen::try_cast(top)) + return dfscreen->getSelectedPlant(); + + if (Gui::dwarfmode_hotkey(top)) + { + if (!cursor || !ui || !world) + return nullptr; + + if (ui->main.mode == ui_sidebar_mode::LookAround) + { + for (df::plant *plant : world->plants.all) + { + if (plant->pos.x == cursor->x && plant->pos.y == cursor->y && plant->pos.z == cursor->z) + { + return plant; + } + } + } + } + + return nullptr; +} + +bool Gui::any_plant_hotkey(df::viewscreen *top) +{ + return getAnyPlant(top) != nullptr; +} + +df::plant *Gui::getSelectedPlant(color_ostream &out, bool quiet) +{ + df::plant *plant = getAnyPlant(Core::getTopViewscreen()); + + if (!plant && !quiet) + out.printerr("No plant is selected in the UI.\n"); + + return plant; +} + // DFHACK_EXPORT void Gui::writeToGamelog(std::string message) diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 71103ffda..0b9a500fa 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -57,6 +57,7 @@ using namespace DFHack; #include "df/job.h" #include "df/building.h" #include "df/renderer.h" +#include "df/plant.h" using namespace df::enums; using df::global::init; @@ -934,3 +935,11 @@ df::building *dfhack_lua_viewscreen::getSelectedBuilding() safe_call_lua(do_notify, 1, 1); return Lua::GetDFObject(Lua::Core::State, -1); } + +df::plant *dfhack_lua_viewscreen::getSelectedPlant() +{ + Lua::StackUnwinder frame(Lua::Core::State); + lua_pushstring(Lua::Core::State, "onGetSelectedPlant"); + safe_call_lua(do_notify, 1, 1); + return Lua::GetDFObject(Lua::Core::State, -1); +} From b7b83e5ce1f1ce04b1b46f64f31a647db6219c1d Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 May 2017 14:46:57 -0400 Subject: [PATCH 386/413] Fix major errors in autochop docs --- docs/Plugins.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 568688a53..4b5985ae7 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -1657,13 +1657,14 @@ quotas. Open the dashboard by running:: - getplants autochop + enable autochop -The plugin must be activated (with ``c``) before it can be used. You can then set logging quotas -and restrict designations to specific burrows (with 'Enter') if desired. The plugin's activity -cycle runs once every in game day. +The plugin must be activated (with :kbd:`d`-:kbd:`t`-:kbd:`c`-:kbd:`a`) before +it can be used. You can then set logging quotas and restrict designations to +specific burrows (with 'Enter') if desired. The plugin's activity cycle runs +once every in game day. -If you add ``enable getplants`` to your dfhack.init there will be a hotkey to +If you add ``enable autochop`` to your dfhack.init there will be a hotkey to open the dashboard from the chop designation menu. From 81610d0259d656526aca2d83f6a3081b9af6f22f Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 May 2017 14:49:32 -0400 Subject: [PATCH 387/413] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index f550d736d..b48397cf5 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f550d736d5dc12d9218a152dc25029287567c485 +Subproject commit b48397cf5b4c954a098151943f7314a1a6eacf90 From b92cb6dcdbe8085b11454286b2fe8afb9544bbc3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 May 2017 14:50:02 -0400 Subject: [PATCH 388/413] Update scripts/autounsuspend --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 95dbacdab..1d768b69f 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 95dbacdab21ce24dbc25aacc8173d370b099bce9 +Subproject commit 1d768b69f640ce7a00713c0ce9a9e6ca1d557218 From adb14491d014e6a5d5d608bd19090f556e6429ef Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 May 2017 17:24:51 -0400 Subject: [PATCH 389/413] Fix loop in Designations::unmarkPlant() --- library/modules/Designations.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/modules/Designations.cpp b/library/modules/Designations.cpp index 8cae35d78..87b935cc3 100644 --- a/library/modules/Designations.cpp +++ b/library/modules/Designations.cpp @@ -100,12 +100,12 @@ bool Designations::unmarkPlant(const df::plant *plant) auto *next = link->next; df::job *job = link->item; - if (!job) - continue; - if (job->job_type != job_type::FellTree && job->job_type != job_type::GatherPlants) - continue; - if (job->pos == plant->pos) + if (job && + (job->job_type == job_type::FellTree || job->job_type == job_type::GatherPlants) && + job->pos == plant->pos) + { Job::removeJob(job); + } link = next; } From 5c784f4ba3ceed96764d7e00beb8118296ae343e Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 May 2017 17:31:54 -0400 Subject: [PATCH 390/413] autochop: Avoid moving menu options around when toggling burrows --- plugins/autochop.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index 13ffa70ea..286910e71 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -587,6 +587,7 @@ public: if (burrows_column.getSelectedElems().size() > 0) { OutputString(COLOR_GREEN, x, y, "Will chop in selected burrows", true, left_margin); + ++y; } else { From adaccceba7f0815c0340d088cd97ce3d6119edcd Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 May 2017 17:36:02 -0400 Subject: [PATCH 391/413] autochop: fix display of unnamed burrows --- plugins/autochop.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index 286910e71..dbc79af42 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -387,10 +387,12 @@ public: auto last_selected_index = burrows_column.highlighted_index; burrows_column.clear(); - for (auto iter = ui->burrows.list.begin(); iter != ui->burrows.list.end(); iter++) + for (df::burrow *burrow : ui->burrows.list) { - df::burrow* burrow = *iter; - auto elem = ListEntry(burrow->name, burrow); + string name = burrow->name; + if (name.empty()) + name = "Burrow " + int_to_string(burrow->id + 1); + auto elem = ListEntry(name, burrow); elem.selected = watchedBurrows.isBurrowWatched(burrow); burrows_column.add(elem); } From fbae598086967f2639bb61a2da74138b66e8555d Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 May 2017 17:36:34 -0400 Subject: [PATCH 392/413] Add extra gui/workflow binding to work with gui/extended-status --- dfhack.init-example | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dfhack.init-example b/dfhack.init-example index a93585d14..19bef37e6 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -138,6 +138,8 @@ keybinding add Alt-A@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workshop-job # workflow front-end keybinding add Alt-W@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workflow keybinding add Alt-W@overallstatus "gui/workflow status" +# equivalent to the one above when gui/extended-status is enabled +keybinding add Alt-W@dfhack/lua/status_overlay "gui/workflow status" # autobutcher front-end keybinding add Shift-B@pet/List/Unit "gui/autobutcher" From 55931703ac23e29089b00d7ff1a379f019f4c062 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 5 May 2017 21:25:25 -0400 Subject: [PATCH 393/413] Designate the correct tile for trees with multi-tile trunks DF always designates the southeast trunk tile, while plant.pos is the center, which is sometimes inaccessible (see #1014) --- library/LuaApi.cpp | 12 +++++- library/include/modules/Designations.h | 3 ++ library/modules/Designations.cpp | 52 +++++++++++++++++++++----- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 2a4fb64d3..266677045 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2328,6 +2328,16 @@ static const LuaWrapper::FunctionReg dfhack_designations_module[] = { {NULL, NULL} }; +static int designations_getPlantDesignationTile(lua_State *state) +{ + return Lua::PushPosXYZ(state, Designations::getPlantDesignationTile(Lua::CheckDFObject(state, 1))); +} + +static const luaL_Reg dfhack_designations_funcs[] = { + {"getPlantDesignationTile", designations_getPlantDesignationTile}, + {NULL, NULL} +}; + /***** Internal module *****/ static void *checkaddr(lua_State *L, int idx, bool allow_null = false) @@ -2806,6 +2816,6 @@ void OpenDFHackApi(lua_State *state) OpenModule(state, "constructions", dfhack_constructions_module); OpenModule(state, "screen", dfhack_screen_module, dfhack_screen_funcs); OpenModule(state, "filesystem", dfhack_filesystem_module, dfhack_filesystem_funcs); - OpenModule(state, "designations", dfhack_designations_module); + OpenModule(state, "designations", dfhack_designations_module, dfhack_designations_funcs); OpenModule(state, "internal", dfhack_internal_module, dfhack_internal_funcs); } diff --git a/library/include/modules/Designations.h b/library/include/modules/Designations.h index 6dcf85f59..914605e58 100644 --- a/library/include/modules/Designations.h +++ b/library/include/modules/Designations.h @@ -14,5 +14,8 @@ namespace DFHack { DFHACK_EXPORT bool canMarkPlant(const df::plant *plant); DFHACK_EXPORT bool canUnmarkPlant(const df::plant *plant); DFHACK_EXPORT bool isPlantMarked(const df::plant *plant); + + // Return the tile that should be designated for this plant + DFHACK_EXPORT df::coord getPlantDesignationTile(const df::plant *plant); } } diff --git a/library/modules/Designations.cpp b/library/modules/Designations.cpp index 87b935cc3..3fb325096 100644 --- a/library/modules/Designations.cpp +++ b/library/modules/Designations.cpp @@ -8,6 +8,8 @@ #include "df/job.h" #include "df/map_block.h" #include "df/plant.h" +#include "df/plant_tree_info.h" +#include "df/plant_tree_tile.h" #include "df/tile_dig_designation.h" #include "df/world.h" @@ -20,18 +22,48 @@ static df::map_block *getPlantBlock(const df::plant *plant) { if (!world) return nullptr; - return Maps::getTileBlock(plant->pos); + return Maps::getTileBlock(Designations::getPlantDesignationTile(plant)); +} + +df::coord Designations::getPlantDesignationTile(const df::plant *plant) +{ + CHECK_NULL_POINTER(plant); + + if (!plant->tree_info) + return plant->pos; + + int dimx = plant->tree_info->dim_x; + int dimy = plant->tree_info->dim_y; + int cx = dimx / 2; + int cy = dimy / 2; + + // Find the southeast trunk tile + int x = cx; + int y = cy; + + while (x + 1 < dimx && y + 1 < dimy) + { + if (plant->tree_info->body[0][(y * dimx) + (x + 1)].bits.trunk) + ++x; + else if (plant->tree_info->body[0][((y + 1) * dimx) + x].bits.trunk) + ++y; + else + break; + } + + return df::coord(plant->pos.x - cx + x, plant->pos.y - cy + y, plant->pos.z); } bool Designations::isPlantMarked(const df::plant *plant) { CHECK_NULL_POINTER(plant); - df::map_block *block = getPlantBlock(plant); + df::coord des_pos = getPlantDesignationTile(plant); + df::map_block *block = Maps::getTileBlock(des_pos); if (!block) return false; - if (block->designation[plant->pos.x % 16][plant->pos.y % 16].bits.dig == tile_dig_designation::Default) + if (block->designation[des_pos.x % 16][des_pos.y % 16].bits.dig == tile_dig_designation::Default) return true; for (auto *link = world->job_list.next; link; link = link->next) @@ -41,7 +73,7 @@ bool Designations::isPlantMarked(const df::plant *plant) continue; if (job->job_type != job_type::FellTree && job->job_type != job_type::GatherPlants) continue; - if (job->pos == plant->pos) + if (job->pos == des_pos) return true; } return false; @@ -63,8 +95,9 @@ bool Designations::markPlant(const df::plant *plant) if (canMarkPlant(plant)) { - df::map_block *block = getPlantBlock(plant); - block->designation[plant->pos.x % 16][plant->pos.y % 16].bits.dig = tile_dig_designation::Default; + df::coord des_pos = getPlantDesignationTile(plant); + df::map_block *block = Maps::getTileBlock(des_pos); + block->designation[des_pos.x % 16][des_pos.y % 16].bits.dig = tile_dig_designation::Default; block->flags.bits.designated = true; return true; } @@ -90,8 +123,9 @@ bool Designations::unmarkPlant(const df::plant *plant) if (canUnmarkPlant(plant)) { - df::map_block *block = getPlantBlock(plant); - block->designation[plant->pos.x % 16][plant->pos.y % 16].bits.dig = tile_dig_designation::No; + df::coord des_pos = getPlantDesignationTile(plant); + df::map_block *block = Maps::getTileBlock(des_pos); + block->designation[des_pos.x % 16][des_pos.y % 16].bits.dig = tile_dig_designation::No; block->flags.bits.designated = true; auto *link = world->job_list.next; @@ -102,7 +136,7 @@ bool Designations::unmarkPlant(const df::plant *plant) if (job && (job->job_type == job_type::FellTree || job->job_type == job_type::GatherPlants) && - job->pos == plant->pos) + job->pos == des_pos) { Job::removeJob(job); } From 3dc2c2259b96b1a6bb1e13babf17121c61f0a8ab Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 6 May 2017 00:11:07 -0400 Subject: [PATCH 394/413] Update getplants to use Designations module Fixes #531 Fixes #1014 Fixes #1018 --- plugins/getplants.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/plugins/getplants.cpp b/plugins/getplants.cpp index 87fc35960..2cf382d01 100644 --- a/plugins/getplants.cpp +++ b/plugins/getplants.cpp @@ -1,5 +1,7 @@ // (un)designate matching plants for gathering/cutting +#include + #include "Core.h" #include "Console.h" #include "Export.h" @@ -7,18 +9,19 @@ #include "DataDefs.h" #include "TileTypes.h" -#include "df/world.h" #include "df/map_block.h" -#include "df/tile_dig_designation.h" -#include "df/plant_raw.h" #include "df/plant.h" +#include "df/plant_raw.h" +#include "df/tile_dig_designation.h" +#include "df/world.h" +#include "modules/Designations.h" #include "modules/Maps.h" -#include using std::string; using std::vector; using std::set; + using namespace DFHack; using namespace df::enums; @@ -129,20 +132,14 @@ command_result df_getplants (color_ostream &out, vector & parameters) continue; if (cur->designation[x][y].bits.hidden) continue; - if (deselect && cur->designation[x][y].bits.dig == tile_dig_designation::Default) + if (deselect && Designations::unmarkPlant(plant)) { - cur->designation[x][y].bits.dig = tile_dig_designation::No; - dirty = true; ++count; } - if (!deselect && cur->designation[x][y].bits.dig == tile_dig_designation::No) + if (!deselect && Designations::markPlant(plant)) { - cur->designation[x][y].bits.dig = tile_dig_designation::Default; - dirty = true; ++count; } - if (dirty) - cur->flags.bits.designated = true; } if (count) out.print("Updated %d plant designations.\n", count); @@ -171,4 +168,4 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector Date: Sat, 6 May 2017 15:15:32 -0400 Subject: [PATCH 395/413] Update stonesense - fix #1083 --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 00f0782bb..1ffdc984d 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 00f0782bbbdc1a739da163a2ac57ef350fa84ec6 +Subproject commit 1ffdc984d0c3d50e790b9ff5991c02fb21dec463 From a62a87fe25c7d0729c3c9a973567d65b05f2b2c9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 6 May 2017 16:43:39 -0400 Subject: [PATCH 396/413] Update NEWS.rst --- NEWS.rst | 29 +++++++++++++++++++++++++---- scripts | 2 +- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 4c9b01f00..7f7695254 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -35,16 +35,19 @@ Changelog .. contents:: :depth: 2 -DFHack future -============= +DFHack 0.43.05-r1 +================= Internals --------- - 64-bit support on all platforms -- Visual Studio 2015 now required on Windows instead of 2010 -- GCC 4.8 or newer required on Linux and OS X (and now supported on OS X) - Several structure fixes to match 64-bit DF's memory layout - Added ``DFHack::Job::removeJob()`` function +- New module: ``Designations`` - handles designation creation (currently for plants only) +- Added ``Gui::getSelectedPlant()`` +- Added ``Units::getMainSocialActivity()``, ``Units::getMainSocialEvent()`` +- Visual Studio 2015 now required to build on Windows instead of 2010 +- GCC 4.8 or newer required to build on Linux and OS X (and now supported on OS X) - Updated TinyXML from 2.5.3 to 2.6.2 - Added the ability to download files manually before building @@ -58,6 +61,7 @@ Lua - String representations of vectors and a few other containers now include their lengths - Added a ``tile-material`` module - Added a ``Painter:key_string()`` method +- Made ``dfhack.gui.revealInDwarfmodeMap()`` available Ruby ---- @@ -80,6 +84,7 @@ New Scripts - `modtools/change-build-menu`: Edit the build mode sidebar menus - `modtools/if-entity`: Run a command if the current entity matches a given ID - `season-palette`: Swap color palettes with the changes of the seasons +- `unforbid`: Unforbids all items New Tweaks ---------- @@ -93,7 +98,20 @@ Fixes - ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable - Fixed ``plug`` output alignment for plugins with long names - `add-thought`: fixed support for emotion names +- `autochop`: + + - fixed several issues with job creation and removal + - stopped designating the center tile (unreachable) for large trees + - stopped options from moving when enabling and disabling burrows + - fixed display of unnamed burrows + - `devel/find-offsets`: fixed a crash when vtables used by globals aren't available +- `getplants`: + + - fixed several issues with job creation and removal + - stopped designating the center tile (unreachable) for large trees + +- `gui/workflow`: added extra keybinding to work with `gui/extended-status` - `manipulator`: - Fixed crash when selecting a profession from an empty list @@ -112,8 +130,10 @@ Misc Improvements ----------------- - Documented all default keybindings (from :file:`dfhack.init-example`) in the docs for the relevant commands; updates enforced by build system. +- `autounsuspend`: reduced update frequency to address potential performance issues - `gui/extended-status`: added a feature to queue beds - `lua` and `gui/gm-editor` now support the same aliases (``scr``, ``unit``, etc.) +- `manipulator`: added social activities to job column - `remotefortressreader`: Added support for - world map snow coverage @@ -125,6 +145,7 @@ Misc Improvements - DF version info - `title-version`: Added a prerelease indicator +- `workflow`: Re-added ``Alt-W`` keybindings DFHack 0.43.03-r1 ================= diff --git a/scripts b/scripts index 1d768b69f..e9c3119e7 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 1d768b69f640ce7a00713c0ce9a9e6ca1d557218 +Subproject commit e9c3119e751c3e2073eb02bbcda01d140cc6ae4a From 60b5786d93e241f463d9b2186340f4227beacd6b Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 6 May 2017 16:51:49 -0400 Subject: [PATCH 397/413] Add some missing people to Authors.rst --- docs/Authors.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 39f2a0301..034ff8635 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -12,6 +12,7 @@ Name Github Other 8Z 8Z acwatkins acwatkins Alexander Gavrilov angavrilov ag +Amostubal Amostubal AndreasPK AndreasPK Angus Mezick amezick Antalia tamarakorr @@ -88,7 +89,9 @@ rampaging-poet Raoul van Putten Raoul XQ raoulxq reverb +Rich Rauenzahn rrauenza Rinin Rinin +rndmvar rndmvar Robert Heinrich rh73 Robert Janetzko robertjanetzko rofl0r rofl0r @@ -108,6 +111,7 @@ Simon Jackson sizeak stolencatkarma sv-esk sv-esk Tacomagic +TheHologram TheHologram Tim Walberg twalberg Timothy Collett danaris Tom Jobbins TheBloke From a1f692686ae1d6c55cbacbc26ce968b6e26d569c Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 7 May 2017 19:24:30 +0530 Subject: [PATCH 398/413] Use forward slashes instead of underscored to separate building subtypes --- .../remotefortressreader/building_reader.cpp | 18 +++++++++--------- .../remotefortressreader.cpp | 4 ---- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/plugins/remotefortressreader/building_reader.cpp b/plugins/remotefortressreader/building_reader.cpp index 4e31e0360..2b9f95390 100644 --- a/plugins/remotefortressreader/building_reader.cpp +++ b/plugins/remotefortressreader/building_reader.cpp @@ -54,7 +54,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D bld->mutable_building_type()->set_building_type(bt); bld->mutable_building_type()->set_building_subtype(st); bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(furnace_type, st)); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(furnace_type, st)); if (st == furnace_type::Custom) { @@ -66,7 +66,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D bld->mutable_building_type()->set_building_type(bt); bld->mutable_building_type()->set_building_subtype(st); bld->mutable_building_type()->set_building_custom(cust->id); - bld->set_id(cust->code); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + cust->code); bld->set_name(cust->name); } } @@ -81,7 +81,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D bld->mutable_building_type()->set_building_type(bt); bld->mutable_building_type()->set_building_subtype(st); bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(shop_type, st)); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(shop_type, st)); } break; @@ -102,7 +102,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D bld->mutable_building_type()->set_building_type(bt); bld->mutable_building_type()->set_building_subtype(st); bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(workshop_type, st)); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(workshop_type, st)); if (st == workshop_type::Custom) { @@ -114,7 +114,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D bld->mutable_building_type()->set_building_type(bt); bld->mutable_building_type()->set_building_subtype(st); bld->mutable_building_type()->set_building_custom(cust->id); - bld->set_id(cust->code); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + cust->code); bld->set_name(cust->name); } } @@ -143,7 +143,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D bld->mutable_building_type()->set_building_type(bt); bld->mutable_building_type()->set_building_subtype(st); bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(siegeengine_type, st)); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(siegeengine_type, st)); } break; @@ -154,7 +154,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D bld->mutable_building_type()->set_building_type(bt); bld->mutable_building_type()->set_building_subtype(st); bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(trap_type, st)); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(trap_type, st)); } break; @@ -177,7 +177,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D bld->mutable_building_type()->set_building_type(bt); bld->mutable_building_type()->set_building_subtype(st); bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(civzone_type, st)); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(civzone_type, st)); } break; @@ -194,7 +194,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D bld->mutable_building_type()->set_building_type(bt); bld->mutable_building_type()->set_building_subtype(st); bld->mutable_building_type()->set_building_custom(-1); - bld->set_id(ENUM_KEY_STR(building_type, bt) + "_" + ENUM_KEY_STR(construction_type, st)); + bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(construction_type, st)); } break; diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 507bd5349..ac06fd160 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -593,7 +593,6 @@ void CopyMat(RemoteFortressReader::MatPair * mat, int type, int index) map hashes; -//check if the tiletypes have changed bool IsTiletypeChanged(DFCoord pos) { uint16_t hash; @@ -612,7 +611,6 @@ bool IsTiletypeChanged(DFCoord pos) map waterHashes; -//check if the designations have changed bool IsDesignationChanged(DFCoord pos) { uint16_t hash; @@ -631,7 +629,6 @@ bool IsDesignationChanged(DFCoord pos) map buildingHashes; -//check if the designations have changed bool IsBuildingChanged(DFCoord pos) { df::map_block * block = Maps::getBlock(pos); @@ -652,7 +649,6 @@ bool IsBuildingChanged(DFCoord pos) map spatterHashes; -//check if map spatters have changed bool IsspatterChanged(DFCoord pos) { df::map_block * block = Maps::getBlock(pos); From 67e60fdaa1844fccda9dd39b6a2b348bc3e499cd Mon Sep 17 00:00:00 2001 From: Quietust Date: Sun, 7 May 2017 13:23:33 -0600 Subject: [PATCH 399/413] Fix issue #874 (revflood doesn't always see past constructed downstairs) --- plugins/reveal.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/plugins/reveal.cpp b/plugins/reveal.cpp index 20b36467e..314259fd4 100644 --- a/plugins/reveal.cpp +++ b/plugins/reveal.cpp @@ -401,12 +401,25 @@ command_result revflood(color_ostream &out, vector & params) if(!MCache->testCoord(current)) continue; - df::tiletype tt = MCache->baseTiletypeAt(current); df::tile_designation des = MCache->designationAt(current); if(!des.bits.hidden) { continue; } + + // use base tile (beneath constructions/ice), to avoid bug #1871 + df::tiletype tt = MCache->baseTiletypeAt(current); + + // unless the actual tile is a downward stairway + df::tiletype ctt = MCache->tiletypeAt(current); + switch (tileShape(ctt)) + { + case tiletype_shape::STAIR_UPDOWN: + case tiletype_shape::STAIR_DOWN: + tt = ctt; + break; + } + bool below = 0; bool above = 0; bool sides = 0; From 8bda7384660c06a83e95e106be56ff4fcbe090e2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 7 May 2017 16:31:30 -0400 Subject: [PATCH 400/413] df_expr_to_ref: support integer array indices --- library/lua/utils.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 07db41808..a6007a08f 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -659,15 +659,17 @@ df_env = df_shortcut_env() function df_expr_to_ref(expr) expr = expr:gsub('%["(.-)"%]', function(field) return '.' .. field end) :gsub('%[\'(.-)\'%]', function(field) return '.' .. field end) + :gsub('%[(%d+)]', function(field) return '.' .. field end) local parts = split_string(expr, '%.') local obj = df_env[parts[1]] for i = 2, #parts do - local cur = obj[parts[i]] + local key = tonumber(parts[i]) or parts[i] + local cur = obj[key] if i == #parts and ((type(cur) ~= 'userdata') or type(cur) == 'userdata' and getmetatable(cur) == nil) then - obj = obj:_field(parts[i]) + obj = obj:_field(key) else - obj = obj[parts[i]] + obj = obj[key] end end return obj From 4dff21897650e97aadd217bc1510a27d2a4780ba Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 May 2017 13:49:07 -0400 Subject: [PATCH 401/413] ruby: fix crash when unloading plugin on Windows --- NEWS.rst | 1 + plugins/ruby/ruby.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 7f7695254..000606863 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -124,6 +124,7 @@ Fixes - `modtools/item-trigger`: fixed errors with plant growths - `remotefortressreader`: fixed a crash when serializing the local map +- `ruby`: fixed a crash when unloading the plugin on Windows - `title-version`: now hidden when loading an arena Misc Improvements diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index ed38868bd..db96e3ed9 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -296,7 +296,7 @@ void (*ruby_sysinit)(int *, const char ***); void (*ruby_init)(void); void (*ruby_init_loadpath)(void); void (*ruby_script)(const char*); -void (*ruby_finalize)(void); +int (*ruby_cleanup)(int); ID (*rb_intern)(const char*); VALUE (*rb_funcall)(VALUE, ID, int, ...); VALUE (*rb_define_module)(const char*); @@ -351,7 +351,7 @@ static int df_loadruby(void) rbloadsym(ruby_init); rbloadsym(ruby_init_loadpath); rbloadsym(ruby_script); - rbloadsym(ruby_finalize); + rbloadsym(ruby_cleanup); rbloadsym(rb_intern); rbloadsym(rb_funcall); rbloadsym(rb_define_module); @@ -476,7 +476,7 @@ static void df_rubythread(void *p) case RB_DIE: running = 0; - ruby_finalize(); + ruby_cleanup(0); break; case RB_EVAL: From 88f9eaeebb2205b70884a19e9a2be25c517f75dc Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 May 2017 13:50:08 -0400 Subject: [PATCH 402/413] stonesense: Disable overlay in STANDARD-based modes Closes dfhack/dfhack#1078 --- NEWS.rst | 1 + plugins/stonesense | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS.rst b/NEWS.rst index 000606863..5360d77c7 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -125,6 +125,7 @@ Fixes - `modtools/item-trigger`: fixed errors with plant growths - `remotefortressreader`: fixed a crash when serializing the local map - `ruby`: fixed a crash when unloading the plugin on Windows +- `stonesense`: disabled overlay in STANDARD-based print modes to prevent crashes - `title-version`: now hidden when loading an arena Misc Improvements diff --git a/plugins/stonesense b/plugins/stonesense index 1ffdc984d..efe406b77 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 1ffdc984d0c3d50e790b9ff5991c02fb21dec463 +Subproject commit efe406b77ba864eb2a7ca66d1f16816c6e0fab7a From 9e32269e90f5b86e2e2fe5a2a2fec0674a36ac93 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 May 2017 13:52:26 -0400 Subject: [PATCH 403/413] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index b48397cf5..665e6d552 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit b48397cf5b4c954a098151943f7314a1a6eacf90 +Subproject commit 665e6d552d3390868e6d76acd5f49ebf938adcd1 From 948e9b2e43c5fbf6b5374d03fffb0f886471cedf Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 May 2017 16:39:10 -0400 Subject: [PATCH 404/413] Update scripts/prefchange (#1080) --- NEWS.rst | 1 + scripts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS.rst b/NEWS.rst index 5360d77c7..1e3fac0cb 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -190,6 +190,7 @@ Misc Improvements - `catsplosion`: now a lua script instead of a plugin - `fix/diplomats`: replaces ``fixdiplomats`` - `fix/merchants`: replaces ``fixmerchants`` +- `prefchange`: added a ``help`` option - Unified script documentation and in-terminal help options Removed diff --git a/scripts b/scripts index e9c3119e7..162f3c3bc 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit e9c3119e751c3e2073eb02bbcda01d140cc6ae4a +Subproject commit 162f3c3bcc35987c53c6f934b77f007ad175c9b7 From 629b4526c69059149563d19015f8adf7e89e67ec Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 10 May 2017 10:40:53 -0400 Subject: [PATCH 405/413] Update NEWS (#874) --- NEWS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.rst b/NEWS.rst index 1e3fac0cb..9fcfd5fa3 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -179,6 +179,7 @@ Fixes - `gui/create-item`: Fixed quality when creating multiple items - `gui/mod-manager`: Fixed error when mods folder doesn't exist - `modtools/item-trigger`: Fixed handling of items with subtypes +- `reveal`: ``revflood`` now handles constructed stairs with floors in generated fortresses - `stockflow`: - Can order metal mechanisms From d083b92e9c866d922c7f33fac1e78e97f8568d57 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 10 May 2017 12:40:57 -0400 Subject: [PATCH 406/413] probe: display tiletype enum names as well --- NEWS.rst | 1 + plugins/probe.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 9fcfd5fa3..9260ad1fc 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -192,6 +192,7 @@ Misc Improvements - `fix/diplomats`: replaces ``fixdiplomats`` - `fix/merchants`: replaces ``fixmerchants`` - `prefchange`: added a ``help`` option +- `probe`: now displays raw tiletype names - Unified script documentation and in-terminal help options Removed diff --git a/plugins/probe.cpp b/plugins/probe.cpp index 94ebc1884..63acfe3da 100644 --- a/plugins/probe.cpp +++ b/plugins/probe.cpp @@ -119,6 +119,7 @@ void describeTile(color_ostream &out, df::tiletype tiletype) out.print("%d", tiletype); if(tileName(tiletype)) out.print(" = %s",tileName(tiletype)); + out.print(" (%s)", ENUM_KEY_STR(tiletype, tiletype).c_str()); out.print("\n"); df::tiletype_shape shape = tileShape(tiletype); From b51e1ad2ef1849a974bec4dff805457a3b59a0e9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 10 May 2017 19:51:11 -0400 Subject: [PATCH 407/413] Add missing anchors to Plugins.rst --- docs/Plugins.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 4b5985ae7..5c7a78c0b 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -101,12 +101,16 @@ Examples: Please report any living/active creatures with cursetype "unknown" - this is most likely with mods which introduce new types of curses. +.. _flows: + flows ===== A tool for checking how many tiles contain flowing liquids. If you suspect that your magma sea leaks into HFS, you can use this tool to be sure without revealing the map. +.. _probe: + probe ===== Can be used to determine tile properties like temperature. @@ -587,6 +591,8 @@ Usage: :confirm enable option1 [option2...]: Enable (or disable) specific confirmation dialogues. +.. _follow: + follow ====== Makes the game view follow the currently highlighted unit after you exit from the From a285175dfc0545b14fdd272c2605996e06ba47a2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 May 2017 21:59:53 -0400 Subject: [PATCH 408/413] Add more missing anchors to Plugins.rst --- docs/Plugins.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 5c7a78c0b..75e3a8f8e 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -996,6 +996,8 @@ Options: **item-type ** Replace the exact item type id in the job item. +.. _job-material: + job-material ============ Alter the material of the selected job. Similar to ``job item-material ...`` @@ -1012,6 +1014,8 @@ Invoked as:: * In :kbd:`b` mode, during selection of building components positions the cursor over the first available choice with the matching material. +.. _job-duplicate: + job-duplicate ============= In :kbd:`q` mode, when a job is highlighted within a workshop or furnace @@ -1203,6 +1207,8 @@ Extra options for ``map``: :mud: Remove mud in addition to the normal stuff. :snow: Also remove snow coverings. +.. _spotclean: + spotclean ========= Works like ``clean map snow mud``, but only for the tile under the cursor. Ideal @@ -1242,6 +1248,7 @@ in the :kbd:`k` list, or inside a container. If called again before the game is resumed, cancels destruction of the item. :dfhack-keybind:`autodump-destroy-item` +.. _cleanowned: cleanowned ========== @@ -1540,6 +1547,8 @@ Examples Stuff up to 50 owned tame male animals who are not grazers into cages built on the current default zone. +.. _autonestbox: + autonestbox =========== Assigns unpastured female egg-layers to nestbox zones. Requires that you create From 787c54d8a709cc45b7d2f93acabe74ffd244890e Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 May 2017 22:01:57 -0400 Subject: [PATCH 409/413] Remove several unused CMake and Doxygen files --- CMake/Modules/CMakeVS10FindMake.cmake | 28 - CMake/Modules/FindCurses.cmake | 23 - CMake/Modules/FindDocutils.cmake | 3 - CMake/Modules/FindDoxygen.cmake | 185 --- library/CMakeLists.txt | 5 - library/doc/CMakeLists.txt | 55 - library/doc/Doxyfile.in | 1554 ------------------------- library/doc/Doxygen.html | 9 - library/doc/img/.dot | 0 library/doc/index.dxgen | 42 - 10 files changed, 1904 deletions(-) delete mode 100644 CMake/Modules/CMakeVS10FindMake.cmake delete mode 100644 CMake/Modules/FindCurses.cmake delete mode 100644 CMake/Modules/FindDocutils.cmake delete mode 100644 CMake/Modules/FindDoxygen.cmake delete mode 100644 library/doc/CMakeLists.txt delete mode 100644 library/doc/Doxyfile.in delete mode 100644 library/doc/Doxygen.html delete mode 100644 library/doc/img/.dot delete mode 100644 library/doc/index.dxgen diff --git a/CMake/Modules/CMakeVS10FindMake.cmake b/CMake/Modules/CMakeVS10FindMake.cmake deleted file mode 100644 index 460de25e5..000000000 --- a/CMake/Modules/CMakeVS10FindMake.cmake +++ /dev/null @@ -1,28 +0,0 @@ - -#============================================================================= -# Copyright 2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distributed this file outside of CMake, substitute the full -# License text for the above reference.) - -# We use MSBuild as the build tool for VS 10 -FIND_PROGRAM(CMAKE_MAKE_PROGRAM - NAMES MSBuild - HINTS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0\\Setup\\VS;ProductDir] - "$ENV{SYSTEMROOT}/Microsoft.NET/Framework/[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;CLR Version]/" - "c:/WINDOWS/Microsoft.NET/Framework/[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;CLR Version]/" - "$ENV{SYSTEMROOT}/Microsoft.NET/Framework/[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\10.0;CLR Version]/" - ) - -MARK_AS_ADVANCED(CMAKE_MAKE_PROGRAM) -SET(MSVC10 1) -SET(MSVC_VERSION 1600) - diff --git a/CMake/Modules/FindCurses.cmake b/CMake/Modules/FindCurses.cmake deleted file mode 100644 index 98adf9815..000000000 --- a/CMake/Modules/FindCurses.cmake +++ /dev/null @@ -1,23 +0,0 @@ -IF(Curses_FOUND) - SET(Curses_FIND_QUIETLY TRUE) -ENDIF() - -FIND_PATH(Curses_INCLUDE_PATH - NAMES ncurses.h curses.h - PATH_SUFFIXES ncurses - PATHS /usr/include/ncursesw /usr/include /usr/local/include /usr/pkg/include -) - -FIND_LIBRARY(Curses_LIBRARY - NAMES ncursesw - PATHS /lib /usr/lib /usr/local/lib /usr/pkg/lib -) - -IF (Curses_INCLUDE_PATH AND Curses_LIBRARY) - SET(Curses_FOUND TRUE) -ENDIF() - -MARK_AS_ADVANCED( - Curses_INCLUDE_PATH - Curses_LIBRARY -) diff --git a/CMake/Modules/FindDocutils.cmake b/CMake/Modules/FindDocutils.cmake deleted file mode 100644 index 8103628df..000000000 --- a/CMake/Modules/FindDocutils.cmake +++ /dev/null @@ -1,3 +0,0 @@ -FIND_PROGRAM(RST2HTML_EXECUTABLE NAMES rst2html rst2html.py) -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Docutils DEFAULT_MSG RST2HTML_EXECUTABLE) \ No newline at end of file diff --git a/CMake/Modules/FindDoxygen.cmake b/CMake/Modules/FindDoxygen.cmake deleted file mode 100644 index 94d20a9ff..000000000 --- a/CMake/Modules/FindDoxygen.cmake +++ /dev/null @@ -1,185 +0,0 @@ -# - This module looks for Doxygen and the path to Graphviz's dot -# Doxygen is a documentation generation tool. Please see -# http://www.doxygen.org -# -# This module accepts the following optional variables: -# -# DOXYGEN_SKIP_DOT = If true this module will skip trying to find Dot -# (an optional component often used by Doxygen) -# -# This modules defines the following variables: -# -# DOXYGEN_EXECUTABLE = The path to the doxygen command. -# DOXYGEN_FOUND = Was Doxygen found or not? -# -# DOXYGEN_DOT_EXECUTABLE = The path to the dot program used by doxygen. -# DOXYGEN_DOT_FOUND = Was Dot found or not? -# DOXYGEN_DOT_PATH = The path to dot not including the executable -# -# - -#Copyright 2000-2009 Kitware, Inc., Insight Software Consortium -#All rights reserved. -# -#Redistribution and use in source and binary forms, with or without -#modification, are permitted provided that the following conditions -#are met: -# -#* Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -#* Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -#* Neither the names of Kitware, Inc., the Insight Software Consortium, -# nor the names of their contributors may be used to endorse or promote -# products derived from this software without specific prior written -# permission. -# -#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -#A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -#HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -#SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -#LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -#DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -#THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -#OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -#----------------------------------------------------------------------------- -# -#The above copyright and license notice applies to distributions of -#CMake in source and binary form. Some source files contain additional -#notices of original copyright by their contributors; see each source -#for details. Third-party software packages supplied with CMake under -#compatible licenses provide their own copyright notices documented in -#corresponding subdirectories. -# -#----------------------------------------------------------------------------- -# -#CMake was initially developed by Kitware with the following sponsorship: -# -# * National Library of Medicine at the National Institutes of Health -# as part of the Insight Segmentation and Registration Toolkit (ITK). -# -# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel -# Visualization Initiative. -# -# * National Alliance for Medical Image Computing (NAMIC) is funded by the -# National Institutes of Health through the NIH Roadmap for Medical Research, -# Grant U54 EB005149. -# -# * Kitware, Inc. - - -# For backwards compatibility support -IF(Doxygen_FIND_QUIETLY) - SET(DOXYGEN_FIND_QUIETLY TRUE) -ENDIF(Doxygen_FIND_QUIETLY) - -# ===== Rationale for OS X AppBundle mods below ===== -# With the OS X GUI version, Doxygen likes to be installed to /Applications and -# it contains the doxygen executable in the bundle. In the versions I've -# seen, it is located in Resources, but in general, more often binaries are -# located in MacOS. -# -# NOTE: The official Doxygen.app that is distributed for OS X uses non-standard -# conventions. Instead of the command-line "doxygen" tool being placed in -# Doxygen.app/Contents/MacOS, "Doxywizard" is placed there instead and -# "doxygen" is placed in Contents/Resources. This is most likely done -# so that something happens when people double-click on the Doxygen.app -# package. Unfortunately, CMake gets confused by this as when it sees the -# bundle it uses "Doxywizard" as the executable to use instead of -# "doxygen". Therefore to work-around this issue we temporarily disable -# the app-bundle feature, just for this CMake module: -if(APPLE) - # Save the old setting - SET(TEMP_DOXYGEN_SAVE_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE}) - # Disable the App-bundle detection feature - SET(CMAKE_FIND_APPBUNDLE "NEVER") -endif() -# FYI: -# In the older versions of OS X Doxygen, dot was included with the -# Doxygen bundle. But the new versions require you to download -# Graphviz.app which contains "dot" in it's bundle. -# ============== End OSX stuff ================ - -# -# Find Doxygen... -# - -FIND_PROGRAM(DOXYGEN_EXECUTABLE - NAMES doxygen - PATHS - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\doxygen_is1;Inno Setup: App Path]/bin" - /Applications/Doxygen.app/Contents/Resources - /Applications/Doxygen.app/Contents/MacOS - DOC "Doxygen documentation generation tool (http://www.doxygen.org)" -) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Doxygen DEFAULT_MSG DOXYGEN_EXECUTABLE) - -# -# Find Dot... -# - -IF(NOT DOXYGEN_SKIP_DOT) - FIND_PROGRAM(DOXYGEN_DOT_EXECUTABLE - NAMES dot - PATHS - "$ENV{ProgramFiles}/Graphviz2.26.3/bin" - "C:/Program Files/Graphviz2.26.3/bin" - "$ENV{ProgramFiles}/Graphviz 2.21/bin" - "C:/Program Files/Graphviz 2.21/bin" - "$ENV{ProgramFiles}/ATT/Graphviz/bin" - "C:/Program Files/ATT/Graphviz/bin" - [HKEY_LOCAL_MACHINE\\SOFTWARE\\ATT\\Graphviz;InstallPath]/bin - /Applications/Graphviz.app/Contents/MacOS - /Applications/Doxygen.app/Contents/Resources - /Applications/Doxygen.app/Contents/MacOS - DOC "Graphviz Dot tool for using Doxygen" - ) - - if(DOXYGEN_DOT_EXECUTABLE) - set(DOXYGEN_DOT_FOUND TRUE) - # The Doxyfile wants the path to Dot, not the entire path and executable - get_filename_component(DOXYGEN_DOT_PATH "${DOXYGEN_DOT_EXECUTABLE}" PATH CACHE) - endif() - -endif(NOT DOXYGEN_SKIP_DOT) - -# -# Backwards compatibility... -# - -if(APPLE) - # Restore the old app-bundle setting setting - SET(CMAKE_FIND_APPBUNDLE ${TEMP_DOXYGEN_SAVE_CMAKE_FIND_APPBUNDLE}) -endif() - -# Maintain the _FOUND variables as "YES" or "NO" for backwards compatibility -# (allows people to stuff them directly into Doxyfile with configure_file()) -if(DOXYGEN_FOUND) - set(DOXYGEN_FOUND "YES") -else() - set(DOXYGEN_FOUND "NO") -endif() -if(DOXYGEN_DOT_FOUND) - set(DOXYGEN_DOT_FOUND "YES") -else() - set(DOXYGEN_DOT_FOUND "NO") -endif() - -# For backwards compatibility support -SET (DOXYGEN ${DOXYGEN_EXECUTABLE} ) -SET (DOT ${DOXYGEN_DOT_EXECUTABLE} ) - -MARK_AS_ADVANCED( - DOXYGEN_EXECUTABLE - DOXYGEN_DOT_EXECUTABLE - DOXYGEN_DOT_PATH - ) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 033c82053..ce73741a2 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -8,7 +8,6 @@ ENDIF() ## build options OPTION(BUILD_DEVEL "Install/package files required for development (For SDK)." OFF) -OPTION(BUILD_DOXYGEN "Create/install/package doxygen documentation for DFHack (For SDK)." OFF) IF(UNIX) OPTION(CONSOLE_NO_CATCH "Make the console not catch 'CTRL+C' events for easier debugging." OFF) ENDIF() @@ -437,8 +436,4 @@ if(BUILD_DEVEL) install(DIRECTORY include/ DESTINATION ${DFHACK_INCLUDES_DESTINATION} FILES_MATCHING PATTERN "*.h" PATTERN "*.inc" ) #linux: include - # Building the docs - IF(BUILD_DOXYGEN) - add_subdirectory (doc) - ENDIF() endif() diff --git a/library/doc/CMakeLists.txt b/library/doc/CMakeLists.txt deleted file mode 100644 index 085f21119..000000000 --- a/library/doc/CMakeLists.txt +++ /dev/null @@ -1,55 +0,0 @@ -# repurposed from libnoise: http://github.com/qknight/libnoise/tree/master/doc/ -# following code and comments is by the original author, with some changes by -# me (peterix) -# ------------------------------------------------------------------------------ -# -# many thanks go to Philippe Poilbarbe for writing the code this file is based on -# http://www.cmake.org/pipermail/cmake/2006-August/010794.html -# -# much later i also found this: -# http://tobias.rautenkranz.ch/cmake/doxygen/ -# but it is hard to understand... - -FIND_PACKAGE(Doxygen QUIET) - -IF(DOXYGEN_FOUND) - SET(DOXYGEN_LANGUAGE "English" CACHE STRING "Language used by doxygen") - MARK_AS_ADVANCED(DOXYGEN_LANGUAGE) - - # you could also set the version with this, see Doxygen.in - # there you will find a line like this: - # PROJECT_NUMBER = @DFHACK_VERSION@ - # @DFHACK_VERSION@ is then replaced by our global DFHACK_VERSION - # - # for instance you could uncomment the next 3 lines and change the version for testing - # SET(DFHACK_VERSION - # "1.2.3-foo500" - # ) - - # doxygen can reference external images with IMAGE_PATH, this is how we set it dynamically - SET( CMAKE_DOXYGEN_IMAGE_PATH - "${CMAKE_CURRENT_SOURCE_DIR}/img" - ) - - # doxygen searches for source code (defined in FILE_PATTERNS, for example: *.cpp *.h) - # with DOXYGEN_SOURCE_DIR we fill a list of directories and later we write it into - # the Doxyfile with a REGEX REPLACE (see below) - SET( DOXYGEN_SOURCE_DIR - "${dfhack_SOURCE_DIR}/library" - ) - - STRING(REGEX REPLACE ";" " " CMAKE_DOXYGEN_INPUT_LIST "${DOXYGEN_SOURCE_DIR}") - set(DOXYFILE_DOT "NO") - if(DOXYGEN_DOT_EXECUTABLE) - set(DOXYFILE_DOT "YES") - endif() - CONFIGURE_FILE(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - ADD_CUSTOM_TARGET(doxygen ALL - ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - - INSTALL( DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html/" DESTINATION ${DFHACK_DEVDOC_DESTINATION}/doxygen ) - INSTALL( FILES "Doxygen.html" DESTINATION ${DFHACK_DEVDOC_DESTINATION}) -ELSE(DOXYGEN_FOUND) - MESSAGE (WARNING "Doxygen binary couldn't be found. Can't build development documentation.'") -ENDIF(DOXYGEN_FOUND) \ No newline at end of file diff --git a/library/doc/Doxyfile.in b/library/doc/Doxyfile.in deleted file mode 100644 index 5ee8f500e..000000000 --- a/library/doc/Doxyfile.in +++ /dev/null @@ -1,1554 +0,0 @@ -# Doxyfile 1.6.3 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = dfhack - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = "@DFHACK_VERSION@" - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = html -# @DOXYGEN_OUTPUT_DIR@ - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = @DOXYGEN_LANGUAGE@ - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it parses. -# With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this tag. -# The format is ext=language, where ext is a file extension, and language is one of -# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, -# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), -# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = YES - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will rougly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = NO - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = YES - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = @CMAKE_DOXYGEN_INPUT_LIST@ - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 - -FILE_PATTERNS = *.cpp \ - *.h \ - *.dxgen - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = Private - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = @CMAKE_DOXYGEN_IMAGE_PATH@ - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = . - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = YES - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. -# For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's -# filter section matches. -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 8 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list. - -USE_INLINE_TREES = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = NO - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be implemented using a PHP enabled web server instead of at the web client using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server based approach is that it scales better to large projects and allows full text search. The disadvances is that it is more difficult to setup -# and does not have live searching capabilities. - -SERVER_BASED_SEARCH = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = NO - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. -# This is useful -# if you want to understand what is going on. -# On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = NO - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = @DOXYFILE_DOT@ - -# By default doxygen will write a font called FreeSans.ttf to the output -# directory and reference it in all dot files that doxygen generates. This -# font does not include all possible unicode characters however, so when you need -# these (or just want a differently looking font) you can specify the font name -# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. - -DOT_FONTNAME = FreeSans - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = YES - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = "@DOXYGEN_DOT_PATH@" - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = YES - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/library/doc/Doxygen.html b/library/doc/Doxygen.html deleted file mode 100644 index da9a6fb65..000000000 --- a/library/doc/Doxygen.html +++ /dev/null @@ -1,9 +0,0 @@ - - - -REDIRECT! - - -This is a redirect to the doxygen stuff. - - diff --git a/library/doc/img/.dot b/library/doc/img/.dot deleted file mode 100644 index e69de29bb..000000000 diff --git a/library/doc/index.dxgen b/library/doc/index.dxgen deleted file mode 100644 index bfb6b2312..000000000 --- a/library/doc/index.dxgen +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* -www.sourceforge.net/projects/dfhack -Copyright (c) 2009 Petr Mrázek (peterix) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -/*! \page index -

    -\htmlonly -

    DFHack

    - -\endhtmlonly -
    - -

    Introduction

    -DFHack is a Dwarf Fortress memory access library and a set of basic tools using -this library. The library is a work in progress, so things might change as more -tools are written for it. - -It is an attempt to unite the various ways tools access DF memory and allow for -easier development of new tools. In general, you can use it to move memory -objects in and out of Dwarf Fortress really fast, regardless of DF version or OS. -*/ - From 98980b82bae9539204e5fb344fc50cc015fe023b Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 13 May 2017 21:54:04 -0400 Subject: [PATCH 410/413] Update Authors.rst dfhack/scripts#18 dfhack/df-structures#186 --- docs/Authors.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 034ff8635..40f2f7748 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -21,6 +21,7 @@ AtomicChicken AtomicChicken belal jimhester Ben Lubar BenLubar Ben Rosser TC01 +brndd brndd Caldfir caldfir Carter Bray Qartar Chris Dombroski cdombroski @@ -63,6 +64,7 @@ melkor217 melkor217 Meneth32 Meph Michael Casadevall NCommander +Michael Crouch creidieki Michon van Dooren MaienM miffedmap miffedmap Mike Stewart thewonderidiot From b9b52963dea1351b0778a0a796edd75f3bb3ea9a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 13 May 2017 21:55:18 -0400 Subject: [PATCH 411/413] Update NEWS.rst dfhack/scripts#18 dfhack/scripts#14 --- NEWS.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 9260ad1fc..ee12e1a32 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -117,10 +117,17 @@ Fixes - Fixed crash when selecting a profession from an empty list - Custom professions are now sorted alphabetically more reliably +- `modtools/create-item`: + + - made gloves usable by specifying handedness + - now creates pairs of boots and gloves + - `modtools/create-unit`: - stopped permanently overwriting the creature creation menu in arena mode - now uses non-English names + - added ``-setUnitToFort`` option to make a unit a civ/group member more easily + - fixed some issues where units would appear in unrevealed areas of the map - `modtools/item-trigger`: fixed errors with plant growths - `remotefortressreader`: fixed a crash when serializing the local map From 01c6416824a7f32e77f77a21a30e53476e3a9c05 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 13 May 2017 21:56:08 -0400 Subject: [PATCH 412/413] Update submodules --- depends/clsocket | 2 +- library/xml | 2 +- scripts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/depends/clsocket b/depends/clsocket index b08d765a7..d1565a3b7 160000 --- a/depends/clsocket +++ b/depends/clsocket @@ -1 +1 @@ -Subproject commit b08d765a7ddacf66693cb2721833b3b56b092aa3 +Subproject commit d1565a3b711514048477e11bc04f60f6218af37f diff --git a/library/xml b/library/xml index 665e6d552..a8e80088b 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 665e6d552d3390868e6d76acd5f49ebf938adcd1 +Subproject commit a8e80088b9cc934da993dc244ece2d0ae14143da diff --git a/scripts b/scripts index 162f3c3bc..0e41c190d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 162f3c3bcc35987c53c6f934b77f007ad175c9b7 +Subproject commit 0e41c190d3f22c71aa7f8e3090d1b7d53c944495 From 2396392b79429028aca2338ed76e4bd1575aff1e Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 13 May 2017 21:58:07 -0400 Subject: [PATCH 413/413] Bump to r1 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 186fabf4f..e261443b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,8 +139,8 @@ endif() # set up versioning. set(DF_VERSION "0.43.05") -SET(DFHACK_RELEASE "beta2") -SET(DFHACK_PRERELEASE TRUE) +SET(DFHACK_RELEASE "r1") +SET(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")

    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