stockpiles: more error handling & cleanup

* prevent crashes when the path doesn't exist
* remove duplicated functions
* sort file list case insensitively
develop
Casey Link 2014-12-04 10:47:17 +01:00
parent 1525823948
commit 2f4678eee5
3 changed files with 68 additions and 41 deletions

@ -72,6 +72,7 @@ void StockpileSerializer::enable_debug ( std::ostream&out )
bool StockpileSerializer::serialize_to_ostream ( std::ostream* output ) bool StockpileSerializer::serialize_to_ostream ( std::ostream* output )
{ {
if ( output->fail( ) ) return false;
mBuffer.Clear(); mBuffer.Clear();
write(); write();
{ {
@ -84,11 +85,17 @@ bool StockpileSerializer::serialize_to_ostream ( std::ostream* output )
bool StockpileSerializer::serialize_to_file ( const std::string & file ) bool StockpileSerializer::serialize_to_file ( const std::string & file )
{ {
std::fstream output ( file, std::ios::out | std::ios::binary | std::ios::trunc ); std::fstream output ( file, std::ios::out | std::ios::binary | std::ios::trunc );
if ( output.fail() )
{
*mOut << "ERROR: failed to open file for writing: " << file << endl;
return false;
}
return serialize_to_ostream ( &output ); return serialize_to_ostream ( &output );
} }
bool StockpileSerializer::parse_from_istream ( std::istream* input ) bool StockpileSerializer::parse_from_istream ( std::istream* input )
{ {
if ( input->fail( ) ) return false;
mBuffer.Clear(); mBuffer.Clear();
io::IstreamInputStream zero_copy_input ( input ); io::IstreamInputStream zero_copy_input ( input );
const bool res = mBuffer.ParseFromZeroCopyStream ( &zero_copy_input ) && input->eof(); const bool res = mBuffer.ParseFromZeroCopyStream ( &zero_copy_input ) && input->eof();
@ -100,6 +107,11 @@ bool StockpileSerializer::parse_from_istream ( std::istream* input )
bool StockpileSerializer::unserialize_from_file ( const std::string & file ) bool StockpileSerializer::unserialize_from_file ( const std::string & file )
{ {
std::fstream input ( file, std::ios::in | std::ios::binary ); std::fstream input ( file, std::ios::in | std::ios::binary );
if ( input.fail() )
{
*mOut << "ERROR: failed to open file for reading: " << file << endl;
return false;
}
return parse_from_istream ( &input ); return parse_from_istream ( &input );
} }

@ -7,8 +7,12 @@
#include "df/creature_raw.h" #include "df/creature_raw.h"
#include "df/plant_raw.h" #include "df/plant_raw.h"
#include <string>
#include <algorithm>
#include <functional>
// os
#include <sys/stat.h>
// Utility Functions {{{ // Utility Functions {{{
// A set of convenience functions for doing common lookups // A set of convenience functions for doing common lookups
@ -48,6 +52,29 @@ static size_t find_plant ( const std::string &plant_id )
return linear_index ( df::global::world->raws.plants.all, &df::plant_raw::id, plant_id ); return linear_index ( df::global::world->raws.plants.all, &df::plant_raw::id, plant_id );
} }
struct less_than_no_case: public std::binary_function< char,char,bool >
{
bool operator () (char x, char y) const
{
return toupper( static_cast< unsigned char >(x)) < toupper( static_cast< unsigned char >(y));
}
};
static bool CompareNoCase(const std::string &a, const std::string &b)
{
return std::lexicographical_compare( a.begin(),a.end(), b.begin(),b.end(), less_than_no_case() );
}
/**
* Checks if the parameter has the dfstock extension.
* Doesn't check if the file exists or not.
*/
static bool is_dfstockfile ( const std::string& filename )
{
return filename.rfind ( ".dfstock" ) != std::string::npos;
}
// }}} utility Functions // }}} utility Functions

@ -9,6 +9,7 @@
#include "../uicommon.h" #include "../uicommon.h"
#include "StockpileUtils.h"
#include "StockpileSerializer.h" #include "StockpileSerializer.h"
@ -25,11 +26,6 @@
#include "df/global_objects.h" #include "df/global_objects.h"
#include "df/viewscreen_dwarfmodest.h" #include "df/viewscreen_dwarfmodest.h"
// os
#include <sys/stat.h>
// stl // stl
#include <functional> #include <functional>
#include <vector> #include <vector>
@ -102,15 +98,9 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
std::cerr << "world: " << sizeof ( df::world ) << " ui: " << sizeof ( df::ui ) std::cerr << "world: " << sizeof ( df::world ) << " ui: " << sizeof ( df::ui )
<< " b_stock: " << sizeof ( building_stockpilest ) << endl; << " b_stock: " << sizeof ( building_stockpilest ) << endl;
if (!Filesystem::isdir("stocksettings")) if ( !Filesystem::isdir ( "stocksettings" ) )
{
if (!Filesystem::mkdir("stocksettings"))
{ {
out.printerr("stockpiles: could not create stocksettings directory!\n");
return CR_FAILURE;
}
} }
// ViewscreenStocks::reset();
return CR_OK; return CR_OK;
} }
@ -125,7 +115,6 @@ DFhackCExport command_result plugin_onstatechange ( color_ostream &out, state_ch
switch ( event ) switch ( event )
{ {
case SC_MAP_LOADED: case SC_MAP_LOADED:
// ViewscreenStocks::reset();
break; break;
default: default:
break; break;
@ -222,23 +211,6 @@ static bool loadstock_guard ( df::viewscreen *top )
} }
} }
static bool file_exists ( const std::string& filename )
{
struct stat buf;
if ( stat ( filename.c_str(), &buf ) != -1 )
{
return true;
}
return false;
}
static bool is_dfstockfile ( const std::string& filename )
{
return filename.rfind ( ".dfstock" ) != std::string::npos;
}
// exporting // exporting
static command_result savestock ( color_ostream &out, vector <string> & parameters ) static command_result savestock ( color_ostream &out, vector <string> & parameters )
{ {
@ -317,7 +289,7 @@ static command_result loadstock ( color_ostream &out, vector <string> & paramete
} }
if ( !is_dfstockfile ( file ) ) file += ".dfstock"; if ( !is_dfstockfile ( file ) ) file += ".dfstock";
if ( file.empty() || !file_exists ( file ) ) if ( file.empty() || !Filesystem::exists ( file ) )
{ {
out.printerr ( "loadstock: a .dfstock file is required to import\n" ); out.printerr ( "loadstock: a .dfstock file is required to import\n" );
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
@ -334,10 +306,11 @@ static command_result loadstock ( color_ostream &out, vector <string> & paramete
return CR_OK; return CR_OK;
} }
/**
* calls the lua function manage_settings() to kickoff the GUI
*/
bool manage_settings ( building_stockpilest *sp ) bool manage_settings ( building_stockpilest *sp )
{ {
// Find strings representing the job to order, and the trigger condition.
// There might be a memory leak here; C++ is odd like that.
auto L = Lua::Core::State; auto L = Lua::Core::State;
color_ostream_proxy out ( Core::getInstance().getConsole() ); color_ostream_proxy out ( Core::getInstance().getConsole() );
@ -395,7 +368,6 @@ struct stockpiles_import_hook : public df::viewscreen_dwarfmodest
int left_margin = dims.menu_x1 + 1; int left_margin = dims.menu_x1 + 1;
int x = left_margin; int x = left_margin;
int y = dims.y2 - 7; int y = dims.y2 - 7;
int y2 = dims.y2 - 8;
int links = 0; int links = 0;
links += sp->links.give_to_pile.size(); links += sp->links.give_to_pile.size();
@ -405,7 +377,6 @@ struct stockpiles_import_hook : public df::viewscreen_dwarfmodest
if ( links + 12 >= y ) if ( links + 12 >= y )
{ {
y += 1; y += 1;
y2 += 1;
} }
OutputHotkeyString ( x, y, "Load/Save Settings", "l", true, left_margin, COLOR_WHITE, COLOR_LIGHTRED ); OutputHotkeyString ( x, y, "Load/Save Settings", "l", true, left_margin, COLOR_WHITE, COLOR_LIGHTRED );
@ -477,6 +448,10 @@ static std::vector<std::string> list_dir ( const std::string &path, bool recursi
static std::vector<std::string> clean_dfstock_list ( const std::string &path ) static std::vector<std::string> clean_dfstock_list ( const std::string &path )
{ {
if ( !Filesystem::exists ( path ) )
{
return std::vector<std::string>();
}
std::vector<std::string> files ( list_dir ( path, true) ); std::vector<std::string> files ( list_dir ( path, true) );
files.erase ( std::remove_if ( files.begin(), files.end(), [] ( const std::string &f ) files.erase ( std::remove_if ( files.begin(), files.end(), [] ( const std::string &f )
{ {
@ -486,16 +461,23 @@ static std::vector<std::string> clean_dfstock_list ( const std::string &path )
{ {
return f.substr ( 0, f.find_last_of ( "." ) ); return f.substr ( 0, f.find_last_of ( "." ) );
} ); } );
std::sort ( files.begin(),files.end(), CompareNoCase );
return files; return files;
} }
static int stockpiles_list_settings ( lua_State *L ) static int stockpiles_list_settings ( lua_State *L )
{ {
auto path = luaL_checkstring ( L, 1 ); auto path = luaL_checkstring ( L, 1 );
if ( !Filesystem::exists ( path ) )
{
lua_pushfstring ( L, "stocksettings path invalid: %s", path );
lua_error ( L );
return 0;
}
color_ostream &out = *Lua::GetOutput ( L ); color_ostream &out = *Lua::GetOutput ( L );
if ( !Filesystem::isdir(path) ) if ( !Filesystem::isdir(path) )
{ {
lua_pushfstring ( L, "invalid directory: %s", path ); lua_pushfstring ( L, "stocksettings path invalid: %s", path );
lua_error ( L ); lua_error ( L );
return 0; return 0;
} }
@ -507,6 +489,11 @@ static int stockpiles_list_settings ( lua_State *L )
static void stockpiles_load ( color_ostream &out, std::string filename ) static void stockpiles_load ( color_ostream &out, std::string filename )
{ {
out << "stockpiles_load " << filename << " "; out << "stockpiles_load " << filename << " ";
if ( !Filesystem::exists ( filename ) )
{
out.printerr ( "invalid file: %s\n", filename.c_str() );
return;
}
std::vector<std::string> params; std::vector<std::string> params;
params.push_back ( filename ); params.push_back ( filename );
command_result r = loadstock ( out, params ); command_result r = loadstock ( out, params );
@ -524,9 +511,10 @@ static void stockpiles_save ( color_ostream &out, std::string filename )
out << " result = "<< r << endl; out << " result = "<< r << endl;
} }
DFHACK_PLUGIN_LUA_FUNCTIONS { DFHACK_PLUGIN_LUA_FUNCTIONS
DFHACK_LUA_FUNCTION(stockpiles_load), {
DFHACK_LUA_FUNCTION(stockpiles_save), DFHACK_LUA_FUNCTION ( stockpiles_load ),
DFHACK_LUA_FUNCTION ( stockpiles_save ),
DFHACK_LUA_END DFHACK_LUA_END
}; };