File indexing completed on 2024-04-06 12:03:07
0001 #ifndef CONDTOOLS_HCAL_CMDLINE_H_
0002 #define CONDTOOLS_HCAL_CMDLINE_H_
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099 #include <list>
0100 #include <sstream>
0101 #include <cstring>
0102 #include <utility>
0103 #include <cstdio>
0104
0105 #ifdef __GNUC__
0106 #include <cstdlib>
0107 #include <typeinfo>
0108 #include <cxxabi.h>
0109 #endif
0110
0111 #ifdef __GXX_EXPERIMENTAL_CXX0X__
0112 #include <memory>
0113 #define CmdLine_shared_ptr std::shared_ptr
0114 #else
0115 #include <tr1/memory>
0116 #define CmdLine_shared_ptr std::tr1::shared_ptr
0117 #endif
0118
0119 namespace cmdline {
0120
0121
0122 class CmdLineError {
0123 public:
0124 inline CmdLineError(const char* msg = nullptr) : os_(new std::ostringstream()) {
0125 if (msg)
0126 *os_ << msg;
0127 }
0128
0129 template <typename T>
0130 inline CmdLineError& operator<<(const T& obj) {
0131 *os_ << obj;
0132 return *this;
0133 }
0134
0135 inline std::string str() const { return os_->str(); }
0136
0137 private:
0138 CmdLine_shared_ptr<std::ostringstream> os_;
0139 };
0140
0141 template <typename T>
0142 inline void OneShotExtract(std::istringstream& is, T& obj) {
0143 is >> obj;
0144 }
0145
0146 template <>
0147 inline void OneShotExtract<std::string>(std::istringstream& is, std::string& obj) {
0148 obj = is.str();
0149 is.seekg(0, std::ios_base::end);
0150 }
0151
0152 class OneShotIStream {
0153 public:
0154 inline OneShotIStream() : valid_(false), readout_(false) {}
0155
0156 inline OneShotIStream(const std::string& s) : str_(s), valid_(true), readout_(false) {}
0157
0158 inline operator void*() const { return valid_ && !readout_ ? (void*)this : (void*)nullptr; }
0159
0160 template <typename T>
0161 inline bool operator>>(T& obj) {
0162 if (readout_)
0163 throw CmdLineError() << "can't reuse command line argument \"" << str_ << '"';
0164 readout_ = true;
0165 if (valid_) {
0166 std::istringstream is(str_);
0167 OneShotExtract(is, obj);
0168 if (is.bad() || is.fail())
0169 throw CmdLineError() << "failed to parse command line argument \"" << str_ << '"'
0170 #ifdef __GNUC__
0171 << ", " << demangle(obj) << " expected"
0172 #endif
0173 ;
0174 if (is.peek() != EOF)
0175 throw CmdLineError() << "extra characters in command line argument \"" << str_ << '"'
0176 #ifdef __GNUC__
0177 << ", " << demangle(obj) << " expected"
0178 #endif
0179 ;
0180 }
0181 return valid_;
0182 }
0183
0184 inline bool isValid() const { return valid_; }
0185
0186 private:
0187 std::string str_;
0188 bool valid_;
0189 bool readout_;
0190
0191 #ifdef __GNUC__
0192 template <typename T>
0193 inline std::string demangle(T& obj) const {
0194 int status;
0195 const std::type_info& ti = typeid(obj);
0196 char* realname = abi::__cxa_demangle(ti.name(), nullptr, nullptr, &status);
0197 std::string s(realname);
0198 free(realname);
0199 return s;
0200 }
0201 #endif
0202 };
0203
0204 class CmdLine {
0205
0206
0207
0208
0209
0210 typedef std::pair<std::string, int> Pair;
0211 typedef std::list<Pair> Optlist;
0212
0213 inline Optlist::iterator find(const char* shortOpt, const char* longOpt) {
0214 Optlist::iterator iend = args_.end();
0215 for (Optlist::iterator it = args_.begin(); it != iend; ++it) {
0216 if (shortOpt && it->second == 1 && it->first == shortOpt)
0217 return it;
0218 if (longOpt && it->second == 2 && it->first == longOpt)
0219 return it;
0220 }
0221 return iend;
0222 }
0223
0224 public:
0225 inline CmdLine(const unsigned argc, const char* const argv[]) : nprogargs_(0) {
0226
0227 const char* progname = std::strrchr(argv[0], '/');
0228 if (progname)
0229 ++progname;
0230 else
0231 progname = argv[0];
0232
0233
0234 if (strncmp(progname, "lt-", 3) == 0)
0235 progname += 3;
0236 progname_ = progname;
0237
0238
0239
0240 bool previousIsOpt = false;
0241 bool nextIsArg = false;
0242 for (unsigned i = 1; i < argc; ++i) {
0243 if (nextIsArg) {
0244 args_.push_back(Pair(argv[i], previousIsOpt ? 0 : 3));
0245 previousIsOpt = false;
0246 ++nprogargs_;
0247 nextIsArg = false;
0248 } else if (strcmp(argv[i], "-") == 0)
0249 nextIsArg = true;
0250 else if (strcmp(argv[i], "--") == 0) {
0251
0252 for (unsigned k = i + 1; k < argc; ++k) {
0253 args_.push_back(Pair(argv[k], 3));
0254 ++nprogargs_;
0255 }
0256 return;
0257 } else if (strncmp(argv[i], "--", 2) == 0) {
0258 args_.push_back(Pair(argv[i], 2));
0259 previousIsOpt = true;
0260 } else if (argv[i][0] == '-') {
0261 const unsigned len = strlen(argv[i]);
0262 for (unsigned k = 1; k < len; ++k) {
0263 std::string dummy("-");
0264 dummy += argv[i][k];
0265 args_.push_back(Pair(dummy, 1));
0266 previousIsOpt = true;
0267 }
0268 } else {
0269 args_.push_back(Pair(argv[i], previousIsOpt ? 0 : 3));
0270 previousIsOpt = false;
0271 ++nprogargs_;
0272 }
0273 }
0274 }
0275
0276 inline const char* progname() const { return progname_.c_str(); }
0277
0278 inline bool has(const char* shortOpt, const char* longOpt = nullptr) {
0279 bool found = false;
0280 for (Optlist::iterator it = find(shortOpt, longOpt); it != args_.end(); it = find(shortOpt, longOpt)) {
0281 found = true;
0282 Optlist::iterator it0(it);
0283 if (++it != args_.end())
0284 if (it->second == 0)
0285 it->second = 3;
0286 args_.erase(it0);
0287 }
0288 return found;
0289 }
0290
0291 inline OneShotIStream option(const char* shortOpt, const char* longOpt = nullptr) {
0292 OneShotIStream result;
0293 for (Optlist::iterator it = find(shortOpt, longOpt); it != args_.end(); it = find(shortOpt, longOpt)) {
0294 Optlist::iterator it0(it);
0295 if (++it != args_.end())
0296 if (it->second == 0) {
0297 result = OneShotIStream(it->first);
0298 args_.erase(it0, ++it);
0299 --nprogargs_;
0300 continue;
0301 }
0302 throw CmdLineError() << "missing command line argument for option \"" << it0->first << '"';
0303 }
0304 return result;
0305 }
0306
0307 inline OneShotIStream require(const char* shortOpt, const char* longOpt = nullptr) {
0308 const OneShotIStream& is(option(shortOpt, longOpt));
0309 if (!is.isValid()) {
0310 const char empty[] = "";
0311 const char* s = shortOpt ? shortOpt : (longOpt ? longOpt : empty);
0312 throw CmdLineError() << "required command line option \"" << s << "\" is missing";
0313 }
0314 return is;
0315 }
0316
0317 inline void optend() const {
0318 for (Optlist::const_iterator it = args_.begin(); it != args_.end(); ++it)
0319 if (it->second == 1 || it->second == 2)
0320 throw CmdLineError("invalid command line option \"") << it->first << '"';
0321 }
0322
0323 inline operator void*() const { return (void*)(static_cast<unsigned long>(nprogargs_)); }
0324
0325 inline unsigned argc() const { return nprogargs_; }
0326
0327 template <typename T>
0328 inline CmdLine& operator>>(T& obj) {
0329 if (!nprogargs_)
0330 throw CmdLineError("no more input available on the command line");
0331 Optlist::iterator it = args_.begin();
0332 for (; it != args_.end(); ++it)
0333 if (it->second == 0 || it->second == 3)
0334 break;
0335 OneShotIStream is(it->first);
0336 args_.erase(it);
0337 --nprogargs_;
0338 is >> obj;
0339 return *this;
0340 }
0341
0342 private:
0343 CmdLine() = delete;
0344
0345 std::string progname_;
0346 Optlist args_;
0347 unsigned nprogargs_;
0348 };
0349
0350 }
0351
0352 #endif