00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef _CJ_OPTIONS_HELPER_H_
00020 #define _CJ_OPTIONS_HELPER_H_ 1
00021
00022 #include <string>
00023 #include <list>
00024 #include <map>
00025 #include <algorithm>
00026 #include <stdexcept>
00027 #include <boost/tokenizer.hpp>
00028 #include <boost/lexical_cast.hpp>
00029 #include <boost/numeric/conversion/cast.hpp>
00030 #include <CjVisitorFactory.hh>
00031 #include "Cj_container_helper.hh"
00032
00033 namespace jmitie {
00034
00035 typedef std::pair< std::string, std::string > optval_t;
00036
00038 std::list< optval_t > parseOptions (std::string optionString, bool allowDupes = false, bool requireCurlies = true);
00039
00040 class Cj_OptionParseFail : public std::runtime_error {
00041 public:
00042 explicit Cj_OptionParseFail (const std::string & message) : std::runtime_error(message) { }
00043
00044 virtual ~Cj_OptionParseFail() throw() {}
00045 };
00046
00047
00048 template <typename Iter> inline std::list<std::string> judeanPopularPeoplesFront( const Iter & first, const Iter & last, const std::string drop_delims, const std::string keep_delims ) {
00049 std::list<std::string> out;
00050 typedef boost::tokenizer < boost::char_separator<char> > toker_t;
00051 toker_t toks( first, last, boost::char_separator<char> (drop_delims.c_str(), keep_delims.c_str()) );
00052 std::copy( toks.begin(), toks.end(), std::back_inserter(out) );
00053 return out;
00054 }
00055
00059 enum throwFlags_t {
00060 DONT_THROW = 0L,
00061 THROW_ON_MISSING = 1L,
00062 THROW_ON_DUPE = (1L << 1),
00063 THROW_ON_BADVAL = (1L << 2)
00064 };
00065
00066 inline throwFlags_t operator|(throwFlags_t a, throwFlags_t b) { return throwFlags_t(static_cast<int>(a) | static_cast<int>(b)); }
00067 inline throwFlags_t operator&(throwFlags_t a, throwFlags_t b) { return throwFlags_t(static_cast<int>(a) & static_cast<int>(b)); }
00068 inline throwFlags_t & operator|=(throwFlags_t & a, throwFlags_t b) { return a = a | b; }
00069 inline throwFlags_t & operator&=(throwFlags_t & a, throwFlags_t b) { return a = a & b; }
00070
00072
00084 template <typename FactoryType, typename ContainerType> inline bool extractFactoryTypeOption (ContainerType & cont, const FactoryType & factory, typename FactoryType::Visitor_shared_ptr & result, const throwFlags_t flags, const typename FactoryType::VisitorArgumentType & va ) {
00085 typename FactoryType::Visitor_shared_ptr output;
00086 if(result) return false;
00087 typename ContainerType::iterator it = cont.begin();
00088 for( ; it != cont.end(); ++it) {
00089 try {
00090 output = factory.createInstance_sharedptr( it->first, it->second, va );
00091 JLOG(4, std::cout << "extractFactoryTypeOption: Created " + factory.description() + " ok" << std::endl; )
00092 break;
00093 } catch (const Cj_NotFoundInFactoryException &) { JLOG(5,std::cout << "extractFactoryTypeOption: " << it->first << " not found in this factory." << std::endl;) }
00094 }
00095 if(it != cont.end()) {
00096 it = cont.erase(it);
00097 result = output;
00098 return true;
00099 }
00100
00101 if(flags & THROW_ON_MISSING) throw Cj_OptionParseFail ("extractFactoryTypeOption: a " + factory.description() + " is required." );
00102 return false;
00103 }
00104
00106
00119 template <typename POD, typename ContainerType> inline bool extractPODValueOption(const std::string optionName, ContainerType & cont, POD & result, const POD * const min_val = 0, const POD * const max_val = 0, const throwFlags_t flags = (THROW_ON_DUPE | THROW_ON_BADVAL) ) {
00120 typedef typename ContainerType::iterator It;
00121 It begin = cont.begin();
00122 It end = cont.end();
00123 It it = jsplib::searchFirstField(begin,end,optionName);
00124 if(it == end) {
00125 if(flags & THROW_ON_MISSING)
00126 throw Cj_OptionParseFail ("extractPODValueOption: option " + optionName + " is required." );
00127 else return false;
00128 }
00129 if(it->second.empty()) {
00130 if (flags & THROW_ON_BADVAL) throw Cj_OptionParseFail ("extractPODValueOption: option " + it->first + " requires a value." );
00131 else return false;
00132 }
00133 if((flags & THROW_ON_DUPE) && (end!=jsplib::searchFirstField( ++It(it), end, optionName ))) throw Cj_OptionParseFail ("extractPODValueOption: please specify " + optionName + " option only once." );
00134 POD val;
00135 try {
00136 val = boost::lexical_cast<POD>(it->second);
00137 if(min_val&&(val<*min_val)) throw boost::bad_lexical_cast();
00138 if(max_val&&(val>*max_val)) throw boost::bad_lexical_cast();
00139 } catch (boost::bad_lexical_cast &) {
00140 if( !(flags & THROW_ON_BADVAL)) return false;
00141 std::string s ("extractPODValueOption: Couldn't parse value from " + it->second);
00142 if(min_val&&(val<*min_val)) {
00143 s.append(": value must be greater or equal to ");
00144 s.append(boost::lexical_cast<std::string>(*min_val));
00145 }
00146 if(min_val&&(val>*max_val)) {
00147 s.append(": value must be less or equal to ");
00148 s.append(boost::lexical_cast<std::string>(*max_val));
00149 }
00150 throw Cj_OptionParseFail( s );
00151 }
00152 cont.erase(it);
00153 result = val;
00154 return true;
00155 }
00156
00158
00169 template <typename ContainerType> inline bool extractStringOption(const std::string optionName, ContainerType & cont, std::string & result, const throwFlags_t flags = (THROW_ON_DUPE | THROW_ON_BADVAL) ) {
00170 typedef typename ContainerType::iterator It;
00171 It begin = cont.begin();
00172 It end = cont.end();
00173 It it = jsplib::searchFirstField(begin,end,optionName);
00174 if(it == end) {
00175 if (flags & THROW_ON_MISSING)
00176 throw Cj_OptionParseFail ("extractStringOption: option " + optionName + " is required." );
00177 else return false;
00178 }
00179 if(it->second.empty()) {
00180 if (flags & THROW_ON_BADVAL) throw Cj_OptionParseFail ("extractStringOption: option " + it->first + " requires a string as a value. " );
00181 else return false;
00182 }
00183 std::string val;
00184 val = it->second;
00185 if((flags & THROW_ON_DUPE) && (end!=jsplib::searchFirstField( ++It(it), end, optionName ))) throw Cj_OptionParseFail ("extractStringOption: please specify " + optionName + " option only once." );
00186 cont.erase(it);
00187 swap(result,val);
00188 return true;
00189 }
00190
00191 template <typename ContainerType> inline bool extractValuelessOption(const std::string optionName, ContainerType & cont, const throwFlags_t flags = (THROW_ON_DUPE | THROW_ON_BADVAL) ) {
00192 typedef typename ContainerType::iterator It;
00193 It begin = cont.begin();
00194 It end = cont.end();
00195 It it = jsplib::searchFirstField(begin,end,optionName);
00196 if(it == end) {
00197 if (flags & THROW_ON_MISSING)
00198 throw Cj_OptionParseFail ("extractValuelessOption: option " + optionName + " is required." );
00199 else return false;
00200 }
00201 if(!it->second.empty()) {
00202 if (flags & THROW_ON_BADVAL) throw Cj_OptionParseFail ("extractValuelessOption: option " + it->first + " cannot have a value." );
00203 else return false;
00204 }
00205 if((flags & THROW_ON_DUPE) && (end!=jsplib::searchFirstField(++It(it),end,optionName))) throw Cj_OptionParseFail ("extractValuelessOption: please specify " + optionName + " option only once." );
00206 cont.erase(it);
00207 return true;
00208 }
00209
00210 template <typename ContainerType, typename RESULT_TYPE> inline bool extractValuelessMultiOption( const std::map< std::string, RESULT_TYPE > & options, ContainerType & cont, RESULT_TYPE & result, const throwFlags_t flags = (THROW_ON_DUPE | THROW_ON_BADVAL) ) {
00211 typedef typename ContainerType::iterator cont_It;
00212 typedef typename std::map< std::string, RESULT_TYPE >::const_iterator opt_CIt;
00213 cont_It found_at = cont.end();
00214 RESULT_TYPE res;
00215
00216 for(cont_It it = cont.begin(); it != cont.end(); ++it) {
00217
00218 opt_CIt optit = options.find( it->first );
00219 if(optit == options.end()) continue;
00220 if((found_at != cont.end()) && (flags & THROW_ON_DUPE)) {
00221 std::string s("extractValuelessMultiOption: please specify one of ( ");
00222 for(opt_CIt oit = options.begin(); oit != options.end(); ++oit) { s.append(oit->first); s.append(1, ' '); }
00223 s += ") only once.";
00224 throw Cj_OptionParseFail ( s );
00225 }
00226 if(found_at == cont.end()) {
00227 res = optit->second;
00228 found_at = it;
00229 if(flags & THROW_ON_DUPE) continue;
00230 else break;
00231 }
00232 }
00233
00234 if(found_at == cont.end()) {
00235 if (flags & THROW_ON_MISSING) {
00236 std::string s("extractValuelessMultiOption: please specify one of ( ");
00237 for(opt_CIt oit = options.begin(); oit != options.end(); ++oit) { s.append(oit->first); s.append(1, ' '); }
00238 s += ") only once.";
00239 throw Cj_OptionParseFail ( s );
00240 } else return false;
00241 }
00242
00243 if(!found_at->second.empty()) {
00244 if (flags & THROW_ON_BADVAL) throw Cj_OptionParseFail ("extractValuelessMultiOption: option " + found_at->first + " cannot have a value." );
00245 else return false;
00246 }
00247 result = res;
00248 cont.erase(found_at);
00249 return true;
00250 }
00251
00252 template <typename ContainerType> inline std::string listOptionNames( const ContainerType & cont ) {
00253 typename ContainerType::const_iterator begin = cont.begin();
00254 typename ContainerType::const_iterator end = cont.end();
00255 if(begin==end) return "";
00256 std::string result(begin->first);
00257 ++begin;
00258 while (begin != end) {
00259 result.append(" ");
00260 result.append(begin->first);
00261 ++begin;
00262 }
00263 return result;
00264 }
00265
00266
00267
00268
00269
00270 template <typename fwdIter> inline fwdIter extractUInt( const fwdIter & begin, const fwdIter & end, unsigned int & j ) {
00271 fwdIter retval;
00272 if(begin==end) return end;
00273 for(retval = begin; retval != end; ++retval) if( ( *retval < '0' ) || ( *retval > '9') ) break;
00274 if(begin==retval) return retval;
00275 std::string s(begin,retval);
00276 unsigned int val;
00277
00278
00279
00280
00281 val = boost::lexical_cast<unsigned int>(s);
00282 j = val;
00283 return retval;
00284 }
00285
00286 }
00287
00288 #endif // _CJ_OPTIONS_HELPER_H_