From 2d6a5e742867f0786f4b0536e6809d623d5c91e8 Mon Sep 17 00:00:00 2001 From: mizipzor Date: Thu, 18 Feb 2010 18:41:36 +0100 Subject: [PATCH 01/11] cleanup of digger tabs to spaces --- tools/digger.cpp | 385 ++++++++++++++++++----------------------------- 1 file changed, 147 insertions(+), 238 deletions(-) diff --git a/tools/digger.cpp b/tools/digger.cpp index 3b875afa6..a667bcb8b 100644 --- a/tools/digger.cpp +++ b/tools/digger.cpp @@ -34,122 +34,84 @@ int vec_count(vector& vec, uint16_t t) return count; } -//// manhattan distance -//int source_distance(int sx, int sy, int sz, -// int x, int y, int z, int i) -//{ -// // TODO changing x and y seems to be optimized away (?) -// cout << x << " " << i << " " << i%16 << " " << x+(i%16) << endl; -// -// // handle the fact that x,y,z refers to a 16x16 grid -// //x += i%16; -// //y += i/16; -// int dx = i%16; -// int dy = i/16; -// //x *= 16; -// //y *= 16; -// //x += dx; -// //y += dy; -// return abs(sx-(x+(i%16)))+abs(sy-(y+(i/16)))+abs(sz-z); -//} - int manhattan_distance(int x, int y, int z, int xx, int yy, int zz) { - return abs(x-xx)+abs(y-yy)+abs(z-zz); + return abs(x-xx)+abs(y-yy)+abs(z-zz); } struct DigTarget { -//public: - DigTarget() : - source_distance(0), - grid_x(0), grid_y(0), - local_x(0), local_y(0), - real_x(0), real_y(0), z(0) - { - } - - DigTarget( - int realx, int realy, int _z, - int sourcex, int sourcey, int sourcez) : - //grid_x(realx/16), grid_y(realy/16), - //local_x(realx%16), local_y(realy%16), - real_x(realx), real_y(realy), z(_z) - { - grid_x = realx/16; - grid_y = realy/16; - - local_x = realx%16; - local_y = realy%16; - - source_distance = manhattan_distance( - real_x, real_y, z, - sourcex, sourcey, sourcez); - } - - DigTarget( - int gridx, int gridy, int _z, - int localx, int localy, - int sourcex, int sourcey, int sourcez) : - //source_distance(manhattan_distance( - // realx, realy, realz, - // sourcex, sourcey, sourcez)), - grid_x(gridx), grid_y(gridy), - local_x(localx), local_y(localy), - z(_z) - //real_x(realx), real_y(realy), real_z(realz) - { - real_x = (grid_x*16)+local_x; - real_y = (grid_y*16)+local_y; - - source_distance = manhattan_distance( - real_x, real_y, z, - sourcex, sourcey, sourcez); - } - - int source_distance; // the distance to the source coords, used for sorting - //int source_distance() const { return _source_distance; } - - int grid_x, grid_y; - int local_x, local_y; - int real_x, real_y; - int z; - //int index; - - //const bool valid; - - bool operator<(const DigTarget& o) const { return source_distance < o.source_distance; } - -//private: -// int source_x, source_y, source_z; -// int _source_distance; + DigTarget() : + source_distance(0), + grid_x(0), grid_y(0), + local_x(0), local_y(0), + real_x(0), real_y(0), z(0) + { + } + + DigTarget( + int realx, int realy, int _z, + int sourcex, int sourcey, int sourcez) : + real_x(realx), real_y(realy), z(_z) + { + grid_x = realx/16; + grid_y = realy/16; + + local_x = realx%16; + local_y = realy%16; + + source_distance = manhattan_distance( + real_x, real_y, z, + sourcex, sourcey, sourcez); + } + + DigTarget( + int gridx, int gridy, int _z, + int localx, int localy, + int sourcex, int sourcey, int sourcez) : + grid_x(gridx), grid_y(gridy), + local_x(localx), local_y(localy), + z(_z) + { + real_x = (grid_x*16)+local_x; + real_y = (grid_y*16)+local_y; + + source_distance = manhattan_distance( + real_x, real_y, z, + sourcex, sourcey, sourcez); + } + + int source_distance; // the distance to the source coords, used for sorting + + int grid_x, grid_y; + int local_x, local_y; + int real_x, real_y; + int z; + + bool operator<(const DigTarget& o) const { return source_distance < o.source_distance; } }; int dig(DFHack::API& DF, - vector& targets, - int num = -1, - const int x_source = 0, - const int y_source = 0, - const int z_source = 0) + vector& targets, + int num = -1, + const int x_source = 0, + const int y_source = 0, + const int z_source = 0) { - if (num == 0) - return 0; // max limit of 0, nothing to do + if (num == 0) + return 0; // max limit of 0, nothing to do uint32_t x_max,y_max,z_max; DFHack::t_designation designations[16][16]; uint16_t tiles[16][16]; - //uint32_t count = 0; DF.getSize(x_max,y_max,z_max); - // every tile found, will later be sorted by distance to source - vector candidates; + // every tile found, will later be sorted by distance to source + vector candidates; - cout << "============================" << endl; - cout << "source is " << x_source << " " << y_source << " " << z_source << endl; + //cout << "============================" << endl; + //cout << "source is " << x_source << " " << y_source << " " << z_source << endl; - //int debugmaxx = 0; - //int debugmaxy = 0; - // walk the map for(uint32_t x = 0; x < x_max; x++) { @@ -157,9 +119,6 @@ int dig(DFHack::API& DF, { for(uint32_t z = 0; z < z_max; z++) { - if (z != z_source) - continue; // hack to cut down on targets - if(DF.isValidBlock(x,y,z)) { // read block designations and tiletype @@ -167,150 +126,100 @@ int dig(DFHack::API& DF, DF.ReadTileTypes(x,y,z, (uint16_t *) tiles); // search all tiles for dig targets: - // visible, not yet marked for dig and matching tile type - for(uint32_t lx = 0; lx < 16; lx++) - { - for(uint32_t ly = 0; ly < 16; ly++) - { - if (designations[lx][ly].bits.hidden == 0 && - designations[lx][ly].bits.dig == 0 && - vec_count(targets, DFHack::tileTypeTable[tiles[lx][ly]].c) > 0) - { - //cout << "target found at: "; - //cout << x << "," << y << "," << z << "," << i << endl; - - //designations[i].bits.dig = DFHack::designation_default; - //++count; - - //int realx = (x*16)+lx; - //int realy = (y*16)+ly; - - candidates.push_back(DigTarget( - x, y, z, - lx, ly, - x_source, y_source, z_source)); - - //cout << "target found at " << world_x << " " << world_y << " " << z; - //cout << ", " << dt->source_distance << " tiles to source" << endl; - - //if (world_x > debugmaxx) - // debugmaxx = world_x; - //if (world_y > debugmaxy) - // debugmaxy = world_y; - } - } // local y + // visible, not yet marked for dig and matching tile type + for(uint32_t lx = 0; lx < 16; lx++) + { + for(uint32_t ly = 0; ly < 16; ly++) + { + if (designations[lx][ly].bits.hidden == 0 && + designations[lx][ly].bits.dig == 0 && + vec_count(targets, DFHack::tileTypeTable[tiles[lx][ly]].c) > 0) + { + candidates.push_back(DigTarget( + x, y, z, + lx, ly, + x_source, y_source, z_source)); + + //cout << "target found at " << world_x << " " << world_y << " " << z; + //cout << ", " << dt->source_distance << " tiles to source" << endl; + } + } // local y } // local x } } } } + // if we found more tiles than was requested, sort them by distance to source, + // keep the front 'num' elements and drop the rest + if (num != -1 && candidates.size() > (unsigned int)num) + { + sort(candidates.begin(), candidates.end()); + candidates.resize(num); + } + num = candidates.size(); - // TODO the following routine doesnt check if the tile is already marked for digging + //cout << "============================" << endl; + //cout << "source is " << x_source << " " << y_source << " " << z_source << endl; - // if we found more tiles than was requested, sort them by distance to source, - // keep the front 'num' elements and drop the rest - if (num != -1 && candidates.size() > (unsigned int)num) - { - sort(candidates.begin(), candidates.end()); - candidates.resize(num); - } - num = candidates.size(); + // mark the tiles for actual digging + for (vector::const_iterator i = candidates.begin(); i != candidates.end(); ++i) + { + //cout << "designating at " << (*i).real_x << " " << (*i).real_y << " " << (*i).z; + //cout << ", " << (*i).source_distance << " tiles to source" << endl; + + // TODO this could probably be made much better, theres a big chance the trees are on the same grid + // TODO move into function in DigTarget + DF.ReadDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations); + designations[(*i).local_x][(*i).local_y].bits.dig = DFHack::designation_default; + DF.WriteDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations); + } - cout << "============================" << endl; - cout << "source is " << x_source << " " << y_source << " " << z_source << endl; + return num; +} - // mark the tiles for actual digging - for (vector::const_iterator i = candidates.begin(); i != candidates.end(); ++i) - { - //int grid_x = (*i).x/16; - //int grid_y = (*i).y/16; - //int z = (*i).z; +void test() +{ + { + DigTarget dt( + 20, 35, 16, + 10, 12, 14); - //int local_x = (*i).x%grid_x; - //int local_y = (*i).y%grid_y; + assert(dt.grid_x == 1); + assert(dt.grid_y == 2); - cout << "designating at " << (*i).real_x << " " << (*i).real_y << " " << (*i).z; - cout << ", " << (*i).source_distance << " tiles to source" << endl; + assert(dt.local_x == 4); + assert(dt.local_y == 3); - // TODO this could probably be made much better, theres a big chance the trees are on the same grid - // TODO move into function in DigTarget - DF.ReadDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations); - designations[(*i).local_x][(*i).local_y].bits.dig = DFHack::designation_default; - DF.WriteDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations); - } + assert(dt.real_x == 20); + assert(dt.real_y == 35); - //cout << debugmaxx << " " << debugmaxy << endl; + assert(dt.z == 16); + assert(dt.source_distance == 35); + } - return num; -} + { + DigTarget dt( + 2, 4, 16, + 5, 10, + 10, 12, 14); -void test() -{ - { - DigTarget dt; - //assert(!dt.valid); - } - - { - DigTarget dt( - 20, 35, 16, - 10, 12, 14); - - assert(dt.grid_x == 1); - assert(dt.grid_y == 2); - - assert(dt.local_x == 4); - assert(dt.local_y == 3); - - assert(dt.real_x == 20); - assert(dt.real_y == 35); - - assert(dt.z == 16); - assert(dt.source_distance == 35); - //assert(dt.valid); - } - - { - DigTarget dt( - 2, 4, 16, - 5, 10, - 10, 12, 14); - - assert(dt.grid_x == 2); - assert(dt.grid_y == 4); - - assert(dt.local_x == 5); - assert(dt.local_y == 10); - - assert(dt.real_x == 37); - assert(dt.real_y == 74); - - assert(dt.z == 16); - assert(dt.source_distance == 91); - //assert(dt.valid); - } - - //{ // sorting - // DigTarget a( - // 20, 35, 16, - // 10, 12, 14); - - // DigTarget b( - // 2, 4, 16, - // 5, 10, - // 10, 12, 14); - - // vector v; - // v.push_back(b); - // v.push_back(a); - // sort(v.begin(), v.end()); - // assert(*(v.begin()) == a); - //} + assert(dt.grid_x == 2); + assert(dt.grid_y == 4); + + assert(dt.local_x == 5); + assert(dt.local_y == 10); + + assert(dt.real_x == 37); + assert(dt.real_y == 74); + + assert(dt.z == 16); + assert(dt.source_distance == 91); + } } int main (int argc, const char* argv[]) { - test(); + test(); vector targets; for (int i = 1; i < argc; ++i) @@ -332,23 +241,23 @@ int main (int argc, const char* argv[]) } DF.InitMap(); - // TODO hack until we have a proper cli to specify origin - int x_source = 134, y_source = 134, z_source = 16; // my wagon starts here; cut trees close to wagon - //DF.InitViewAndCursor(); - //if (!DF.getViewCoords(x_source, y_source, z_source)) - //{ - // cerr << "Enable cursor" << endl; - // return 1; - //} - + // TODO hack until we have a proper cli to specify origin + int x_source = 134, y_source = 134, z_source = 16; // my wagon starts here; cut trees close to wagon + //DF.InitViewAndCursor(); + //if (!DF.getViewCoords(x_source, y_source, z_source)) + //{ + // cerr << "Enable cursor" << endl; + // return 1; + //} + int count = dig(DF, targets, 10, x_source, y_source, z_source); // <-- important part cout << count << " targets designated" << endl; - + DF.Detach(); } - #ifndef LINUX_BUILD +#ifndef LINUX_BUILD cout << "Done. Press any key to continue" << endl; cin.ignore(); - #endif +#endif return 0; } \ No newline at end of file From b81d6d6744aad07049cb4f12d14d71fc89a787e5 Mon Sep 17 00:00:00 2001 From: mizipzor Date: Thu, 18 Feb 2010 18:53:48 +0100 Subject: [PATCH 02/11] added string splitter to digger, to handle comma delimited arguments --- tools/digger.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/tools/digger.cpp b/tools/digger.cpp index a667bcb8b..f0584bfc5 100644 --- a/tools/digger.cpp +++ b/tools/digger.cpp @@ -23,6 +23,7 @@ using namespace std; #include #include +// counts the occurances of a certain element in a vector int vec_count(vector& vec, uint16_t t) { int count = 0; @@ -33,7 +34,27 @@ int vec_count(vector& vec, uint16_t t) } return count; } + +// splits a string on a certain char +// +// src is the string to split +// delim is the delimiter to split the string around +// tokens is filled with every occurance between delims +void string_split(vector& tokens, const std::string& src, const std::string& delim) +{ + std::string::size_type start = 0; + std::string::size_type end; + while (true) + { + end = src.find(delim, start); + tokens.push_back(src.substr(start, end - start)); + if (end == std::string::npos) // last token handled + break; + start = end + delim.size(); // skip next delim + } +} +// calculates the manhattan distance between two coords int manhattan_distance(int x, int y, int z, int xx, int yy, int zz) { return abs(x-xx)+abs(y-yy)+abs(z-zz); @@ -179,6 +200,8 @@ int dig(DFHack::API& DF, void test() { + ////////////////////////// + // DigTarget { DigTarget dt( 20, 35, 16, @@ -196,7 +219,6 @@ void test() assert(dt.z == 16); assert(dt.source_distance == 35); } - { DigTarget dt( 2, 4, 16, @@ -215,6 +237,29 @@ void test() assert(dt.z == 16); assert(dt.source_distance == 91); } + + ////////////////////////// + // string splitter + { + vector tokens; + string src = "10,9,11"; + string delim = ","; + string_split(tokens, src, delim); + + assert(tokens.size() == 3); + assert(tokens[0] == "10"); + assert(tokens[1] == "9"); + assert(tokens[2] == "11"); + } + { + vector tokens; + string src = "10"; + string delim = ","; + string_split(tokens, src, delim); + + assert(tokens.size() == 1); + assert(tokens[0] == "10"); + } } int main (int argc, const char* argv[]) From 53d32e6076dd9b50aa5ea2888b4edd3ead1c5fa6 Mon Sep 17 00:00:00 2001 From: mizipzor Date: Fri, 19 Feb 2010 18:17:58 +0100 Subject: [PATCH 03/11] fixed line endings (visual studio bugged me about it) --- tools/digger.cpp | 587 ++++++++++++++++++++++++----------------------- 1 file changed, 297 insertions(+), 290 deletions(-) diff --git a/tools/digger.cpp b/tools/digger.cpp index f0584bfc5..b9b503f4c 100644 --- a/tools/digger.cpp +++ b/tools/digger.cpp @@ -1,39 +1,40 @@ -// digger.cpp - -// Usage: Call with a list of TileClass ids separated by a space, -// every (visible) tile on the map with that id will be designated for digging. - -// NOTE currently only works with trees - -// TODO add a sort of "sub-target" to dig() to make it able to designate stone as well -// TODO add proper cli -// TODO add interactive text based menu -// TODO add ability to mark num closest to cursor - -#include -#include -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -#include - -// counts the occurances of a certain element in a vector -int vec_count(vector& vec, uint16_t t) -{ - int count = 0; - for (uint32_t i = 0; i < vec.size(); ++i) - { - if (vec[i] == t) - ++count; - } - return count; -} +// digger.cpp + +// Usage: Call with a list of TileClass ids separated by a space, +// every (visible) tile on the map with that id will be designated for digging. + +// NOTE currently only works with trees + +// TODO add a sort of "sub-target" to dig() to make it able to designate stone as well +// TODO add proper cli +// TODO add interactive text based menu +// TODO add ability to mark num closest to cursor + +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +#include + +// counts the occurances of a certain element in a vector +int vec_count(vector& vec, uint16_t t) +{ + int count = 0; + for (uint32_t i = 0; i < vec.size(); ++i) + { + if (vec[i] == t) + ++count; + } + return count; +} // splits a string on a certain char // @@ -52,257 +53,263 @@ void string_split(vector& tokens, const std::string& src, const std::str break; start = end + delim.size(); // skip next delim } -} - -// calculates the manhattan distance between two coords -int manhattan_distance(int x, int y, int z, int xx, int yy, int zz) -{ - return abs(x-xx)+abs(y-yy)+abs(z-zz); -} - -struct DigTarget -{ - DigTarget() : - source_distance(0), - grid_x(0), grid_y(0), - local_x(0), local_y(0), - real_x(0), real_y(0), z(0) - { - } - - DigTarget( - int realx, int realy, int _z, - int sourcex, int sourcey, int sourcez) : - real_x(realx), real_y(realy), z(_z) - { - grid_x = realx/16; - grid_y = realy/16; - - local_x = realx%16; - local_y = realy%16; - - source_distance = manhattan_distance( - real_x, real_y, z, - sourcex, sourcey, sourcez); - } - - DigTarget( - int gridx, int gridy, int _z, - int localx, int localy, - int sourcex, int sourcey, int sourcez) : - grid_x(gridx), grid_y(gridy), - local_x(localx), local_y(localy), - z(_z) - { - real_x = (grid_x*16)+local_x; - real_y = (grid_y*16)+local_y; - - source_distance = manhattan_distance( - real_x, real_y, z, - sourcex, sourcey, sourcez); - } - - int source_distance; // the distance to the source coords, used for sorting - - int grid_x, grid_y; - int local_x, local_y; - int real_x, real_y; - int z; - - bool operator<(const DigTarget& o) const { return source_distance < o.source_distance; } -}; - -int dig(DFHack::API& DF, - vector& targets, - int num = -1, - const int x_source = 0, - const int y_source = 0, - const int z_source = 0) -{ - if (num == 0) - return 0; // max limit of 0, nothing to do - - uint32_t x_max,y_max,z_max; - DFHack::t_designation designations[16][16]; - uint16_t tiles[16][16]; - DF.getSize(x_max,y_max,z_max); - - // every tile found, will later be sorted by distance to source - vector candidates; - - //cout << "============================" << endl; - //cout << "source is " << x_source << " " << y_source << " " << z_source << endl; - - // walk the map - for(uint32_t x = 0; x < x_max; x++) - { - for(uint32_t y = 0; y < y_max; y++) - { - for(uint32_t z = 0; z < z_max; z++) - { - if(DF.isValidBlock(x,y,z)) - { - // read block designations and tiletype - DF.ReadDesignations(x,y,z, (uint32_t *) designations); - DF.ReadTileTypes(x,y,z, (uint16_t *) tiles); - - // search all tiles for dig targets: - // visible, not yet marked for dig and matching tile type - for(uint32_t lx = 0; lx < 16; lx++) - { - for(uint32_t ly = 0; ly < 16; ly++) - { - if (designations[lx][ly].bits.hidden == 0 && - designations[lx][ly].bits.dig == 0 && - vec_count(targets, DFHack::tileTypeTable[tiles[lx][ly]].c) > 0) - { - candidates.push_back(DigTarget( - x, y, z, - lx, ly, - x_source, y_source, z_source)); - - //cout << "target found at " << world_x << " " << world_y << " " << z; - //cout << ", " << dt->source_distance << " tiles to source" << endl; - } - } // local y - } // local x - } - } - } - } - // if we found more tiles than was requested, sort them by distance to source, - // keep the front 'num' elements and drop the rest - if (num != -1 && candidates.size() > (unsigned int)num) - { - sort(candidates.begin(), candidates.end()); - candidates.resize(num); - } - num = candidates.size(); - - //cout << "============================" << endl; - //cout << "source is " << x_source << " " << y_source << " " << z_source << endl; - - // mark the tiles for actual digging - for (vector::const_iterator i = candidates.begin(); i != candidates.end(); ++i) - { - //cout << "designating at " << (*i).real_x << " " << (*i).real_y << " " << (*i).z; - //cout << ", " << (*i).source_distance << " tiles to source" << endl; - - // TODO this could probably be made much better, theres a big chance the trees are on the same grid - // TODO move into function in DigTarget - DF.ReadDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations); - designations[(*i).local_x][(*i).local_y].bits.dig = DFHack::designation_default; - DF.WriteDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations); - } - - return num; -} - -void test() -{ - ////////////////////////// - // DigTarget - { - DigTarget dt( - 20, 35, 16, - 10, 12, 14); - - assert(dt.grid_x == 1); - assert(dt.grid_y == 2); - - assert(dt.local_x == 4); - assert(dt.local_y == 3); - - assert(dt.real_x == 20); - assert(dt.real_y == 35); - - assert(dt.z == 16); - assert(dt.source_distance == 35); - } - { - DigTarget dt( - 2, 4, 16, - 5, 10, - 10, 12, 14); - - assert(dt.grid_x == 2); - assert(dt.grid_y == 4); - - assert(dt.local_x == 5); - assert(dt.local_y == 10); - - assert(dt.real_x == 37); - assert(dt.real_y == 74); - - assert(dt.z == 16); - assert(dt.source_distance == 91); - } - - ////////////////////////// - // string splitter - { - vector tokens; - string src = "10,9,11"; - string delim = ","; - string_split(tokens, src, delim); - - assert(tokens.size() == 3); - assert(tokens[0] == "10"); - assert(tokens[1] == "9"); - assert(tokens[2] == "11"); - } - { - vector tokens; - string src = "10"; - string delim = ","; - string_split(tokens, src, delim); - - assert(tokens.size() == 1); - assert(tokens[0] == "10"); - } -} - -int main (int argc, const char* argv[]) -{ - test(); - - vector targets; - for (int i = 1; i < argc; ++i) - { - targets.push_back(atoi(argv[i])); - } - if (targets.size() == 0) - { - cout << "Usage: Call with a list of TileClass ids separated by a space,\n"; - cout << "every (visible) tile on the map with that id will be designated for digging.\n\n"; - } - else - { - DFHack::API DF("Memory.xml"); - if(!DF.Attach()) - { - cerr << "DF not found" << endl; - return 1; - } - DF.InitMap(); - - // TODO hack until we have a proper cli to specify origin - int x_source = 134, y_source = 134, z_source = 16; // my wagon starts here; cut trees close to wagon - //DF.InitViewAndCursor(); - //if (!DF.getViewCoords(x_source, y_source, z_source)) - //{ - // cerr << "Enable cursor" << endl; - // return 1; - //} - - int count = dig(DF, targets, 10, x_source, y_source, z_source); // <-- important part - cout << count << " targets designated" << endl; - - DF.Detach(); - } -#ifndef LINUX_BUILD - cout << "Done. Press any key to continue" << endl; - cin.ignore(); -#endif - return 0; -} \ No newline at end of file +} + +// calculates the manhattan distance between two coords +int manhattan_distance(int x, int y, int z, int xx, int yy, int zz) +{ + return abs(x-xx)+abs(y-yy)+abs(z-zz); +} + +struct DigTarget +{ + DigTarget() : + source_distance(0), + grid_x(0), grid_y(0), + local_x(0), local_y(0), + real_x(0), real_y(0), z(0) + { + } + + DigTarget( + int realx, int realy, int _z, + int sourcex, int sourcey, int sourcez) : + real_x(realx), real_y(realy), z(_z) + { + grid_x = realx/16; + grid_y = realy/16; + + local_x = realx%16; + local_y = realy%16; + + source_distance = manhattan_distance( + real_x, real_y, z, + sourcex, sourcey, sourcez); + } + + DigTarget( + int gridx, int gridy, int _z, + int localx, int localy, + int sourcex, int sourcey, int sourcez) : + grid_x(gridx), grid_y(gridy), + local_x(localx), local_y(localy), + z(_z) + { + real_x = (grid_x*16)+local_x; + real_y = (grid_y*16)+local_y; + + source_distance = manhattan_distance( + real_x, real_y, z, + sourcex, sourcey, sourcez); + } + + int source_distance; // the distance to the source coords, used for sorting + + int grid_x, grid_y; + int local_x, local_y; + int real_x, real_y; + int z; + + bool operator<(const DigTarget& o) const { return source_distance < o.source_distance; } +}; + +int dig(DFHack::API& DF, + vector& targets, + int num = -1, + const int x_source = 0, + const int y_source = 0, + const int z_source = 0) +{ + if (num == 0) + return 0; // max limit of 0, nothing to do + + uint32_t x_max,y_max,z_max; + DFHack::t_designation designations[16][16]; + uint16_t tiles[16][16]; + DF.getSize(x_max,y_max,z_max); + + // every tile found, will later be sorted by distance to source + vector candidates; + + //cout << "============================" << endl; + //cout << "source is " << x_source << " " << y_source << " " << z_source << endl; + + // walk the map + for(uint32_t x = 0; x < x_max; x++) + { + for(uint32_t y = 0; y < y_max; y++) + { + for(uint32_t z = 0; z < z_max; z++) + { + if(DF.isValidBlock(x,y,z)) + { + // read block designations and tiletype + DF.ReadDesignations(x,y,z, (uint32_t *) designations); + DF.ReadTileTypes(x,y,z, (uint16_t *) tiles); + + // search all tiles for dig targets: + // visible, not yet marked for dig and matching tile type + for(uint32_t lx = 0; lx < 16; lx++) + { + for(uint32_t ly = 0; ly < 16; ly++) + { + if (designations[lx][ly].bits.hidden == 0 && + designations[lx][ly].bits.dig == 0 && + vec_count(targets, DFHack::tileTypeTable[tiles[lx][ly]].c) > 0) + { + candidates.push_back(DigTarget( + x, y, z, + lx, ly, + x_source, y_source, z_source)); + + //cout << "target found at " << world_x << " " << world_y << " " << z; + //cout << ", " << dt->source_distance << " tiles to source" << endl; + } + } // local y + } // local x + } + } + } + } + // if we found more tiles than was requested, sort them by distance to source, + // keep the front 'num' elements and drop the rest + if (num != -1 && candidates.size() > (unsigned int)num) + { + sort(candidates.begin(), candidates.end()); + candidates.resize(num); + } + num = candidates.size(); + + //cout << "============================" << endl; + //cout << "source is " << x_source << " " << y_source << " " << z_source << endl; + + // mark the tiles for actual digging + for (vector::const_iterator i = candidates.begin(); i != candidates.end(); ++i) + { + //cout << "designating at " << (*i).real_x << " " << (*i).real_y << " " << (*i).z; + //cout << ", " << (*i).source_distance << " tiles to source" << endl; + + // TODO this could probably be made much better, theres a big chance the trees are on the same grid + // TODO move into function in DigTarget + DF.ReadDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations); + designations[(*i).local_x][(*i).local_y].bits.dig = DFHack::designation_default; + DF.WriteDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations); + } + + return num; +} + +void test() +{ + ////////////////////////// + // DigTarget + { + DigTarget dt( + 20, 35, 16, + 10, 12, 14); + + assert(dt.grid_x == 1); + assert(dt.grid_y == 2); + + assert(dt.local_x == 4); + assert(dt.local_y == 3); + + assert(dt.real_x == 20); + assert(dt.real_y == 35); + + assert(dt.z == 16); + assert(dt.source_distance == 35); + } + { + DigTarget dt( + 2, 4, 16, + 5, 10, + 10, 12, 14); + + assert(dt.grid_x == 2); + assert(dt.grid_y == 4); + + assert(dt.local_x == 5); + assert(dt.local_y == 10); + + assert(dt.real_x == 37); + assert(dt.real_y == 74); + + assert(dt.z == 16); + assert(dt.source_distance == 91); + } + + ////////////////////////// + // string splitter + { + vector tokens; + string src = "10,9,11"; + string delim = ","; + string_split(tokens, src, delim); + + assert(tokens.size() == 3); + assert(tokens[0] == "10"); + assert(tokens[1] == "9"); + assert(tokens[2] == "11"); + } + { + vector tokens; + string src = "10"; + string delim = ","; + string_split(tokens, src, delim); + + assert(tokens.size() == 1); + assert(tokens[0] == "10"); + } +} + +int main (int argc, const char* argv[]) +{ + test(); + void *options= gopt_sort( & argc, argv, gopt_start( + gopt_option( 'h', 0, gopt_shorts( 'h', '?' ), gopt_longs( "help", "HELP" )), + gopt_option( 'z', 0, gopt_shorts( 0 ), gopt_longs( "version" )), + gopt_option( 'v', GOPT_REPEAT, gopt_shorts( 'v' ), gopt_longs( "verbose" )), + gopt_option( 'o', GOPT_ARG, gopt_shorts( 'o' ), gopt_longs( "output" )))); + + + vector targets; + for (int i = 1; i < argc; ++i) + { + targets.push_back(atoi(argv[i])); + } + if (targets.size() == 0) + { + cout << "Usage: Call with a list of TileClass ids separated by a space,\n"; + cout << "every (visible) tile on the map with that id will be designated for digging.\n\n"; + } + else + { + DFHack::API DF("Memory.xml"); + if(!DF.Attach()) + { + cerr << "DF not found" << endl; + return 1; + } + DF.InitMap(); + + // TODO hack until we have a proper cli to specify origin + int x_source = 134, y_source = 134, z_source = 16; // my wagon starts here; cut trees close to wagon + //DF.InitViewAndCursor(); + //if (!DF.getViewCoords(x_source, y_source, z_source)) + //{ + // cerr << "Enable cursor" << endl; + // return 1; + //} + + int count = dig(DF, targets, 10, x_source, y_source, z_source); // <-- important part + cout << count << " targets designated" << endl; + + DF.Detach(); + } +#ifndef LINUX_BUILD + cout << "Done. Press any key to continue" << endl; + cin.ignore(); +#endif + return 0; +} From 7ab1fcd01976cd94ea7470a3aa76f4f3d6d0ec8d Mon Sep 17 00:00:00 2001 From: mizipzor Date: Fri, 19 Feb 2010 19:04:55 +0100 Subject: [PATCH 04/11] added proper exports to gopt.h renamed gopt.c to gopt.cpp --- library/gopt/{gopt.c => gopt.cpp} | 0 library/gopt/gopt.h | 14 ++++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) rename library/gopt/{gopt.c => gopt.cpp} (100%) diff --git a/library/gopt/gopt.c b/library/gopt/gopt.cpp similarity index 100% rename from library/gopt/gopt.c rename to library/gopt/gopt.cpp diff --git a/library/gopt/gopt.h b/library/gopt/gopt.h index 93885a12f..f6c452f64 100644 --- a/library/gopt/gopt.h +++ b/library/gopt/gopt.h @@ -20,6 +20,8 @@ read http://www.purposeful.co.uk/tfl/ #ifndef GOPT_H_INCLUDED #define GOPT_H_INCLUDED +#include + #define GOPT_ONCE 0 #define GOPT_REPEAT 1 #define GOPT_NOARG 0 @@ -31,29 +33,29 @@ read http://www.purposeful.co.uk/tfl/ #define gopt_longs( ... ) (const char**)(const char*[]){ __VA_ARGS__, NULL } -void *gopt_sort( int *argc, const char **argv, const void *opt_specs ); +DFHACK_EXPORT void *gopt_sort( int *argc, const char **argv, const void *opt_specs ); /* returns a pointer for use in the following calls * prints to stderr and call exit() on error */ -size_t gopt( const void *opts, int key ); +DFHACK_EXPORT size_t gopt( const void *opts, int key ); /* returns the number of times the option was specified * which will be 0 or 1 unless GOPT_REPEAT was used */ -size_t gopt_arg( const void *opts, int key, const char **arg ); +DFHACK_EXPORT size_t gopt_arg( const void *opts, int key, const char **arg ); /* returns the number of times the option was specified * writes a pointer to the option argument from the first (or only) occurance to *arg */ -const char *gopt_arg_i( const void *opts, int key, size_t i ); +DFHACK_EXPORT const char *gopt_arg_i( const void *opts, int key, size_t i ); /* returns a pointer to the ith (starting at zero) occurance * of the option, or NULL if it was not specified that many times */ -size_t gopt_args( const void *opts, int key, const char **args, size_t args_len ); +DFHACK_EXPORT size_t gopt_args( const void *opts, int key, const char **args, size_t args_len ); /* returns the number of times the option was specified * writes pointers to the option arguments in the order of occurance to args[]. * writes at most args_len pointers * if the return value is less than args_len, also writes a null pointer */ -void gopt_free( void *opts ); +DFHACK_EXPORT void gopt_free( void *opts ); /* releases memory allocated in the corresponding call to gopt_sort() * opts can no longer be used */ From 6586bba48c9db6d624ef84ed0786706ad6a0708e Mon Sep 17 00:00:00 2001 From: mizipzor Date: Fri, 19 Feb 2010 20:48:17 +0100 Subject: [PATCH 05/11] added argstream --- library/argstream/argstream.h | 813 ++++++++++++++++++++++++++++++++++ 1 file changed, 813 insertions(+) create mode 100644 library/argstream/argstream.h diff --git a/library/argstream/argstream.h b/library/argstream/argstream.h new file mode 100644 index 000000000..8b55e294a --- /dev/null +++ b/library/argstream/argstream.h @@ -0,0 +1,813 @@ +/* Copyright (C) 2004 Xavier Décoret +* + * argsteam is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ARGSTREAM_H +#define ARGSTREAM_H + + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + class argstream; + + template + class ValueHolder; + + template + argstream& operator>> (argstream&, const ValueHolder&); + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValueHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValueHolder + { + public: + ValueHolder(char s, + const char* l, + T& b, + const char* desc, + bool mandatory); + ValueHolder(const char* l, + T& b, + const char* desc, + bool mandatory); + ValueHolder(char s, + T& b, + const char* desc, + bool mandatory); + friend argstream& operator>><>(argstream& s,const ValueHolder& v); + std::string name() const; + std::string description() const; + private: + std::string shortName_; + std::string longName_; + T* value_; + T initialValue_; + std::string description_; + bool mandatory_; + }; + template + inline ValueHolder + parameter(char s, + const char* l, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(s,l,b,desc,mandatory); + } + template + inline ValueHolder + parameter(char s, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(s,b,desc,mandatory); + } + template + inline ValueHolder + parameter(const char* l, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(l,b,desc,mandatory); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of OptionHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + class OptionHolder + { + public: + inline OptionHolder(char s, + const char* l, + bool& b, + const char* desc); + inline OptionHolder(const char* l, + bool& b, + const char* desc); + inline OptionHolder(char s, + bool& b, + const char* desc); + friend argstream& operator>>(argstream& s,const OptionHolder& v); + inline std::string name() const; + inline std::string description() const; + protected: + inline OptionHolder(char s, + const char* l, + const char* desc); + friend OptionHolder help(char s='h', + const char* l="help", + const char* desc="Display this help"); + private: + std::string shortName_; + std::string longName_; + bool* value_; + std::string description_; + }; + inline OptionHolder + option(char s, + const char* l, + bool& b, + const char* desc="") + { + return OptionHolder(s,l,b,desc); + } + inline OptionHolder + option(char s, + bool& b, + const char* desc="") + { + return OptionHolder(s,b,desc); + } + inline OptionHolder + option(const char* l, + bool& b, + const char* desc="") + { + return OptionHolder(l,b,desc); + } + inline OptionHolder + help(char s, + const char* l, + const char* desc) + { + return OptionHolder(s,l,desc); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValuesHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValuesHolder + { + public: + ValuesHolder(const O& o, + const char* desc, + int len); + friend argstream& operator>><>(argstream& s,const ValuesHolder& v); + std::string name() const; + std::string description() const; + typedef T value_type; + private: + mutable O value_; + std::string description_; + int len_; + char letter_; + }; + template + inline ValuesHolder + values(const O& o, + const char* desc="", + int len=-1) + { + return ValuesHolder(o,desc,len); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValueParser + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValueParser + { + public: + inline T operator()(const std::string& s) const + { + std::istringstream is(s); + T t; + is>>t; + return t; + } + }; + // We need to specialize for string otherwise parsing of a value that + // contains space (for example a string with space passed in quotes on the + // command line) would parse only the first element of the value!!! + template <> + class ValueParser + { + public: + inline std::string operator()(const std::string& s) const + { + return s; + } + }; + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of argstream + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + class argstream + { + public: + inline argstream(int argc,char** argv); + inline argstream(const char* c); + template + friend argstream& operator>>(argstream& s,const ValueHolder& v); + friend inline argstream& operator>>(argstream& s,const OptionHolder& v); + template + friend argstream& operator>>(argstream& s,const ValuesHolder& v); + + inline bool helpRequested() const; + inline bool isOk() const; + inline std::string errorLog() const; + inline std::string usage() const; + inline void defaultErrorHandling(bool ignoreUnused=false) const; + static inline char uniqueLetter(); + protected: + void parse(int argc,char** argv); + private: + typedef std::list::iterator value_iterator; + typedef std::pair help_entry; + std::string progName_; + std::map options_; + std::list values_; + bool minusActive_; + bool isOk_; + std::deque argHelps_; + std::string cmdLine_; + std::deque errors_; + bool helpRequested_; + }; + //************************************************************ + // Implementation of ValueHolder + //************************************************************ + template + ValueHolder::ValueHolder(char s, + const char* l, + T& v, + const char* desc, + bool mandatory) + : shortName_(1,s), + longName_(l), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + ValueHolder::ValueHolder(const char* l, + T& v, + const char* desc, + bool mandatory) + : longName_(l), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + ValueHolder::ValueHolder(char s, + T& v, + const char* desc, + bool mandatory) + : shortName_(1,s), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + std::string + ValueHolder::name() const + { + std::ostringstream os; + if (!shortName_.empty()) os<<'-'< + std::string + ValueHolder::description() const + { + std::ostringstream os; + os< + //************************************************************ + template + ValuesHolder::ValuesHolder(const O& o, + const char* desc, + int len) + : value_(o), + description_(desc), + len_(len) + { + letter_ = argstream::uniqueLetter(); + } + template + std::string + ValuesHolder::name() const + { + std::ostringstream os; + os< + std::string + ValuesHolder::description() const + { + return description_; + } + //************************************************************ + // Implementation of argstream + //************************************************************ + inline + argstream::argstream(int argc,char** argv) + : progName_(argv[0]), + minusActive_(true), + isOk_(true) + { + parse(argc,argv); + } + inline + argstream::argstream(const char* c) + : progName_(""), + minusActive_(true), + isOk_(true) + { + std::string s(c); + // Build argc, argv from s. We must add a dummy first element for + // progName because parse() expects it!! + std::deque args; + args.push_back(""); + std::istringstream is(s); + while (is.good()) + { + std::string t; + is>>t; + args.push_back(t); + } + char* pargs[args.size()]; + char** p = pargs; + for (std::deque::const_iterator + iter = args.begin(); + iter != args.end();++iter) + { + *p++ = const_cast(iter->c_str()); + } + parse(args.size(),pargs); + } + inline void + argstream::parse(int argc,char** argv) + { + // Run thru all arguments. + // * it has -- in front : it is a long name option, if remainder is empty, + // it is an error + // * it has - in front : it is a sequence of short name options, if + // remainder is empty, deactivates option (- will + // now be considered a char). + // * if any other char, or if option was deactivated + // : it is a value. Values are split in parameters + // (immediately follow an option) and pure values. + // Each time a value is parsed, if the previously parsed argument was an + // option, then the option is linked to the value in case of it is a + // option with parameter. The subtle point is that when several options + // are given with short names (ex: -abc equivalent to -a -b -c), the last + // parsed option is -c). + // Since we use map for option, any successive call overides the previous + // one: foo -a -b -a hello is equivalent to foo -b -a hello + // For values it is not true since we might have several times the same + // value. + value_iterator* lastOption = NULL; + for (char** a = argv,**astop=a+argc;++a!=astop;) + { + std::string s(*a); + if (minusActive_ && s[0] == '-') + { + if (s.size() > 1 && s[1] == '-') + { + if (s.size() == 2) + { + minusActive_ = false; + continue; + } + lastOption = &(options_[s.substr(2)] = values_.end()); + } + else + { + if (s.size() > 1) + { + // Parse all chars, if it is a minus we have an error + for (std::string::const_iterator cter = s.begin(); + ++cter != s.end();) + { + if (*cter == '-') + { + isOk_ = false; + std::ostringstream os; + os<<"- in the middle of a switch "<::const_iterator + iter = options_.begin();iter != options_.end();++iter) + { + std::cout<<"DEBUG: option "<first; + if (iter->second != values_.end()) + { + std::cout<<" -> "<<*(iter->second); + } + std::cout<::const_iterator + iter = values_.begin();iter != values_.end();++iter) + { + std::cout<<"DEBUG: value "<<*iter<::const_iterator + iter = argHelps_.begin();iter != argHelps_.end();++iter) + { + if (lmaxfirst.size()) lmax = iter->first.size(); + } + for (std::deque::const_iterator + iter = argHelps_.begin();iter != argHelps_.end();++iter) + { + os<<'\t'<first<first.size(),' ') + <<" : "<second<<'\n'; + } + return os.str(); + } + inline std::string + argstream::errorLog() const + { + std::string s; + for(std::deque::const_iterator iter = errors_.begin(); + iter != errors_.end();++iter) + { + s += *iter; + s += '\n'; + } + return s; + } + inline char + argstream::uniqueLetter() + { + static unsigned int c = 'a'; + return c++; + } + template + argstream& + operator>>(argstream& s,const ValueHolder& v) + { + // Search in the options if there is any such option defined either with a + // short name or a long name. If both are found, only the last one is + // used. +#ifdef ARGSTREAM_DEBUG + std::cout<<"DEBUG: searching "<::iterator iter = + s.options_.find(v.shortName_); + if (iter == s.options_.end()) + { + iter = s.options_.find(v.longName_); + } + if (iter != s.options_.end()) + { + // If we find counterpart for value holder on command line, either it + // has an associated value in which case we assign it, or it has not, in + // which case we have an error. + if (iter->second != s.values_.end()) + { +#ifdef ARGSTREAM_DEBUG + std::cout<<"DEBUG: found value "<<*(iter->second)< p; + *(v.value_) = p(*(iter->second)); + // The option and its associated value are removed, the subtle thing + // is that someother options might have this associated value too, + // which we must invalidate. + s.values_.erase(iter->second); + for (std::map::iterator + jter = s.options_.begin();jter != s.options_.end();++jter) + { + if (jter->second == iter->second) + { + jter->second = s.values_.end(); + } + } + s.options_.erase(iter); + } + else + { + s.isOk_ = false; + std::ostringstream os; + os<<"No value following switch "<first + <<" on command line"; + s.errors_.push_back(os.str()); + } + } + else + { + if (v.mandatory_) + { + s.isOk_ = false; + std::ostringstream os; + os<<"Mandatory parameter "; + if (!v.shortName_.empty()) os<<'-'<>(argstream& s,const OptionHolder& v) + { + // Search in the options if there is any such option defined either with a + // short name or a long name. If both are found, only the last one is + // used. +#ifdef ARGSTREAM_DEBUG + std::cout<<"DEBUG: searching "<::iterator iter = + s.options_.find(v.shortName_); + if (iter == s.options_.end()) + { + iter = s.options_.find(v.longName_); + } + if (iter != s.options_.end()) + { + // If we find counterpart for value holder on command line then the + // option is true and if an associated value was found, it is ignored + if (v.value_ != NULL) + { + *(v.value_) = true; + } + else + { + s.helpRequested_ = true; + } + // The option only is removed + s.options_.erase(iter); + } + else + { + if (v.value_ != NULL) + { + *(v.value_) = false; + } + else + { + s.helpRequested_ = false; + } + } + return s; + } + template + argstream& + operator>>(argstream& s,const ValuesHolder& v) + { + s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); + { + std::ostringstream os; + os<<' '<::iterator first = s.values_.begin(); + // We add to the iterator as much values as we can, limited to the length + // specified (if different of -1) + int n = v.len_ != -1?v.len_:s.values_.size(); + while (first != s.values_.end() && n-->0) + { + // Read the value from the string *first + ValueParser p; + *(v.value_++) = p(*first ); + s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); + // The value we just removed was maybe "remembered" by an option so we + // remove it now. + for (std::map::iterator + jter = s.options_.begin();jter != s.options_.end();++jter) + { + if (jter->second == first) + { + jter->second = s.values_.end(); + } + } + ++first; + } + // Check if we have enough values + if (n != 0) + { + s.isOk_ = false; + std::ostringstream os; + os<<"Expecting "< Date: Fri, 19 Feb 2010 20:48:46 +0100 Subject: [PATCH 06/11] code format --- library/argstream/argstream.h | 1550 ++++++++++++++++----------------- 1 file changed, 775 insertions(+), 775 deletions(-) diff --git a/library/argstream/argstream.h b/library/argstream/argstream.h index 8b55e294a..76c2aade0 100644 --- a/library/argstream/argstream.h +++ b/library/argstream/argstream.h @@ -1,19 +1,19 @@ /* Copyright (C) 2004 Xavier Décoret * - * argsteam is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Foobar is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Foobar; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +* argsteam is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* Foobar is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Foobar; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ #ifndef ARGSTREAM_H #define ARGSTREAM_H @@ -29,785 +29,785 @@ namespace { - class argstream; + class argstream; - template - class ValueHolder; - - template - argstream& operator>> (argstream&, const ValueHolder&); - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of ValueHolder - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - template - class ValueHolder - { - public: - ValueHolder(char s, - const char* l, - T& b, - const char* desc, - bool mandatory); - ValueHolder(const char* l, - T& b, - const char* desc, - bool mandatory); - ValueHolder(char s, - T& b, - const char* desc, - bool mandatory); - friend argstream& operator>><>(argstream& s,const ValueHolder& v); - std::string name() const; - std::string description() const; - private: - std::string shortName_; - std::string longName_; - T* value_; - T initialValue_; - std::string description_; - bool mandatory_; - }; - template - inline ValueHolder - parameter(char s, - const char* l, - T& b, - const char* desc="", - bool mandatory = true) - { - return ValueHolder(s,l,b,desc,mandatory); - } - template - inline ValueHolder - parameter(char s, - T& b, - const char* desc="", - bool mandatory = true) - { - return ValueHolder(s,b,desc,mandatory); - } - template - inline ValueHolder - parameter(const char* l, - T& b, - const char* desc="", - bool mandatory = true) - { - return ValueHolder(l,b,desc,mandatory); - } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of OptionHolder - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - class OptionHolder - { - public: - inline OptionHolder(char s, - const char* l, - bool& b, - const char* desc); - inline OptionHolder(const char* l, - bool& b, - const char* desc); - inline OptionHolder(char s, - bool& b, - const char* desc); - friend argstream& operator>>(argstream& s,const OptionHolder& v); - inline std::string name() const; - inline std::string description() const; - protected: - inline OptionHolder(char s, - const char* l, - const char* desc); - friend OptionHolder help(char s='h', - const char* l="help", - const char* desc="Display this help"); - private: - std::string shortName_; - std::string longName_; - bool* value_; - std::string description_; - }; - inline OptionHolder - option(char s, - const char* l, - bool& b, - const char* desc="") - { - return OptionHolder(s,l,b,desc); - } - inline OptionHolder - option(char s, - bool& b, - const char* desc="") - { - return OptionHolder(s,b,desc); - } - inline OptionHolder - option(const char* l, - bool& b, - const char* desc="") - { - return OptionHolder(l,b,desc); - } - inline OptionHolder - help(char s, - const char* l, - const char* desc) - { - return OptionHolder(s,l,desc); - } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of ValuesHolder - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - template - class ValuesHolder - { - public: - ValuesHolder(const O& o, - const char* desc, - int len); - friend argstream& operator>><>(argstream& s,const ValuesHolder& v); - std::string name() const; - std::string description() const; - typedef T value_type; - private: - mutable O value_; - std::string description_; - int len_; - char letter_; - }; - template - inline ValuesHolder - values(const O& o, - const char* desc="", - int len=-1) - { - return ValuesHolder(o,desc,len); - } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of ValueParser - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - template - class ValueParser - { - public: - inline T operator()(const std::string& s) const - { - std::istringstream is(s); - T t; - is>>t; - return t; - } - }; - // We need to specialize for string otherwise parsing of a value that - // contains space (for example a string with space passed in quotes on the - // command line) would parse only the first element of the value!!! - template <> - class ValueParser - { - public: - inline std::string operator()(const std::string& s) const - { - return s; - } - }; - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of argstream - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - class argstream - { - public: - inline argstream(int argc,char** argv); - inline argstream(const char* c); template - friend argstream& operator>>(argstream& s,const ValueHolder& v); - friend inline argstream& operator>>(argstream& s,const OptionHolder& v); + class ValueHolder; + + template + argstream& operator>> (argstream&, const ValueHolder&); + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValueHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValueHolder + { + public: + ValueHolder(char s, + const char* l, + T& b, + const char* desc, + bool mandatory); + ValueHolder(const char* l, + T& b, + const char* desc, + bool mandatory); + ValueHolder(char s, + T& b, + const char* desc, + bool mandatory); + friend argstream& operator>><>(argstream& s,const ValueHolder& v); + std::string name() const; + std::string description() const; + private: + std::string shortName_; + std::string longName_; + T* value_; + T initialValue_; + std::string description_; + bool mandatory_; + }; + template + inline ValueHolder + parameter(char s, + const char* l, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(s,l,b,desc,mandatory); + } + template + inline ValueHolder + parameter(char s, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(s,b,desc,mandatory); + } + template + inline ValueHolder + parameter(const char* l, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(l,b,desc,mandatory); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of OptionHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + class OptionHolder + { + public: + inline OptionHolder(char s, + const char* l, + bool& b, + const char* desc); + inline OptionHolder(const char* l, + bool& b, + const char* desc); + inline OptionHolder(char s, + bool& b, + const char* desc); + friend argstream& operator>>(argstream& s,const OptionHolder& v); + inline std::string name() const; + inline std::string description() const; + protected: + inline OptionHolder(char s, + const char* l, + const char* desc); + friend OptionHolder help(char s='h', + const char* l="help", + const char* desc="Display this help"); + private: + std::string shortName_; + std::string longName_; + bool* value_; + std::string description_; + }; + inline OptionHolder + option(char s, + const char* l, + bool& b, + const char* desc="") + { + return OptionHolder(s,l,b,desc); + } + inline OptionHolder + option(char s, + bool& b, + const char* desc="") + { + return OptionHolder(s,b,desc); + } + inline OptionHolder + option(const char* l, + bool& b, + const char* desc="") + { + return OptionHolder(l,b,desc); + } + inline OptionHolder + help(char s, + const char* l, + const char* desc) + { + return OptionHolder(s,l,desc); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValuesHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ template - friend argstream& operator>>(argstream& s,const ValuesHolder& v); + class ValuesHolder + { + public: + ValuesHolder(const O& o, + const char* desc, + int len); + friend argstream& operator>><>(argstream& s,const ValuesHolder& v); + std::string name() const; + std::string description() const; + typedef T value_type; + private: + mutable O value_; + std::string description_; + int len_; + char letter_; + }; + template + inline ValuesHolder + values(const O& o, + const char* desc="", + int len=-1) + { + return ValuesHolder(o,desc,len); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValueParser + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValueParser + { + public: + inline T operator()(const std::string& s) const + { + std::istringstream is(s); + T t; + is>>t; + return t; + } + }; + // We need to specialize for string otherwise parsing of a value that + // contains space (for example a string with space passed in quotes on the + // command line) would parse only the first element of the value!!! + template <> + class ValueParser + { + public: + inline std::string operator()(const std::string& s) const + { + return s; + } + }; + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of argstream + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + class argstream + { + public: + inline argstream(int argc,char** argv); + inline argstream(const char* c); + template + friend argstream& operator>>(argstream& s,const ValueHolder& v); + friend inline argstream& operator>>(argstream& s,const OptionHolder& v); + template + friend argstream& operator>>(argstream& s,const ValuesHolder& v); - inline bool helpRequested() const; - inline bool isOk() const; - inline std::string errorLog() const; - inline std::string usage() const; - inline void defaultErrorHandling(bool ignoreUnused=false) const; - static inline char uniqueLetter(); - protected: - void parse(int argc,char** argv); - private: - typedef std::list::iterator value_iterator; - typedef std::pair help_entry; - std::string progName_; - std::map options_; - std::list values_; - bool minusActive_; - bool isOk_; - std::deque argHelps_; - std::string cmdLine_; - std::deque errors_; - bool helpRequested_; - }; - //************************************************************ - // Implementation of ValueHolder - //************************************************************ - template - ValueHolder::ValueHolder(char s, - const char* l, - T& v, - const char* desc, - bool mandatory) - : shortName_(1,s), - longName_(l), - value_(&v), - initialValue_(v), - description_(desc), - mandatory_(mandatory) - { - } - template - ValueHolder::ValueHolder(const char* l, - T& v, - const char* desc, - bool mandatory) - : longName_(l), - value_(&v), - initialValue_(v), - description_(desc), - mandatory_(mandatory) - { - } - template - ValueHolder::ValueHolder(char s, - T& v, - const char* desc, - bool mandatory) - : shortName_(1,s), - value_(&v), - initialValue_(v), - description_(desc), - mandatory_(mandatory) - { - } - template - std::string - ValueHolder::name() const - { - std::ostringstream os; - if (!shortName_.empty()) os<<'-'< - std::string - ValueHolder::description() const - { - std::ostringstream os; - os< - //************************************************************ - template - ValuesHolder::ValuesHolder(const O& o, - const char* desc, - int len) - : value_(o), - description_(desc), - len_(len) - { - letter_ = argstream::uniqueLetter(); - } - template - std::string - ValuesHolder::name() const - { - std::ostringstream os; - os< - std::string - ValuesHolder::description() const - { - return description_; - } - //************************************************************ - // Implementation of argstream - //************************************************************ - inline - argstream::argstream(int argc,char** argv) - : progName_(argv[0]), - minusActive_(true), - isOk_(true) - { - parse(argc,argv); - } - inline - argstream::argstream(const char* c) - : progName_(""), - minusActive_(true), - isOk_(true) - { - std::string s(c); - // Build argc, argv from s. We must add a dummy first element for - // progName because parse() expects it!! - std::deque args; - args.push_back(""); - std::istringstream is(s); - while (is.good()) - { - std::string t; - is>>t; - args.push_back(t); - } - char* pargs[args.size()]; - char** p = pargs; - for (std::deque::const_iterator - iter = args.begin(); - iter != args.end();++iter) - { - *p++ = const_cast(iter->c_str()); - } - parse(args.size(),pargs); - } - inline void - argstream::parse(int argc,char** argv) - { - // Run thru all arguments. - // * it has -- in front : it is a long name option, if remainder is empty, - // it is an error - // * it has - in front : it is a sequence of short name options, if - // remainder is empty, deactivates option (- will - // now be considered a char). - // * if any other char, or if option was deactivated - // : it is a value. Values are split in parameters - // (immediately follow an option) and pure values. - // Each time a value is parsed, if the previously parsed argument was an - // option, then the option is linked to the value in case of it is a - // option with parameter. The subtle point is that when several options - // are given with short names (ex: -abc equivalent to -a -b -c), the last - // parsed option is -c). - // Since we use map for option, any successive call overides the previous - // one: foo -a -b -a hello is equivalent to foo -b -a hello - // For values it is not true since we might have several times the same - // value. - value_iterator* lastOption = NULL; - for (char** a = argv,**astop=a+argc;++a!=astop;) - { - std::string s(*a); - if (minusActive_ && s[0] == '-') - { - if (s.size() > 1 && s[1] == '-') - { - if (s.size() == 2) - { - minusActive_ = false; - continue; - } - lastOption = &(options_[s.substr(2)] = values_.end()); - } - else - { - if (s.size() > 1) - { - // Parse all chars, if it is a minus we have an error - for (std::string::const_iterator cter = s.begin(); - ++cter != s.end();) - { - if (*cter == '-') - { - isOk_ = false; - std::ostringstream os; - os<<"- in the middle of a switch "<::iterator value_iterator; + typedef std::pair help_entry; + std::string progName_; + std::map options_; + std::list values_; + bool minusActive_; + bool isOk_; + std::deque argHelps_; + std::string cmdLine_; + std::deque errors_; + bool helpRequested_; + }; + //************************************************************ + // Implementation of ValueHolder + //************************************************************ + template + ValueHolder::ValueHolder(char s, + const char* l, + T& v, + const char* desc, + bool mandatory) + : shortName_(1,s), + longName_(l), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { } -#ifdef ARGSTREAM_DEBUG - for (std::map::const_iterator - iter = options_.begin();iter != options_.end();++iter) + template + ValueHolder::ValueHolder(const char* l, + T& v, + const char* desc, + bool mandatory) + : longName_(l), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + ValueHolder::ValueHolder(char s, + T& v, + const char* desc, + bool mandatory) + : shortName_(1,s), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + std::string + ValueHolder::name() const + { + std::ostringstream os; + if (!shortName_.empty()) os<<'-'< + std::string + ValueHolder::description() const + { + std::ostringstream os; + os<first; - if (iter->second != values_.end()) - { - std::cout<<" -> "<<*(iter->second); - } - std::cout<::const_iterator - iter = values_.begin();iter != values_.end();++iter) + inline OptionHolder::OptionHolder(char s, + bool& b, + const char* desc) + : shortName_(1,s), + value_(&b), + description_(desc) { - std::cout<<"DEBUG: value "<<*iter< + //************************************************************ + template + ValuesHolder::ValuesHolder(const O& o, + const char* desc, + int len) + : value_(o), + description_(desc), + len_(len) + { + letter_ = argstream::uniqueLetter(); + } + template + std::string + ValuesHolder::name() const + { + std::ostringstream os; + os< + std::string + ValuesHolder::description() const + { + return description_; + } + //************************************************************ + // Implementation of argstream + //************************************************************ + inline + argstream::argstream(int argc,char** argv) + : progName_(argv[0]), + minusActive_(true), + isOk_(true) + { + parse(argc,argv); + } + inline + argstream::argstream(const char* c) + : progName_(""), + minusActive_(true), + isOk_(true) + { + std::string s(c); + // Build argc, argv from s. We must add a dummy first element for + // progName because parse() expects it!! + std::deque args; + args.push_back(""); + std::istringstream is(s); + while (is.good()) + { + std::string t; + is>>t; + args.push_back(t); + } + char* pargs[args.size()]; + char** p = pargs; + for (std::deque::const_iterator + iter = args.begin(); + iter != args.end();++iter) + { + *p++ = const_cast(iter->c_str()); + } + parse(args.size(),pargs); + } + inline void + argstream::parse(int argc,char** argv) + { + // Run thru all arguments. + // * it has -- in front : it is a long name option, if remainder is empty, + // it is an error + // * it has - in front : it is a sequence of short name options, if + // remainder is empty, deactivates option (- will + // now be considered a char). + // * if any other char, or if option was deactivated + // : it is a value. Values are split in parameters + // (immediately follow an option) and pure values. + // Each time a value is parsed, if the previously parsed argument was an + // option, then the option is linked to the value in case of it is a + // option with parameter. The subtle point is that when several options + // are given with short names (ex: -abc equivalent to -a -b -c), the last + // parsed option is -c). + // Since we use map for option, any successive call overides the previous + // one: foo -a -b -a hello is equivalent to foo -b -a hello + // For values it is not true since we might have several times the same + // value. + value_iterator* lastOption = NULL; + for (char** a = argv,**astop=a+argc;++a!=astop;) + { + std::string s(*a); + if (minusActive_ && s[0] == '-') + { + if (s.size() > 1 && s[1] == '-') + { + if (s.size() == 2) + { + minusActive_ = false; + continue; + } + lastOption = &(options_[s.substr(2)] = values_.end()); + } + else + { + if (s.size() > 1) + { + // Parse all chars, if it is a minus we have an error + for (std::string::const_iterator cter = s.begin(); + ++cter != s.end();) + { + if (*cter == '-') + { + isOk_ = false; + std::ostringstream os; + os<<"- in the middle of a switch "<::const_iterator + iter = options_.begin();iter != options_.end();++iter) + { + std::cout<<"DEBUG: option "<first; + if (iter->second != values_.end()) + { + std::cout<<" -> "<<*(iter->second); + } + std::cout<::const_iterator + iter = values_.begin();iter != values_.end();++iter) + { + std::cout<<"DEBUG: value "<<*iter<::const_iterator - iter = argHelps_.begin();iter != argHelps_.end();++iter) - { - if (lmaxfirst.size()) lmax = iter->first.size(); - } - for (std::deque::const_iterator - iter = argHelps_.begin();iter != argHelps_.end();++iter) - { - os<<'\t'<first<first.size(),' ') - <<" : "<second<<'\n'; - } - return os.str(); - } - inline std::string - argstream::errorLog() const - { - std::string s; - for(std::deque::const_iterator iter = errors_.begin(); - iter != errors_.end();++iter) - { - s += *iter; - s += '\n'; - } - return s; - } - inline char - argstream::uniqueLetter() - { - static unsigned int c = 'a'; - return c++; - } - template - argstream& - operator>>(argstream& s,const ValueHolder& v) - { - // Search in the options if there is any such option defined either with a - // short name or a long name. If both are found, only the last one is - // used. -#ifdef ARGSTREAM_DEBUG - std::cout<<"DEBUG: searching "<::iterator iter = - s.options_.find(v.shortName_); - if (iter == s.options_.end()) + inline bool + argstream::isOk() const + { + return isOk_; + } + inline bool + argstream::helpRequested() const { - iter = s.options_.find(v.longName_); + return helpRequested_; } - if (iter != s.options_.end()) + inline std::string + argstream::usage() const { - // If we find counterpart for value holder on command line, either it - // has an associated value in which case we assign it, or it has not, in - // which case we have an error. - if (iter->second != s.values_.end()) - { + std::ostringstream os; + os<<"usage: "<::const_iterator + iter = argHelps_.begin();iter != argHelps_.end();++iter) + { + if (lmaxfirst.size()) lmax = iter->first.size(); + } + for (std::deque::const_iterator + iter = argHelps_.begin();iter != argHelps_.end();++iter) + { + os<<'\t'<first<first.size(),' ') + <<" : "<second<<'\n'; + } + return os.str(); + } + inline std::string + argstream::errorLog() const + { + std::string s; + for(std::deque::const_iterator iter = errors_.begin(); + iter != errors_.end();++iter) + { + s += *iter; + s += '\n'; + } + return s; + } + inline char + argstream::uniqueLetter() + { + static unsigned int c = 'a'; + return c++; + } + template + argstream& + operator>>(argstream& s,const ValueHolder& v) + { + // Search in the options if there is any such option defined either with a + // short name or a long name. If both are found, only the last one is + // used. +#ifdef ARGSTREAM_DEBUG + std::cout<<"DEBUG: searching "<::iterator iter = + s.options_.find(v.shortName_); + if (iter == s.options_.end()) + { + iter = s.options_.find(v.longName_); + } + if (iter != s.options_.end()) + { + // If we find counterpart for value holder on command line, either it + // has an associated value in which case we assign it, or it has not, in + // which case we have an error. + if (iter->second != s.values_.end()) + { #ifdef ARGSTREAM_DEBUG - std::cout<<"DEBUG: found value "<<*(iter->second)<second)< p; - *(v.value_) = p(*(iter->second)); - // The option and its associated value are removed, the subtle thing - // is that someother options might have this associated value too, - // which we must invalidate. - s.values_.erase(iter->second); - for (std::map::iterator - jter = s.options_.begin();jter != s.options_.end();++jter) - { - if (jter->second == iter->second) - { - jter->second = s.values_.end(); - } - } - s.options_.erase(iter); - } - else - { - s.isOk_ = false; - std::ostringstream os; - os<<"No value following switch "<first - <<" on command line"; - s.errors_.push_back(os.str()); - } - } - else - { - if (v.mandatory_) - { - s.isOk_ = false; - std::ostringstream os; - os<<"Mandatory parameter "; - if (!v.shortName_.empty()) os<<'-'<>(argstream& s,const OptionHolder& v) - { - // Search in the options if there is any such option defined either with a - // short name or a long name. If both are found, only the last one is - // used. + ValueParser p; + *(v.value_) = p(*(iter->second)); + // The option and its associated value are removed, the subtle thing + // is that someother options might have this associated value too, + // which we must invalidate. + s.values_.erase(iter->second); + for (std::map::iterator + jter = s.options_.begin();jter != s.options_.end();++jter) + { + if (jter->second == iter->second) + { + jter->second = s.values_.end(); + } + } + s.options_.erase(iter); + } + else + { + s.isOk_ = false; + std::ostringstream os; + os<<"No value following switch "<first + <<" on command line"; + s.errors_.push_back(os.str()); + } + } + else + { + if (v.mandatory_) + { + s.isOk_ = false; + std::ostringstream os; + os<<"Mandatory parameter "; + if (!v.shortName_.empty()) os<<'-'<>(argstream& s,const OptionHolder& v) + { + // Search in the options if there is any such option defined either with a + // short name or a long name. If both are found, only the last one is + // used. #ifdef ARGSTREAM_DEBUG - std::cout<<"DEBUG: searching "<::iterator iter = - s.options_.find(v.shortName_); - if (iter == s.options_.end()) - { - iter = s.options_.find(v.longName_); - } - if (iter != s.options_.end()) - { - // If we find counterpart for value holder on command line then the - // option is true and if an associated value was found, it is ignored - if (v.value_ != NULL) - { - *(v.value_) = true; - } - else - { - s.helpRequested_ = true; - } - // The option only is removed - s.options_.erase(iter); - } - else - { - if (v.value_ != NULL) - { - *(v.value_) = false; - } - else - { - s.helpRequested_ = false; - } - } - return s; - } - template - argstream& - operator>>(argstream& s,const ValuesHolder& v) - { - s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); - { - std::ostringstream os; - os<<' '<::iterator first = s.values_.begin(); - // We add to the iterator as much values as we can, limited to the length - // specified (if different of -1) - int n = v.len_ != -1?v.len_:s.values_.size(); - while (first != s.values_.end() && n-->0) - { - // Read the value from the string *first - ValueParser p; - *(v.value_++) = p(*first ); - s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); - // The value we just removed was maybe "remembered" by an option so we - // remove it now. - for (std::map::iterator - jter = s.options_.begin();jter != s.options_.end();++jter) - { - if (jter->second == first) - { - jter->second = s.values_.end(); - } - } - ++first; - } - // Check if we have enough values - if (n != 0) - { - s.isOk_ = false; - std::ostringstream os; - os<<"Expecting "<::iterator iter = + s.options_.find(v.shortName_); + if (iter == s.options_.end()) + { + iter = s.options_.find(v.longName_); + } + if (iter != s.options_.end()) + { + // If we find counterpart for value holder on command line then the + // option is true and if an associated value was found, it is ignored + if (v.value_ != NULL) + { + *(v.value_) = true; + } + else + { + s.helpRequested_ = true; + } + // The option only is removed + s.options_.erase(iter); + } + else + { + if (v.value_ != NULL) + { + *(v.value_) = false; + } + else + { + s.helpRequested_ = false; + } + } + return s; + } + template + argstream& + operator>>(argstream& s,const ValuesHolder& v) + { + s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); + { + std::ostringstream os; + os<<' '<::iterator first = s.values_.begin(); + // We add to the iterator as much values as we can, limited to the length + // specified (if different of -1) + int n = v.len_ != -1?v.len_:s.values_.size(); + while (first != s.values_.end() && n-->0) + { + // Read the value from the string *first + ValueParser p; + *(v.value_++) = p(*first ); + s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); + // The value we just removed was maybe "remembered" by an option so we + // remove it now. + for (std::map::iterator + jter = s.options_.begin();jter != s.options_.end();++jter) + { + if (jter->second == first) + { + jter->second = s.values_.end(); + } + } + ++first; + } + // Check if we have enough values + if (n != 0) + { + s.isOk_ = false; + std::ostringstream os; + os<<"Expecting "< Date: Fri, 19 Feb 2010 20:51:33 +0100 Subject: [PATCH 07/11] one constructor had three compile errors, just commented it out --- library/argstream/argstream.h | 58 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/library/argstream/argstream.h b/library/argstream/argstream.h index 76c2aade0..aa5bdaa49 100644 --- a/library/argstream/argstream.h +++ b/library/argstream/argstream.h @@ -218,7 +218,7 @@ namespace { public: inline argstream(int argc,char** argv); - inline argstream(const char* c); + //inline argstream(const char* c); template friend argstream& operator>>(argstream& s,const ValueHolder& v); friend inline argstream& operator>>(argstream& s,const OptionHolder& v); @@ -408,34 +408,34 @@ namespace { parse(argc,argv); } - inline - argstream::argstream(const char* c) - : progName_(""), - minusActive_(true), - isOk_(true) - { - std::string s(c); - // Build argc, argv from s. We must add a dummy first element for - // progName because parse() expects it!! - std::deque args; - args.push_back(""); - std::istringstream is(s); - while (is.good()) - { - std::string t; - is>>t; - args.push_back(t); - } - char* pargs[args.size()]; - char** p = pargs; - for (std::deque::const_iterator - iter = args.begin(); - iter != args.end();++iter) - { - *p++ = const_cast(iter->c_str()); - } - parse(args.size(),pargs); - } + //inline + // argstream::argstream(const char* c) + // : progName_(""), + // minusActive_(true), + // isOk_(true) + //{ + // std::string s(c); + // // Build argc, argv from s. We must add a dummy first element for + // // progName because parse() expects it!! + // std::deque args; + // args.push_back(""); + // std::istringstream is(s); + // while (is.good()) + // { + // std::string t; + // is>>t; + // args.push_back(t); + // } + // char* pargs[args.size()]; + // char** p = pargs; + // for (std::deque::const_iterator + // iter = args.begin(); + // iter != args.end();++iter) + // { + // *p++ = const_cast(iter->c_str()); + // } + // parse(args.size(),pargs); + //} inline void argstream::parse(int argc,char** argv) { From 32e08c66870b997658b0a38d111ae3893102d1e4 Mon Sep 17 00:00:00 2001 From: mizipzor Date: Fri, 19 Feb 2010 20:52:07 +0100 Subject: [PATCH 08/11] removed gopt --- library/gopt/gopt.cpp | 265 ------------------------------------------ library/gopt/gopt.h | 62 ---------- 2 files changed, 327 deletions(-) delete mode 100644 library/gopt/gopt.cpp delete mode 100644 library/gopt/gopt.h diff --git a/library/gopt/gopt.cpp b/library/gopt/gopt.cpp deleted file mode 100644 index 4deeeb5c1..000000000 --- a/library/gopt/gopt.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* gopt.c version 8.1: tom.viza@gmail.com PUBLIC DOMAIN 2003-8 */ -/* -I, Tom Vajzovic, am the author of this software and its documentation and -permanently abandon all copyright and other intellectual property rights in -them, including the right to be identified as the author. - -I am fairly certain that this software does what the documentation says it -does, but I cannot guarantee that it does, or that it does what you think it -should, and I cannot guarantee that it will not have undesirable side effects. - -You are free to use, modify and distribute this software as you please, but -you do so at your own risk. If you remove or hide this warning then you are -responsible for any problems encountered by people that you make the software -available to. - -Before modifying or distributing this software I ask that you would please -read http://www.purposeful.co.uk/tfl/ -*/ - -#include -#include -#include -#include "gopt.h" - -#ifdef USE_SYSEXITS -#include -#else -#define EX_OSERR EXIT_FAILURE -#define EX_USAGE EXIT_FAILURE -#endif - -struct opt_spec_s { - int key; - int flags; - const char *shorts; - const char* const *longs; -}; -typedef struct opt_spec_s opt_spec_t; - -struct opt_s { - int key; - const char *arg; -}; -typedef struct opt_s opt_t; - -void *gopt_sort( int *argc, const char **argv, const void *opt_specs ){ - void *opts; - {{{ - const char* const *arg_p= argv + 1; - size_t opt_count= 1; - for( ; *arg_p; ++arg_p ) - if( '-' == (*arg_p)[0] && (*arg_p)[1] ) - if( '-' == (*arg_p)[1] ) - if( (*arg_p)[2] ) - ++opt_count; - else - break; - else { - const opt_spec_t *opt_spec_p= (const opt_spec_t*)opt_specs; - for( ; opt_spec_p-> key; ++opt_spec_p ) - if( strchr( opt_spec_p-> shorts, (*arg_p)[1] )){ - opt_count+= opt_spec_p-> flags & GOPT_ARG ? 1 : strlen( (*arg_p) + 1 ); - break; - } - } - opts= malloc( opt_count * sizeof(opt_t) ); - }}} - { - const char **arg_p= argv + 1; - const char **next_operand= arg_p; - opt_t *next_option= (opt_t*)opts; - - if( ! opts ){ - perror( argv[0] ); - exit( EX_OSERR ); - } - for( ; *arg_p; ++arg_p ) - if( '-' == (*arg_p)[0] && (*arg_p)[1] ) - if( '-' == (*arg_p)[1] ) - if( (*arg_p)[2] ) - {{{ - const opt_spec_t *opt_spec_p= (const opt_spec_t*)opt_specs; - const char* const *longs= opt_spec_p-> longs; - next_option-> key= 0; - while( *longs ){ - const char *option_cp= (*arg_p) + 2; - const char *name_cp= *longs; - while( *option_cp && *option_cp == *name_cp ){ - ++option_cp; - ++name_cp; - } - if( '=' == *option_cp || !*option_cp ){ - if( *name_cp ){ - if( next_option-> key ){ - fprintf( stderr, "%s: --%.*s: abbreviated option is ambiguous\n", argv[0], (int)( option_cp -( (*arg_p) + 2 )), (*arg_p) + 2 ); - free( opts ); - exit( EX_USAGE ); - } - next_option-> key= opt_spec_p-> key; - } - else { - next_option-> key= opt_spec_p-> key; - goto found_long; - } - } - if( !*++longs ){ - ++opt_spec_p; - if( opt_spec_p-> key ) - longs= opt_spec_p-> longs; - } - } - if( ! next_option-> key ){ - fprintf( stderr, "%s: --%.*s: unknown option\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 ); - free( opts ); - exit( EX_USAGE ); - } - for( opt_spec_p= (const opt_spec_t*)opt_specs; opt_spec_p-> key != next_option-> key; ++opt_spec_p ); - found_long: - - if( !( opt_spec_p-> flags & GOPT_REPEAT )){ - const opt_t *opt_p= (const opt_t*)opts; - for( ; opt_p != next_option; ++opt_p ) - if( opt_p-> key == opt_spec_p-> key ){ - fprintf( stderr, "%s: --%.*s: option may not be repeated (in any long or short form)\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 ); - free( opts ); - exit( EX_USAGE ); - } - } - if( opt_spec_p-> flags & GOPT_ARG ){ - next_option-> arg= strchr( (*arg_p) + 2, '=' ) + 1; - if( (char*)0 + 1 == next_option-> arg ){ - ++arg_p; - if( !*arg_p || '-' == (*arg_p)[0] && (*arg_p)[1] ){ - fprintf( stderr, "%s: --%s: option requires an option argument\n", argv[0], (*(arg_p-1)) + 2 ); - free( opts ); - exit( EX_USAGE ); - } - next_option-> arg= *arg_p; - } - } - else { - if( strchr( (*arg_p) + 2, '=' )){ - fprintf( stderr, "%s: --%.*s: option may not take an option argument\n", argv[0], (int)strcspn( (*arg_p) + 2, "=" ), (*arg_p) + 2 ); - free( opts ); - exit( EX_USAGE ); - } - next_option-> arg= NULL; - } - ++next_option; - }}} - else { - for( ++arg_p; *arg_p; ++arg_p ) - *next_operand++= *arg_p; - break; - } - else - {{{ - const char *short_opt= (*arg_p) + 1; - for( ;*short_opt; ++short_opt ){ - const opt_spec_t *opt_spec_p= (const opt_spec_t*)opt_specs; - - for( ; opt_spec_p-> key; ++opt_spec_p ) - if( strchr( opt_spec_p-> shorts, *short_opt )){ - if( !( opt_spec_p-> flags & GOPT_REPEAT )){ - const opt_t *opt_p= (const opt_t*)opts; - for( ; opt_p != next_option; ++opt_p ) - if( opt_p-> key == opt_spec_p-> key ){ - fprintf( stderr, "%s: -%c: option may not be repeated (in any long or short form)\n", argv[0], *short_opt ); - free( opts ); - exit( EX_USAGE ); - } - } - next_option-> key= opt_spec_p-> key; - - if( opt_spec_p-> flags & GOPT_ARG ){ - if( short_opt[1] ) - next_option-> arg= short_opt + 1; - - else { - ++arg_p; - if( !*arg_p || '-' == (*arg_p)[0] && (*arg_p)[1] ){ - fprintf( stderr, "%s: -%c: option requires an option argument\n", argv[0], *short_opt ); - free( opts ); - exit( EX_USAGE ); - } - next_option-> arg= *arg_p; - } - ++next_option; - goto break_2; - } - next_option-> arg= NULL; - ++next_option; - goto continue_2; - } - fprintf( stderr, "%s: -%c: unknown option\n", argv[0], *short_opt ); - free( opts ); - exit( EX_USAGE ); - continue_2: 0; - } - break_2: 0; - }}} - else - *next_operand++= *arg_p; - - next_option-> key= 0; - *next_operand= NULL; - *argc= next_operand - argv; - } - return opts; -} - -size_t gopt( const void *vptr_opts, int key ){ - const opt_t *opts= (const opt_t*)vptr_opts; - size_t count= 0; - for( ; opts-> key; ++opts ) - count+= opts-> key == key; - - return count; -} - -size_t gopt_arg( const void *vptr_opts, int key, const char **arg ){ - const opt_t *opts= (const opt_t*)vptr_opts; - size_t count= 0; - - for( ; opts-> key; ++opts ) - if( opts-> key == key ){ - if( ! count ) - *arg= opts-> arg; - ++count; - } - return count; -} - -const char *gopt_arg_i( const void *vptr_opts, int key, size_t i ){ - const opt_t *opts= (const opt_t*)vptr_opts; - - for( ; opts-> key; ++opts ) - if( opts-> key == key ){ - if( ! i ) - return opts-> arg; - --i; - } - return NULL; -} - -size_t gopt_args( const void *vptr_opts, int key, const char **args, size_t args_len ){ - const char **args_stop= args + args_len; - const char **args_ptr= args; - const opt_t *opts= (const opt_t*)vptr_opts; - - for( ; opts-> key; ++opts ) - if( opts-> key == key ){ - if( args_stop == args_ptr ) - return args_len + gopt( opts, key ); - - *args_ptr++= opts-> arg; - } - if( args_stop != args_ptr ) - *args_ptr= NULL; - return args_ptr - args; -} - -void gopt_free( void *vptr_opts ){ - free( vptr_opts ); -} diff --git a/library/gopt/gopt.h b/library/gopt/gopt.h deleted file mode 100644 index f6c452f64..000000000 --- a/library/gopt/gopt.h +++ /dev/null @@ -1,62 +0,0 @@ -/* gopt.h version 8.1: tom.viza@gmail.com PUBLIC DOMAIN 2003-8 */ -/* -I, Tom Vajzovic, am the author of this software and its documentation and -permanently abandon all copyright and other intellectual property rights in -them, including the right to be identified as the author. - -I am fairly certain that this software does what the documentation says it -does, but I cannot guarantee that it does, or that it does what you think it -should, and I cannot guarantee that it will not have undesirable side effects. - -You are free to use, modify and distribute this software as you please, but -you do so at your own risk. If you remove or hide this warning then you are -responsible for any problems encountered by people that you make the software -available to. - -Before modifying or distributing this software I ask that you would please -read http://www.purposeful.co.uk/tfl/ -*/ - -#ifndef GOPT_H_INCLUDED -#define GOPT_H_INCLUDED - -#include - -#define GOPT_ONCE 0 -#define GOPT_REPEAT 1 -#define GOPT_NOARG 0 -#define GOPT_ARG 2 - -#define gopt_start(...) (const void*)( const struct { int k; int f; const char *s; const char*const*l; }[]){ __VA_ARGS__, {0}} -#define gopt_option(k,f,s,l) { k, f, s, l } -#define gopt_shorts( ... ) (const char*)(const char[]){ __VA_ARGS__, 0 } -#define gopt_longs( ... ) (const char**)(const char*[]){ __VA_ARGS__, NULL } - - -DFHACK_EXPORT void *gopt_sort( int *argc, const char **argv, const void *opt_specs ); -/* returns a pointer for use in the following calls - * prints to stderr and call exit() on error - */ -DFHACK_EXPORT size_t gopt( const void *opts, int key ); -/* returns the number of times the option was specified - * which will be 0 or 1 unless GOPT_REPEAT was used - */ -DFHACK_EXPORT size_t gopt_arg( const void *opts, int key, const char **arg ); -/* returns the number of times the option was specified - * writes a pointer to the option argument from the first (or only) occurance to *arg - */ -DFHACK_EXPORT const char *gopt_arg_i( const void *opts, int key, size_t i ); -/* returns a pointer to the ith (starting at zero) occurance - * of the option, or NULL if it was not specified that many times - */ -DFHACK_EXPORT size_t gopt_args( const void *opts, int key, const char **args, size_t args_len ); -/* returns the number of times the option was specified - * writes pointers to the option arguments in the order of occurance to args[]. - * writes at most args_len pointers - * if the return value is less than args_len, also writes a null pointer - */ -DFHACK_EXPORT void gopt_free( void *opts ); -/* releases memory allocated in the corresponding call to gopt_sort() - * opts can no longer be used - */ -#endif /* GOPT_H_INCLUDED */ From adbf4b81b4057e13e718374f7362cf775815aa50 Mon Sep 17 00:00:00 2001 From: mizipzor Date: Fri, 19 Feb 2010 20:55:11 +0100 Subject: [PATCH 09/11] updated cmakelists --- library/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 4eae87b63..66921f55d 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -19,7 +19,7 @@ md5/md5wrapper.h tinyxml/tinystr.h tinyxml/tinyxml.h -gopt/gopt.h +argstream/argstream.h ../shmserver/shms.h ) @@ -35,7 +35,6 @@ tinyxml/tinystr.cpp tinyxml/tinyxml.cpp tinyxml/tinyxmlerror.cpp tinyxml/tinyxmlparser.cpp -gopt/gopt.c ) SET(PROJECT_HDRS_LINUX From 7f404483f1ec9b7a745ee8d3f5f385108ca0025a Mon Sep 17 00:00:00 2001 From: mizipzor Date: Fri, 19 Feb 2010 21:24:20 +0100 Subject: [PATCH 10/11] fixed (fix as in hack) crash when std::string was used to store a command line argument --- library/argstream/argstream.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/library/argstream/argstream.h b/library/argstream/argstream.h index aa5bdaa49..cdc8e4600 100644 --- a/library/argstream/argstream.h +++ b/library/argstream/argstream.h @@ -635,15 +635,17 @@ namespace // The option and its associated value are removed, the subtle thing // is that someother options might have this associated value too, // which we must invalidate. - s.values_.erase(iter->second); - for (std::map::iterator - jter = s.options_.begin();jter != s.options_.end();++jter) - { - if (jter->second == iter->second) - { - jter->second = s.values_.end(); - } - } + s.values_.erase(iter->second); + + // FIXME this loop seems to crash if a std::string is used as the value + //for (std::map::iterator + // jter = s.options_.begin();jter != s.options_.end();++jter) + //{ + // if (jter->second == iter->second) + // { + // jter->second = s.values_.end(); + // } + //} s.options_.erase(iter); } else From 194bf2ddc11fdb0061f76627d4dd519838429b90 Mon Sep 17 00:00:00 2001 From: mizipzor Date: Fri, 19 Feb 2010 21:29:23 +0100 Subject: [PATCH 11/11] added argstream to digger, showing how it can be used --- tools/digger.cpp | 67 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/tools/digger.cpp b/tools/digger.cpp index b9b503f4c..9e7ee48ec 100644 --- a/tools/digger.cpp +++ b/tools/digger.cpp @@ -22,7 +22,7 @@ using namespace std; #include #include #include -#include +#include // counts the occurances of a certain element in a vector int vec_count(vector& vec, uint16_t t) @@ -55,6 +55,20 @@ void string_split(vector& tokens, const std::string& src, const std::str } } +void parse_int_csv(vector& targets, const std::string& src) +{ + std::string::size_type start = 0; + std::string::size_type end; + while (true) + { + end = src.find(",", start); + targets.push_back(atoi(src.substr(start, end - start).c_str())); + if (end == std::string::npos) // last token handled + break; + start = end + 1; // skip next delim + } +} + // calculates the manhattan distance between two coords int manhattan_distance(int x, int y, int z, int xx, int yy, int zz) { @@ -261,27 +275,48 @@ void test() assert(tokens.size() == 1); assert(tokens[0] == "10"); } + { + vector targets; + parse_int_csv(targets, "9,10"); + assert(targets[0] == 9); + assert(targets[1] == 10); + } } -int main (int argc, const char* argv[]) +int main (int argc, char** argv) { - test(); - void *options= gopt_sort( & argc, argv, gopt_start( - gopt_option( 'h', 0, gopt_shorts( 'h', '?' ), gopt_longs( "help", "HELP" )), - gopt_option( 'z', 0, gopt_shorts( 0 ), gopt_longs( "version" )), - gopt_option( 'v', GOPT_REPEAT, gopt_shorts( 'v' ), gopt_longs( "verbose" )), - gopt_option( 'o', GOPT_ARG, gopt_shorts( 'o' ), gopt_longs( "output" )))); - - +test(); + + // Command line options + string s_targets; + string s_origin = "0,0,0"; + bool verbose; + int max; + argstream as(argc,argv); + + as >>option('v',"verbose",verbose,"Active verbose mode") // TODO handle verbose + >>parameter('o',"origin",s_origin,"Close to where we should designate targets, format: x,y,z") + >>parameter('t',"targets",s_targets,"What kinds of tile we should designate, format: type1,type2") + >>parameter('m',"max",max,"The maximum limit of designated targets") + >>help(); + + // handle some commands vector targets; - for (int i = 1; i < argc; ++i) + parse_int_csv(targets, s_targets); + + vector origin; + parse_int_csv(origin, s_origin); + + // sane check + if (!as.isOk()) { - targets.push_back(atoi(argv[i])); + cout << as.errorLog(); } - if (targets.size() == 0) + else if (targets.size() == 0 || origin.size() != 3) { - cout << "Usage: Call with a list of TileClass ids separated by a space,\n"; - cout << "every (visible) tile on the map with that id will be designated for digging.\n\n"; + //cout << "Usage: Call with a list of TileClass ids separated by a space,\n"; + //cout << "every (visible) tile on the map with that id will be designated for digging.\n\n"; + cout << as.usage(); } else { @@ -302,7 +337,7 @@ int main (int argc, const char* argv[]) // return 1; //} - int count = dig(DF, targets, 10, x_source, y_source, z_source); // <-- important part + int count = dig(DF, targets, 10, origin[0],origin[1],origin[2]); // <-- important part cout << count << " targets designated" << endl; DF.Detach();