1 /***** This code was generated by Yaggo. Do not edit ******/ 2 3 /* Quorum 4 * Copyright (C) 2012 Genome group at University of Maryland. 5 * 6 * This program is free software: you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation, either version 3 of the 9 * License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 21 22 #ifndef __CMDLINE_HPP__ 23 #define __CMDLINE_HPP__ 24 25 #include <stdint.h> 26 #include <unistd.h> 27 #include <stdlib.h> 28 #include <getopt.h> 29 #include <errno.h> 30 #include <string.h> 31 #include <stdexcept> 32 #include <string> 33 #include <limits> 34 #include <vector> 35 #include <iostream> 36 #include <sstream> 37 #include <memory> 38 39 class cmdline { 40 // Boiler plate stuff. Conversion from string to other formats adjust_double_si_suffix(double & res,const char * suffix)41 static bool adjust_double_si_suffix(double &res, const char *suffix) { 42 if(*suffix == '\0') 43 return true; 44 if(*(suffix + 1) != '\0') 45 return false; 46 47 switch(*suffix) { 48 case 'a': res *= 1e-18; break; 49 case 'f': res *= 1e-15; break; 50 case 'p': res *= 1e-12; break; 51 case 'n': res *= 1e-9; break; 52 case 'u': res *= 1e-6; break; 53 case 'm': res *= 1e-3; break; 54 case 'k': res *= 1e3; break; 55 case 'M': res *= 1e6; break; 56 case 'G': res *= 1e9; break; 57 case 'T': res *= 1e12; break; 58 case 'P': res *= 1e15; break; 59 case 'E': res *= 1e18; break; 60 default: return false; 61 } 62 return true; 63 } 64 conv_double(const char * str,::std::string & err,bool si_suffix)65 static double conv_double(const char *str, ::std::string &err, bool si_suffix) { 66 char *endptr = 0; 67 errno = 0; 68 double res = strtod(str, &endptr); 69 if(errno) { 70 err.assign(strerror(errno)); 71 return (double)0.0; 72 } 73 bool invalid = 74 si_suffix ? !adjust_double_si_suffix(res, endptr) : *endptr != '\0'; 75 if(invalid) { 76 err.assign("Invalid character"); 77 return (double)0.0; 78 } 79 return res; 80 } 81 conv_enum(const char * str,::std::string & err,const char * const strs[])82 static int conv_enum(const char* str, ::std::string& err, const char* const strs[]) { 83 int res = 0; 84 for(const char* const* cstr = strs; *cstr; ++cstr, ++res) 85 if(!strcmp(*cstr, str)) 86 return res; 87 err += "Invalid constant '"; 88 err += str; 89 err += "'. Expected one of { "; 90 for(const char* const* cstr = strs; *cstr; ++cstr) { 91 if(cstr != strs) 92 err += ", "; 93 err += *cstr; 94 } 95 err += " }"; 96 return -1; 97 } 98 99 template<typename T> adjust_int_si_suffix(T & res,const char * suffix)100 static bool adjust_int_si_suffix(T &res, const char *suffix) { 101 if(*suffix == '\0') 102 return true; 103 if(*(suffix + 1) != '\0') 104 return false; 105 106 switch(*suffix) { 107 case 'k': res *= (T)1000; break; 108 case 'M': res *= (T)1000000; break; 109 case 'G': res *= (T)1000000000; break; 110 case 'T': res *= (T)1000000000000; break; 111 case 'P': res *= (T)1000000000000000; break; 112 case 'E': res *= (T)1000000000000000000; break; 113 default: return false; 114 } 115 return true; 116 } 117 118 template<typename T> conv_int(const char * str,::std::string & err,bool si_suffix)119 static T conv_int(const char *str, ::std::string &err, bool si_suffix) { 120 char *endptr = 0; 121 errno = 0; 122 long long int res = strtoll(str, &endptr, 0); 123 if(errno) { 124 err.assign(strerror(errno)); 125 return (T)0; 126 } 127 bool invalid = 128 si_suffix ? !adjust_int_si_suffix(res, endptr) : *endptr != '\0'; 129 if(invalid) { 130 err.assign("Invalid character"); 131 return (T)0; 132 } 133 if(res > ::std::numeric_limits<T>::max() || 134 res < ::std::numeric_limits<T>::min()) { 135 err.assign("Value out of range"); 136 return (T)0; 137 } 138 return (T)res; 139 } 140 141 template<typename T> conv_uint(const char * str,::std::string & err,bool si_suffix)142 static T conv_uint(const char *str, ::std::string &err, bool si_suffix) { 143 char *endptr = 0; 144 errno = 0; 145 while(isspace(*str)) { ++str; } 146 if(*str == '-') { 147 err.assign("Negative value"); 148 return (T)0; 149 } 150 unsigned long long int res = strtoull(str, &endptr, 0); 151 if(errno) { 152 err.assign(strerror(errno)); 153 return (T)0; 154 } 155 bool invalid = 156 si_suffix ? !adjust_int_si_suffix(res, endptr) : *endptr != '\0'; 157 if(invalid) { 158 err.assign("Invalid character"); 159 return (T)0; 160 } 161 if(res > ::std::numeric_limits<T>::max()) { 162 err.assign("Value out of range"); 163 return (T)0; 164 } 165 return (T)res; 166 } 167 168 template<typename T> vec_str(const std::vector<T> & vec)169 static ::std::string vec_str(const std::vector<T> &vec) { 170 ::std::ostringstream os; 171 for(typename ::std::vector<T>::const_iterator it = vec.begin(); 172 it != vec.end(); ++it) { 173 if(it != vec.begin()) 174 os << ","; 175 os << *it; 176 } 177 return os.str(); 178 } 179 180 class string : public ::std::string { 181 public: string()182 string() : ::std::string() {} string(const::std::string & s)183 explicit string(const ::std::string &s) : std::string(s) {} string(const char * s)184 explicit string(const char *s) : ::std::string(s) {} as_enum(const char * const strs[])185 int as_enum(const char* const strs[]) { 186 ::std::string err; 187 int res = conv_enum((const char*)this->c_str(), err, strs); 188 if(!err.empty()) 189 throw ::std::runtime_error(err); 190 return res; 191 } 192 193 as_uint32_suffix() const194 uint32_t as_uint32_suffix() const { return as_uint32(true); } as_uint32(bool si_suffix=false) const195 uint32_t as_uint32(bool si_suffix = false) const { 196 ::std::string err; 197 uint32_t res = conv_uint<uint32_t>((const char*)this->c_str(), err, si_suffix); 198 if(!err.empty()) { 199 ::std::string msg("Invalid conversion of '"); 200 msg += *this; 201 msg += "' to uint32_t: "; 202 msg += err; 203 throw ::std::runtime_error(msg); 204 } 205 return res; 206 } as_uint64_suffix() const207 uint64_t as_uint64_suffix() const { return as_uint64(true); } as_uint64(bool si_suffix=false) const208 uint64_t as_uint64(bool si_suffix = false) const { 209 ::std::string err; 210 uint64_t res = conv_uint<uint64_t>((const char*)this->c_str(), err, si_suffix); 211 if(!err.empty()) { 212 ::std::string msg("Invalid conversion of '"); 213 msg += *this; 214 msg += "' to uint64_t: "; 215 msg += err; 216 throw ::std::runtime_error(msg); 217 } 218 return res; 219 } as_int32_suffix() const220 int32_t as_int32_suffix() const { return as_int32(true); } as_int32(bool si_suffix=false) const221 int32_t as_int32(bool si_suffix = false) const { 222 ::std::string err; 223 int32_t res = conv_int<int32_t>((const char*)this->c_str(), err, si_suffix); 224 if(!err.empty()) { 225 ::std::string msg("Invalid conversion of '"); 226 msg += *this; 227 msg += "' to int32_t: "; 228 msg += err; 229 throw ::std::runtime_error(msg); 230 } 231 return res; 232 } as_int64_suffix() const233 int64_t as_int64_suffix() const { return as_int64(true); } as_int64(bool si_suffix=false) const234 int64_t as_int64(bool si_suffix = false) const { 235 ::std::string err; 236 int64_t res = conv_int<int64_t>((const char*)this->c_str(), err, si_suffix); 237 if(!err.empty()) { 238 ::std::string msg("Invalid conversion of '"); 239 msg += *this; 240 msg += "' to int64_t: "; 241 msg += err; 242 throw ::std::runtime_error(msg); 243 } 244 return res; 245 } as_int_suffix() const246 int as_int_suffix() const { return as_int(true); } as_int(bool si_suffix=false) const247 int as_int(bool si_suffix = false) const { 248 ::std::string err; 249 int res = conv_int<int>((const char*)this->c_str(), err, si_suffix); 250 if(!err.empty()) { 251 ::std::string msg("Invalid conversion of '"); 252 msg += *this; 253 msg += "' to int_t: "; 254 msg += err; 255 throw ::std::runtime_error(msg); 256 } 257 return res; 258 } as_long_suffix() const259 long as_long_suffix() const { return as_long(true); } as_long(bool si_suffix=false) const260 long as_long(bool si_suffix = false) const { 261 ::std::string err; 262 long res = conv_int<long>((const char*)this->c_str(), err, si_suffix); 263 if(!err.empty()) { 264 ::std::string msg("Invalid conversion of '"); 265 msg += *this; 266 msg += "' to long_t: "; 267 msg += err; 268 throw ::std::runtime_error(msg); 269 } 270 return res; 271 } as_double_suffix() const272 double as_double_suffix() const { return as_double(true); } as_double(bool si_suffix=false) const273 double as_double(bool si_suffix = false) const { 274 ::std::string err; 275 double res = conv_double((const char*)this->c_str(), err, si_suffix); 276 if(!err.empty()) { 277 ::std::string msg("Invalid conversion of '"); 278 msg += *this; 279 msg += "' to double_t: "; 280 msg += err; 281 throw ::std::runtime_error(msg); 282 } 283 return res; 284 } 285 }; 286 287 public: 288 ::std::vector<const char *> file_arg; 289 typedef ::std::vector<const char *>::iterator file_arg_it; 290 typedef ::std::vector<const char *>::const_iterator file_arg_const_it; 291 292 enum { 293 START_OPT = 1000 294 }; 295 cmdline()296 cmdline() : 297 file_arg() 298 { } 299 cmdline(int argc,char * argv[])300 cmdline(int argc, char* argv[]) : 301 file_arg() 302 { parse(argc, argv); } 303 parse(int argc,char * argv[])304 void parse(int argc, char* argv[]) { 305 static struct option long_options[] = { 306 {"help", 0, 0, 'h'}, 307 {"usage", 0, 0, 'U'}, 308 {"version", 0, 0, 'V'}, 309 {0, 0, 0, 0} 310 }; 311 static const char *short_options = "hVU"; 312 313 #define CHECK_ERR(type,val,which) if(!err.empty()) { ::std::cerr << "Invalid " #type " '" << val << "' for [" which "]: " << err << "\n"; exit(1); } 314 while(true) { 315 int index = -1; 316 int c = getopt_long(argc, argv, short_options, long_options, &index); 317 if(c == -1) break; 318 switch(c) { 319 case ':': 320 ::std::cerr << "Missing required argument for " 321 << (index == -1 ? ::std::string(1, (char)optopt) : std::string(long_options[index].name)) 322 << ::std::endl; 323 exit(1); 324 case 'h': 325 ::std::cout << usage() << "\n\n" << help() << std::endl; 326 exit(0); 327 case 'U': 328 ::std::cout << usage() << "\nUse --help for more information." << std::endl; 329 exit(0); 330 case 'V': 331 print_version(); 332 exit(0); 333 case '?': 334 ::std::cerr << "Use --usage or --help for some help\n"; 335 exit(1); 336 } 337 } 338 339 // Parse arguments 340 if(argc - optind < 2) 341 error("Requires at least 2 arguments."); 342 for( ; optind < argc; ++optind) { 343 file_arg.push_back(argv[optind]); 344 } 345 } usage()346 static const char * usage() { return "Merge input files"; } 347 class error { 348 int code_; 349 std::ostringstream msg_; 350 351 // Select the correct version (GNU or XSI) version of 352 // strerror_r. strerror_ behaves like the GNU version of strerror_r, 353 // regardless of which version is provided by the system. strerror__(char * buf,int res)354 static const char* strerror__(char* buf, int res) { 355 return res != -1 ? buf : "Invalid error"; 356 } strerror__(char * buf,char * res)357 static const char* strerror__(char* buf, char* res) { 358 return res; 359 } strerror_(int err,char * buf,size_t buflen)360 static const char* strerror_(int err, char* buf, size_t buflen) { 361 return strerror__(buf, strerror_r(err, buf, buflen)); 362 } 363 struct no_t { }; 364 365 public: 366 static no_t no; error(int code=EXIT_FAILURE)367 error(int code = EXIT_FAILURE) : code_(code) { } error(const char * msg,int code=EXIT_FAILURE)368 explicit error(const char* msg, int code = EXIT_FAILURE) : code_(code) 369 { msg_ << msg; } error(const std::string & msg,int code=EXIT_FAILURE)370 error(const std::string& msg, int code = EXIT_FAILURE) : code_(code) 371 { msg_ << msg; } operator <<(no_t)372 error& operator<<(no_t) { 373 char buf[1024]; 374 msg_ << ": " << strerror_(errno, buf, sizeof(buf)); 375 return *this; 376 } 377 template<typename T> operator <<(const T & x)378 error& operator<<(const T& x) { msg_ << x; return (*this); } ~error()379 ~error() { 380 ::std::cerr << "Error: " << msg_.str() << "\n" 381 << usage() << "\n" 382 << "Use --help for more information" 383 << ::std::endl; 384 exit(code_); 385 } 386 }; help()387 static const char * help() { return 388 "Take an even number of files and interleave sequences from even and odd files.\n\n" 389 "Options (default value in (), *required):\n" 390 " -U, --usage Usage\n" 391 " -h, --help This message\n" 392 " -V, --version Version"; 393 } hidden()394 static const char* hidden() { return ""; } print_version(::std::ostream & os=std::cout) const395 void print_version(::std::ostream &os = std::cout) const { 396 #ifndef PACKAGE_VERSION 397 #define PACKAGE_VERSION "0.0.0" 398 #endif 399 os << PACKAGE_VERSION << "\n"; 400 } dump(::std::ostream & os=std::cout)401 void dump(::std::ostream &os = std::cout) { 402 os << "file_arg:" << vec_str(file_arg) << "\n"; 403 } 404 }; 405 #endif // __CMDLINE_HPP__" 406