Merge branch 'master' of git://github.com/mizipzor/dfhack
commit
5cfb401d49
@ -0,0 +1,815 @@
|
|||||||
|
/* Copyright (C) 2004 Xavier Décoret <Xavier.Decoret@imag.fr>
|
||||||
|
*
|
||||||
|
* 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 <string>
|
||||||
|
#include <list>
|
||||||
|
#include <deque>
|
||||||
|
#include <map>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class argstream;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class ValueHolder;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
argstream& operator>> (argstream&, const ValueHolder<T>&);
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Interface of ValueHolder<T>
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
template<class T>
|
||||||
|
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<T>& 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 <class T>
|
||||||
|
inline ValueHolder<T>
|
||||||
|
parameter(char s,
|
||||||
|
const char* l,
|
||||||
|
T& b,
|
||||||
|
const char* desc="",
|
||||||
|
bool mandatory = true)
|
||||||
|
{
|
||||||
|
return ValueHolder<T>(s,l,b,desc,mandatory);
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
inline ValueHolder<T>
|
||||||
|
parameter(char s,
|
||||||
|
T& b,
|
||||||
|
const char* desc="",
|
||||||
|
bool mandatory = true)
|
||||||
|
{
|
||||||
|
return ValueHolder<T>(s,b,desc,mandatory);
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
inline ValueHolder<T>
|
||||||
|
parameter(const char* l,
|
||||||
|
T& b,
|
||||||
|
const char* desc="",
|
||||||
|
bool mandatory = true)
|
||||||
|
{
|
||||||
|
return ValueHolder<T>(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 T,class O>
|
||||||
|
class ValuesHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ValuesHolder(const O& o,
|
||||||
|
const char* desc,
|
||||||
|
int len);
|
||||||
|
friend argstream& operator>><>(argstream& s,const ValuesHolder<T,O>& 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<class T,class O>
|
||||||
|
inline ValuesHolder<T,O>
|
||||||
|
values(const O& o,
|
||||||
|
const char* desc="",
|
||||||
|
int len=-1)
|
||||||
|
{
|
||||||
|
return ValuesHolder<T,O>(o,desc,len);
|
||||||
|
}
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
// Interface of ValueParser
|
||||||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
template <class T>
|
||||||
|
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<std::string>
|
||||||
|
{
|
||||||
|
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<class T>
|
||||||
|
friend argstream& operator>>(argstream& s,const ValueHolder<T>& v);
|
||||||
|
friend inline argstream& operator>>(argstream& s,const OptionHolder& v);
|
||||||
|
template<class T,class O>
|
||||||
|
friend argstream& operator>>(argstream& s,const ValuesHolder<T,O>& 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<std::string>::iterator value_iterator;
|
||||||
|
typedef std::pair<std::string,std::string> help_entry;
|
||||||
|
std::string progName_;
|
||||||
|
std::map<std::string,value_iterator> options_;
|
||||||
|
std::list<std::string> values_;
|
||||||
|
bool minusActive_;
|
||||||
|
bool isOk_;
|
||||||
|
std::deque<help_entry> argHelps_;
|
||||||
|
std::string cmdLine_;
|
||||||
|
std::deque<std::string> errors_;
|
||||||
|
bool helpRequested_;
|
||||||
|
};
|
||||||
|
//************************************************************
|
||||||
|
// Implementation of ValueHolder<T>
|
||||||
|
//************************************************************
|
||||||
|
template<class T>
|
||||||
|
ValueHolder<T>::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<class T>
|
||||||
|
ValueHolder<T>::ValueHolder(const char* l,
|
||||||
|
T& v,
|
||||||
|
const char* desc,
|
||||||
|
bool mandatory)
|
||||||
|
: longName_(l),
|
||||||
|
value_(&v),
|
||||||
|
initialValue_(v),
|
||||||
|
description_(desc),
|
||||||
|
mandatory_(mandatory)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
template<class T>
|
||||||
|
ValueHolder<T>::ValueHolder(char s,
|
||||||
|
T& v,
|
||||||
|
const char* desc,
|
||||||
|
bool mandatory)
|
||||||
|
: shortName_(1,s),
|
||||||
|
value_(&v),
|
||||||
|
initialValue_(v),
|
||||||
|
description_(desc),
|
||||||
|
mandatory_(mandatory)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
template<class T>
|
||||||
|
std::string
|
||||||
|
ValueHolder<T>::name() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
if (!shortName_.empty()) os<<'-'<<shortName_;
|
||||||
|
if (!longName_.empty()) {
|
||||||
|
if (!shortName_.empty()) os<<'/';
|
||||||
|
os<<"--"<<longName_;
|
||||||
|
}
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
template<class T>
|
||||||
|
std::string
|
||||||
|
ValueHolder<T>::description() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os<<description_;
|
||||||
|
if (mandatory_)
|
||||||
|
{
|
||||||
|
os<<"(mandatory)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os<<"(default="<<initialValue_<<")";
|
||||||
|
}
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
//************************************************************
|
||||||
|
// Implementation of OptionHolder
|
||||||
|
//************************************************************
|
||||||
|
inline OptionHolder::OptionHolder(char s,
|
||||||
|
const char* l,
|
||||||
|
bool& b,
|
||||||
|
const char* desc)
|
||||||
|
: shortName_(1,s),
|
||||||
|
longName_(l),
|
||||||
|
value_(&b),
|
||||||
|
description_(desc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
inline OptionHolder::OptionHolder(const char* l,
|
||||||
|
bool& b,
|
||||||
|
const char* desc)
|
||||||
|
: longName_(l),
|
||||||
|
value_(&b),
|
||||||
|
description_(desc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
inline OptionHolder::OptionHolder(char s,
|
||||||
|
bool& b,
|
||||||
|
const char* desc)
|
||||||
|
: shortName_(1,s),
|
||||||
|
value_(&b),
|
||||||
|
description_(desc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
inline OptionHolder::OptionHolder(char s,
|
||||||
|
const char* l,
|
||||||
|
const char* desc)
|
||||||
|
: shortName_(1,s),
|
||||||
|
longName_(l),
|
||||||
|
value_(NULL),
|
||||||
|
description_(desc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
inline std::string
|
||||||
|
OptionHolder::name() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
if (!shortName_.empty()) os<<'-'<<shortName_;
|
||||||
|
if (!longName_.empty())
|
||||||
|
{
|
||||||
|
if (!shortName_.empty()) os<<'/';
|
||||||
|
os<<"--"<<longName_;
|
||||||
|
}
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
inline std::string
|
||||||
|
OptionHolder::description() const
|
||||||
|
{
|
||||||
|
return description_;
|
||||||
|
}
|
||||||
|
//************************************************************
|
||||||
|
// Implementation of ValuesHolder<T,O>
|
||||||
|
//************************************************************
|
||||||
|
template<class T,class O>
|
||||||
|
ValuesHolder<T,O>::ValuesHolder(const O& o,
|
||||||
|
const char* desc,
|
||||||
|
int len)
|
||||||
|
: value_(o),
|
||||||
|
description_(desc),
|
||||||
|
len_(len)
|
||||||
|
{
|
||||||
|
letter_ = argstream::uniqueLetter();
|
||||||
|
}
|
||||||
|
template <class T,class O>
|
||||||
|
std::string
|
||||||
|
ValuesHolder<T,O>::name() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os<<letter_<<"i";
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
template <class T,class O>
|
||||||
|
std::string
|
||||||
|
ValuesHolder<T,O>::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<std::string> 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<std::string>::const_iterator
|
||||||
|
// iter = args.begin();
|
||||||
|
// iter != args.end();++iter)
|
||||||
|
// {
|
||||||
|
// *p++ = const_cast<char*>(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 "<<a;
|
||||||
|
errors_.push_back(os.str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lastOption = &(options_[std::string(1,*cter)] = values_.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isOk_ = false;
|
||||||
|
errors_.push_back("Invalid argument -");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
values_.push_back(s);
|
||||||
|
if (lastOption != NULL)
|
||||||
|
{
|
||||||
|
*lastOption = --values_.end();
|
||||||
|
}
|
||||||
|
lastOption = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef ARGSTREAM_DEBUG
|
||||||
|
for (std::map<std::string,value_iterator>::const_iterator
|
||||||
|
iter = options_.begin();iter != options_.end();++iter)
|
||||||
|
{
|
||||||
|
std::cout<<"DEBUG: option "<<iter->first;
|
||||||
|
if (iter->second != values_.end())
|
||||||
|
{
|
||||||
|
std::cout<<" -> "<<*(iter->second);
|
||||||
|
}
|
||||||
|
std::cout<<std::endl;
|
||||||
|
}
|
||||||
|
for (std::list<std::string>::const_iterator
|
||||||
|
iter = values_.begin();iter != values_.end();++iter)
|
||||||
|
{
|
||||||
|
std::cout<<"DEBUG: value "<<*iter<<std::endl;
|
||||||
|
}
|
||||||
|
#endif // ARGSTREAM_DEBUG
|
||||||
|
}
|
||||||
|
inline bool
|
||||||
|
argstream::isOk() const
|
||||||
|
{
|
||||||
|
return isOk_;
|
||||||
|
}
|
||||||
|
inline bool
|
||||||
|
argstream::helpRequested() const
|
||||||
|
{
|
||||||
|
return helpRequested_;
|
||||||
|
}
|
||||||
|
inline std::string
|
||||||
|
argstream::usage() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os<<"usage: "<<progName_<<cmdLine_<<'\n';
|
||||||
|
unsigned int lmax = 0;
|
||||||
|
for (std::deque<help_entry>::const_iterator
|
||||||
|
iter = argHelps_.begin();iter != argHelps_.end();++iter)
|
||||||
|
{
|
||||||
|
if (lmax<iter->first.size()) lmax = iter->first.size();
|
||||||
|
}
|
||||||
|
for (std::deque<help_entry>::const_iterator
|
||||||
|
iter = argHelps_.begin();iter != argHelps_.end();++iter)
|
||||||
|
{
|
||||||
|
os<<'\t'<<iter->first<<std::string(lmax-iter->first.size(),' ')
|
||||||
|
<<" : "<<iter->second<<'\n';
|
||||||
|
}
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
inline std::string
|
||||||
|
argstream::errorLog() const
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
for(std::deque<std::string>::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<class T>
|
||||||
|
argstream&
|
||||||
|
operator>>(argstream& s,const ValueHolder<T>& 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 "<<v.shortName_<<" "<<v.longName_<<std::endl;
|
||||||
|
#endif
|
||||||
|
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||||
|
if (v.mandatory_)
|
||||||
|
{
|
||||||
|
if (!v.shortName_.empty())
|
||||||
|
{
|
||||||
|
s.cmdLine_ += " -";
|
||||||
|
s.cmdLine_ += v.shortName_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s.cmdLine_ += " --";
|
||||||
|
s.cmdLine_ += v.longName_;
|
||||||
|
}
|
||||||
|
s.cmdLine_ += " value";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!v.shortName_.empty())
|
||||||
|
{
|
||||||
|
s.cmdLine_ += " [-";
|
||||||
|
s.cmdLine_ += v.shortName_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s.cmdLine_ += " [--";
|
||||||
|
s.cmdLine_ += v.longName_;
|
||||||
|
}
|
||||||
|
s.cmdLine_ += " value]";
|
||||||
|
|
||||||
|
}
|
||||||
|
std::map<std::string,argstream::value_iterator>::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)<<std::endl;
|
||||||
|
#endif
|
||||||
|
ValueParser<T> 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);
|
||||||
|
|
||||||
|
// FIXME this loop seems to crash if a std::string is used as the value
|
||||||
|
//for (std::map<std::string,argstream::value_iterator>::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 "<<iter->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<<'-'<<v.shortName_;
|
||||||
|
if (!v.longName_.empty())
|
||||||
|
{
|
||||||
|
if (!v.shortName_.empty()) os<<'/';
|
||||||
|
os<<"--"<<v.longName_;
|
||||||
|
}
|
||||||
|
os<<" missing";
|
||||||
|
s.errors_.push_back(os.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
inline argstream&
|
||||||
|
operator>>(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 "<<v.shortName_<<" "<<v.longName_<<std::endl;
|
||||||
|
#endif
|
||||||
|
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||||
|
{
|
||||||
|
std::string c;
|
||||||
|
if (!v.shortName_.empty())
|
||||||
|
{
|
||||||
|
c += " [-";
|
||||||
|
c += v.shortName_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c += " [--";
|
||||||
|
c += v.longName_;
|
||||||
|
}
|
||||||
|
c += "]";
|
||||||
|
s.cmdLine_ = c+s.cmdLine_;
|
||||||
|
}
|
||||||
|
std::map<std::string,argstream::value_iterator>::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<class T,class O>
|
||||||
|
argstream&
|
||||||
|
operator>>(argstream& s,const ValuesHolder<T,O>& v)
|
||||||
|
{
|
||||||
|
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os<<' '<<v.letter_<<'1';
|
||||||
|
switch (v.len_)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
os<<"...";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
os<<"..."<<v.letter_<<v.len_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s.cmdLine_ += os.str();
|
||||||
|
}
|
||||||
|
std::list<std::string>::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<T> 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<std::string,argstream::value_iterator>::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 "<<v.len_<<" values";
|
||||||
|
s.errors_.push_back(os.str());
|
||||||
|
}
|
||||||
|
// Erase the values parsed
|
||||||
|
s.values_.erase(s.values_.begin(),first);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
inline void
|
||||||
|
argstream::defaultErrorHandling(bool ignoreUnused) const
|
||||||
|
{
|
||||||
|
if (helpRequested_)
|
||||||
|
{
|
||||||
|
std::cout<<usage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!isOk_)
|
||||||
|
{
|
||||||
|
std::cerr<<errorLog();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!ignoreUnused &&
|
||||||
|
(!values_.empty() || !options_.empty()))
|
||||||
|
{
|
||||||
|
std::cerr<<"Unused arguments"<<std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // ARGSTREAM_H
|
||||||
|
|
@ -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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "gopt.h"
|
|
||||||
|
|
||||||
#ifdef USE_SYSEXITS
|
|
||||||
#include <sysexits.h>
|
|
||||||
#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 );
|
|
||||||
}
|
|
@ -1,60 +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
|
|
||||||
|
|
||||||
#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 }
|
|
||||||
|
|
||||||
|
|
||||||
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 );
|
|
||||||
/* 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 );
|
|
||||||
/* 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 );
|
|
||||||
/* 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 );
|
|
||||||
/* 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 );
|
|
||||||
/* releases memory allocated in the corresponding call to gopt_sort()
|
|
||||||
* opts can no longer be used
|
|
||||||
*/
|
|
||||||
#endif /* GOPT_H_INCLUDED */
|
|
@ -1,354 +1,350 @@
|
|||||||
// digger.cpp
|
// digger.cpp
|
||||||
|
|
||||||
// Usage: Call with a list of TileClass ids separated by a space,
|
// 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.
|
// every (visible) tile on the map with that id will be designated for digging.
|
||||||
|
|
||||||
// NOTE currently only works with trees
|
// 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 a sort of "sub-target" to dig() to make it able to designate stone as well
|
||||||
// TODO add proper cli
|
// TODO add proper cli
|
||||||
// TODO add interactive text based menu
|
// TODO add interactive text based menu
|
||||||
// TODO add ability to mark num closest to cursor
|
// TODO add ability to mark num closest to cursor
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <integers.h>
|
#include <integers.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include <DFTypes.h>
|
#include <DFTypes.h>
|
||||||
#include <DFTileTypes.h>
|
#include <DFTileTypes.h>
|
||||||
#include <DFHackAPI.h>
|
#include <DFHackAPI.h>
|
||||||
|
#include <argstream/argstream.h>
|
||||||
int vec_count(vector<uint16_t>& vec, uint16_t t)
|
|
||||||
{
|
// counts the occurances of a certain element in a vector
|
||||||
int count = 0;
|
int vec_count(vector<uint16_t>& vec, uint16_t t)
|
||||||
for (uint32_t i = 0; i < vec.size(); ++i)
|
{
|
||||||
{
|
int count = 0;
|
||||||
if (vec[i] == t)
|
for (uint32_t i = 0; i < vec.size(); ++i)
|
||||||
++count;
|
{
|
||||||
}
|
if (vec[i] == t)
|
||||||
return count;
|
++count;
|
||||||
}
|
}
|
||||||
|
return count;
|
||||||
//// manhattan distance
|
}
|
||||||
//int source_distance(int sx, int sy, int sz,
|
|
||||||
// int x, int y, int z, int i)
|
// splits a string on a certain char
|
||||||
//{
|
//
|
||||||
// // TODO changing x and y seems to be optimized away (?)
|
// src is the string to split
|
||||||
// cout << x << " " << i << " " << i%16 << " " << x+(i%16) << endl;
|
// delim is the delimiter to split the string around
|
||||||
//
|
// tokens is filled with every occurance between delims
|
||||||
// // handle the fact that x,y,z refers to a 16x16 grid
|
void string_split(vector<string>& tokens, const std::string& src, const std::string& delim)
|
||||||
// //x += i%16;
|
{
|
||||||
// //y += i/16;
|
std::string::size_type start = 0;
|
||||||
// int dx = i%16;
|
std::string::size_type end;
|
||||||
// int dy = i/16;
|
while (true)
|
||||||
// //x *= 16;
|
{
|
||||||
// //y *= 16;
|
end = src.find(delim, start);
|
||||||
// //x += dx;
|
tokens.push_back(src.substr(start, end - start));
|
||||||
// //y += dy;
|
if (end == std::string::npos) // last token handled
|
||||||
// return abs(sx-(x+(i%16)))+abs(sy-(y+(i/16)))+abs(sz-z);
|
break;
|
||||||
//}
|
start = end + delim.size(); // skip next delim
|
||||||
|
}
|
||||||
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);
|
void parse_int_csv(vector<uint16_t>& targets, const std::string& src)
|
||||||
}
|
{
|
||||||
|
std::string::size_type start = 0;
|
||||||
struct DigTarget
|
std::string::size_type end;
|
||||||
{
|
while (true)
|
||||||
//public:
|
{
|
||||||
DigTarget() :
|
end = src.find(",", start);
|
||||||
source_distance(0),
|
targets.push_back(atoi(src.substr(start, end - start).c_str()));
|
||||||
grid_x(0), grid_y(0),
|
if (end == std::string::npos) // last token handled
|
||||||
local_x(0), local_y(0),
|
break;
|
||||||
real_x(0), real_y(0), z(0)
|
start = end + 1; // skip next delim
|
||||||
{
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DigTarget(
|
// calculates the manhattan distance between two coords
|
||||||
int realx, int realy, int _z,
|
int manhattan_distance(int x, int y, int z, int xx, int yy, int zz)
|
||||||
int sourcex, int sourcey, int sourcez) :
|
{
|
||||||
//grid_x(realx/16), grid_y(realy/16),
|
return abs(x-xx)+abs(y-yy)+abs(z-zz);
|
||||||
//local_x(realx%16), local_y(realy%16),
|
}
|
||||||
real_x(realx), real_y(realy), z(_z)
|
|
||||||
{
|
struct DigTarget
|
||||||
grid_x = realx/16;
|
{
|
||||||
grid_y = realy/16;
|
DigTarget() :
|
||||||
|
source_distance(0),
|
||||||
local_x = realx%16;
|
grid_x(0), grid_y(0),
|
||||||
local_y = realy%16;
|
local_x(0), local_y(0),
|
||||||
|
real_x(0), real_y(0), z(0)
|
||||||
source_distance = manhattan_distance(
|
{
|
||||||
real_x, real_y, z,
|
}
|
||||||
sourcex, sourcey, sourcez);
|
|
||||||
}
|
DigTarget(
|
||||||
|
int realx, int realy, int _z,
|
||||||
DigTarget(
|
int sourcex, int sourcey, int sourcez) :
|
||||||
int gridx, int gridy, int _z,
|
real_x(realx), real_y(realy), z(_z)
|
||||||
int localx, int localy,
|
{
|
||||||
int sourcex, int sourcey, int sourcez) :
|
grid_x = realx/16;
|
||||||
//source_distance(manhattan_distance(
|
grid_y = realy/16;
|
||||||
// realx, realy, realz,
|
|
||||||
// sourcex, sourcey, sourcez)),
|
local_x = realx%16;
|
||||||
grid_x(gridx), grid_y(gridy),
|
local_y = realy%16;
|
||||||
local_x(localx), local_y(localy),
|
|
||||||
z(_z)
|
source_distance = manhattan_distance(
|
||||||
//real_x(realx), real_y(realy), real_z(realz)
|
real_x, real_y, z,
|
||||||
{
|
sourcex, sourcey, sourcez);
|
||||||
real_x = (grid_x*16)+local_x;
|
}
|
||||||
real_y = (grid_y*16)+local_y;
|
|
||||||
|
DigTarget(
|
||||||
source_distance = manhattan_distance(
|
int gridx, int gridy, int _z,
|
||||||
real_x, real_y, z,
|
int localx, int localy,
|
||||||
sourcex, sourcey, sourcez);
|
int sourcex, int sourcey, int sourcez) :
|
||||||
}
|
grid_x(gridx), grid_y(gridy),
|
||||||
|
local_x(localx), local_y(localy),
|
||||||
int source_distance; // the distance to the source coords, used for sorting
|
z(_z)
|
||||||
//int source_distance() const { return _source_distance; }
|
{
|
||||||
|
real_x = (grid_x*16)+local_x;
|
||||||
int grid_x, grid_y;
|
real_y = (grid_y*16)+local_y;
|
||||||
int local_x, local_y;
|
|
||||||
int real_x, real_y;
|
source_distance = manhattan_distance(
|
||||||
int z;
|
real_x, real_y, z,
|
||||||
//int index;
|
sourcex, sourcey, sourcez);
|
||||||
|
}
|
||||||
//const bool valid;
|
|
||||||
|
int source_distance; // the distance to the source coords, used for sorting
|
||||||
bool operator<(const DigTarget& o) const { return source_distance < o.source_distance; }
|
|
||||||
|
int grid_x, grid_y;
|
||||||
//private:
|
int local_x, local_y;
|
||||||
// int source_x, source_y, source_z;
|
int real_x, real_y;
|
||||||
// int _source_distance;
|
int z;
|
||||||
};
|
|
||||||
|
bool operator<(const DigTarget& o) const { return source_distance < o.source_distance; }
|
||||||
int dig(DFHack::API& DF,
|
};
|
||||||
vector<uint16_t>& targets,
|
|
||||||
int num = -1,
|
int dig(DFHack::API& DF,
|
||||||
const int x_source = 0,
|
vector<uint16_t>& targets,
|
||||||
const int y_source = 0,
|
int num = -1,
|
||||||
const int z_source = 0)
|
const int x_source = 0,
|
||||||
{
|
const int y_source = 0,
|
||||||
if (num == 0)
|
const int z_source = 0)
|
||||||
return 0; // max limit of 0, nothing to do
|
{
|
||||||
|
if (num == 0)
|
||||||
uint32_t x_max,y_max,z_max;
|
return 0; // max limit of 0, nothing to do
|
||||||
DFHack::t_designation designations[16][16];
|
|
||||||
uint16_t tiles[16][16];
|
uint32_t x_max,y_max,z_max;
|
||||||
//uint32_t count = 0;
|
DFHack::t_designation designations[16][16];
|
||||||
DF.getSize(x_max,y_max,z_max);
|
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<DigTarget> candidates;
|
// every tile found, will later be sorted by distance to source
|
||||||
|
vector<DigTarget> 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++)
|
||||||
// walk the map
|
{
|
||||||
for(uint32_t x = 0; x < x_max; x++)
|
for(uint32_t y = 0; y < y_max; y++)
|
||||||
{
|
{
|
||||||
for(uint32_t y = 0; y < y_max; y++)
|
for(uint32_t z = 0; z < z_max; z++)
|
||||||
{
|
{
|
||||||
for(uint32_t z = 0; z < z_max; z++)
|
if(DF.isValidBlock(x,y,z))
|
||||||
{
|
{
|
||||||
if (z != z_source)
|
// read block designations and tiletype
|
||||||
continue; // hack to cut down on targets
|
DF.ReadDesignations(x,y,z, (uint32_t *) designations);
|
||||||
|
DF.ReadTileTypes(x,y,z, (uint16_t *) tiles);
|
||||||
if(DF.isValidBlock(x,y,z))
|
|
||||||
{
|
// search all tiles for dig targets:
|
||||||
// read block designations and tiletype
|
// visible, not yet marked for dig and matching tile type
|
||||||
DF.ReadDesignations(x,y,z, (uint32_t *) designations);
|
for(uint32_t lx = 0; lx < 16; lx++)
|
||||||
DF.ReadTileTypes(x,y,z, (uint16_t *) tiles);
|
{
|
||||||
|
for(uint32_t ly = 0; ly < 16; ly++)
|
||||||
// search all tiles for dig targets:
|
{
|
||||||
// visible, not yet marked for dig and matching tile type
|
if (designations[lx][ly].bits.hidden == 0 &&
|
||||||
for(uint32_t lx = 0; lx < 16; lx++)
|
designations[lx][ly].bits.dig == 0 &&
|
||||||
{
|
vec_count(targets, DFHack::tileTypeTable[tiles[lx][ly]].c) > 0)
|
||||||
for(uint32_t ly = 0; ly < 16; ly++)
|
{
|
||||||
{
|
candidates.push_back(DigTarget(
|
||||||
if (designations[lx][ly].bits.hidden == 0 &&
|
x, y, z,
|
||||||
designations[lx][ly].bits.dig == 0 &&
|
lx, ly,
|
||||||
vec_count(targets, DFHack::tileTypeTable[tiles[lx][ly]].c) > 0)
|
x_source, y_source, z_source));
|
||||||
{
|
|
||||||
//cout << "target found at: ";
|
//cout << "target found at " << world_x << " " << world_y << " " << z;
|
||||||
//cout << x << "," << y << "," << z << "," << i << endl;
|
//cout << ", " << dt->source_distance << " tiles to source" << endl;
|
||||||
|
}
|
||||||
//designations[i].bits.dig = DFHack::designation_default;
|
} // local y
|
||||||
//++count;
|
} // local x
|
||||||
|
}
|
||||||
//int realx = (x*16)+lx;
|
}
|
||||||
//int realy = (y*16)+ly;
|
}
|
||||||
|
}
|
||||||
candidates.push_back(DigTarget(
|
// if we found more tiles than was requested, sort them by distance to source,
|
||||||
x, y, z,
|
// keep the front 'num' elements and drop the rest
|
||||||
lx, ly,
|
if (num != -1 && candidates.size() > (unsigned int)num)
|
||||||
x_source, y_source, z_source));
|
{
|
||||||
|
sort(candidates.begin(), candidates.end());
|
||||||
//cout << "target found at " << world_x << " " << world_y << " " << z;
|
candidates.resize(num);
|
||||||
//cout << ", " << dt->source_distance << " tiles to source" << endl;
|
}
|
||||||
|
num = candidates.size();
|
||||||
//if (world_x > debugmaxx)
|
|
||||||
// debugmaxx = world_x;
|
//cout << "============================" << endl;
|
||||||
//if (world_y > debugmaxy)
|
//cout << "source is " << x_source << " " << y_source << " " << z_source << endl;
|
||||||
// debugmaxy = world_y;
|
|
||||||
}
|
// mark the tiles for actual digging
|
||||||
} // local y
|
for (vector<DigTarget>::const_iterator i = candidates.begin(); i != candidates.end(); ++i)
|
||||||
} // local x
|
{
|
||||||
}
|
//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
|
||||||
// TODO the following routine doesnt check if the tile is already marked for digging
|
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;
|
||||||
// if we found more tiles than was requested, sort them by distance to source,
|
DF.WriteDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations);
|
||||||
// keep the front 'num' elements and drop the rest
|
}
|
||||||
if (num != -1 && candidates.size() > (unsigned int)num)
|
|
||||||
{
|
return num;
|
||||||
sort(candidates.begin(), candidates.end());
|
}
|
||||||
candidates.resize(num);
|
|
||||||
}
|
void test()
|
||||||
num = candidates.size();
|
{
|
||||||
|
//////////////////////////
|
||||||
cout << "============================" << endl;
|
// DigTarget
|
||||||
cout << "source is " << x_source << " " << y_source << " " << z_source << endl;
|
{
|
||||||
|
DigTarget dt(
|
||||||
// mark the tiles for actual digging
|
20, 35, 16,
|
||||||
for (vector<DigTarget>::const_iterator i = candidates.begin(); i != candidates.end(); ++i)
|
10, 12, 14);
|
||||||
{
|
|
||||||
//int grid_x = (*i).x/16;
|
assert(dt.grid_x == 1);
|
||||||
//int grid_y = (*i).y/16;
|
assert(dt.grid_y == 2);
|
||||||
//int z = (*i).z;
|
|
||||||
|
assert(dt.local_x == 4);
|
||||||
//int local_x = (*i).x%grid_x;
|
assert(dt.local_y == 3);
|
||||||
//int local_y = (*i).y%grid_y;
|
|
||||||
|
assert(dt.real_x == 20);
|
||||||
cout << "designating at " << (*i).real_x << " " << (*i).real_y << " " << (*i).z;
|
assert(dt.real_y == 35);
|
||||||
cout << ", " << (*i).source_distance << " tiles to source" << endl;
|
|
||||||
|
assert(dt.z == 16);
|
||||||
// TODO this could probably be made much better, theres a big chance the trees are on the same grid
|
assert(dt.source_distance == 35);
|
||||||
// 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;
|
DigTarget dt(
|
||||||
DF.WriteDesignations((*i).grid_x, (*i).grid_y, (*i).z, (uint32_t *) designations);
|
2, 4, 16,
|
||||||
}
|
5, 10,
|
||||||
|
10, 12, 14);
|
||||||
//cout << debugmaxx << " " << debugmaxy << endl;
|
|
||||||
|
assert(dt.grid_x == 2);
|
||||||
return num;
|
assert(dt.grid_y == 4);
|
||||||
}
|
|
||||||
|
assert(dt.local_x == 5);
|
||||||
void test()
|
assert(dt.local_y == 10);
|
||||||
{
|
|
||||||
{
|
assert(dt.real_x == 37);
|
||||||
DigTarget dt;
|
assert(dt.real_y == 74);
|
||||||
//assert(!dt.valid);
|
|
||||||
}
|
assert(dt.z == 16);
|
||||||
|
assert(dt.source_distance == 91);
|
||||||
{
|
}
|
||||||
DigTarget dt(
|
|
||||||
20, 35, 16,
|
//////////////////////////
|
||||||
10, 12, 14);
|
// string splitter
|
||||||
|
{
|
||||||
assert(dt.grid_x == 1);
|
vector<string> tokens;
|
||||||
assert(dt.grid_y == 2);
|
string src = "10,9,11";
|
||||||
|
string delim = ",";
|
||||||
assert(dt.local_x == 4);
|
string_split(tokens, src, delim);
|
||||||
assert(dt.local_y == 3);
|
|
||||||
|
assert(tokens.size() == 3);
|
||||||
assert(dt.real_x == 20);
|
assert(tokens[0] == "10");
|
||||||
assert(dt.real_y == 35);
|
assert(tokens[1] == "9");
|
||||||
|
assert(tokens[2] == "11");
|
||||||
assert(dt.z == 16);
|
}
|
||||||
assert(dt.source_distance == 35);
|
{
|
||||||
//assert(dt.valid);
|
vector<string> tokens;
|
||||||
}
|
string src = "10";
|
||||||
|
string delim = ",";
|
||||||
{
|
string_split(tokens, src, delim);
|
||||||
DigTarget dt(
|
|
||||||
2, 4, 16,
|
assert(tokens.size() == 1);
|
||||||
5, 10,
|
assert(tokens[0] == "10");
|
||||||
10, 12, 14);
|
}
|
||||||
|
{
|
||||||
assert(dt.grid_x == 2);
|
vector<uint16_t> targets;
|
||||||
assert(dt.grid_y == 4);
|
parse_int_csv(targets, "9,10");
|
||||||
|
assert(targets[0] == 9);
|
||||||
assert(dt.local_x == 5);
|
assert(targets[1] == 10);
|
||||||
assert(dt.local_y == 10);
|
}
|
||||||
|
}
|
||||||
assert(dt.real_x == 37);
|
|
||||||
assert(dt.real_y == 74);
|
int main (int argc, char** argv)
|
||||||
|
{
|
||||||
assert(dt.z == 16);
|
test();
|
||||||
assert(dt.source_distance == 91);
|
|
||||||
//assert(dt.valid);
|
// Command line options
|
||||||
}
|
string s_targets;
|
||||||
|
string s_origin = "0,0,0";
|
||||||
//{ // sorting
|
bool verbose;
|
||||||
// DigTarget a(
|
int max;
|
||||||
// 20, 35, 16,
|
argstream as(argc,argv);
|
||||||
// 10, 12, 14);
|
|
||||||
|
as >>option('v',"verbose",verbose,"Active verbose mode") // TODO handle verbose
|
||||||
// DigTarget b(
|
>>parameter('o',"origin",s_origin,"Close to where we should designate targets, format: x,y,z")
|
||||||
// 2, 4, 16,
|
>>parameter('t',"targets",s_targets,"What kinds of tile we should designate, format: type1,type2")
|
||||||
// 5, 10,
|
>>parameter('m',"max",max,"The maximum limit of designated targets")
|
||||||
// 10, 12, 14);
|
>>help();
|
||||||
|
|
||||||
// vector<DigTarget> v;
|
// handle some commands
|
||||||
// v.push_back(b);
|
vector<uint16_t> targets;
|
||||||
// v.push_back(a);
|
parse_int_csv(targets, s_targets);
|
||||||
// sort(v.begin(), v.end());
|
|
||||||
// assert(*(v.begin()) == a);
|
vector<uint16_t> origin;
|
||||||
//}
|
parse_int_csv(origin, s_origin);
|
||||||
}
|
|
||||||
|
// sane check
|
||||||
int main (int argc, const char* argv[])
|
if (!as.isOk())
|
||||||
{
|
{
|
||||||
test();
|
cout << as.errorLog();
|
||||||
|
}
|
||||||
vector<uint16_t> targets;
|
else if (targets.size() == 0 || origin.size() != 3)
|
||||||
for (int i = 1; i < argc; ++i)
|
{
|
||||||
{
|
//cout << "Usage: Call with a list of TileClass ids separated by a space,\n";
|
||||||
targets.push_back(atoi(argv[i]));
|
//cout << "every (visible) tile on the map with that id will be designated for digging.\n\n";
|
||||||
}
|
cout << as.usage();
|
||||||
if (targets.size() == 0)
|
}
|
||||||
{
|
else
|
||||||
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";
|
DFHack::API DF("Memory.xml");
|
||||||
}
|
if(!DF.Attach())
|
||||||
else
|
{
|
||||||
{
|
cerr << "DF not found" << endl;
|
||||||
DFHack::API DF("Memory.xml");
|
return 1;
|
||||||
if(!DF.Attach())
|
}
|
||||||
{
|
DF.InitMap();
|
||||||
cerr << "DF not found" << 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.InitMap();
|
//DF.InitViewAndCursor();
|
||||||
|
//if (!DF.getViewCoords(x_source, y_source, z_source))
|
||||||
// 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
|
// cerr << "Enable cursor" << endl;
|
||||||
//DF.InitViewAndCursor();
|
// return 1;
|
||||||
//if (!DF.getViewCoords(x_source, y_source, z_source))
|
//}
|
||||||
//{
|
|
||||||
// cerr << "Enable cursor" << endl;
|
int count = dig(DF, targets, 10, origin[0],origin[1],origin[2]); // <-- important part
|
||||||
// return 1;
|
cout << count << " targets designated" << endl;
|
||||||
//}
|
|
||||||
|
DF.Detach();
|
||||||
int count = dig(DF, targets, 10, x_source, y_source, z_source); // <-- important part
|
}
|
||||||
cout << count << " targets designated" << endl;
|
#ifndef LINUX_BUILD
|
||||||
|
cout << "Done. Press any key to continue" << endl;
|
||||||
DF.Detach();
|
cin.ignore();
|
||||||
}
|
#endif
|
||||||
#ifndef LINUX_BUILD
|
return 0;
|
||||||
cout << "Done. Press any key to continue" << endl;
|
}
|
||||||
cin.ignore();
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue