1 /***** This code was generated by Yaggo. Do not edit ******/ 2 3 #ifndef __EXTRACT_CMDLINE_HPP__ 4 #define __EXTRACT_CMDLINE_HPP__ 5 6 #include <stdint.h> 7 #include <unistd.h> 8 #include <stdlib.h> 9 #include <getopt.h> 10 #include <errno.h> 11 #include <string.h> 12 #include <stdexcept> 13 #include <string> 14 #include <limits> 15 #include <vector> 16 #include <iostream> 17 #include <sstream> 18 #include <memory> 19 20 class extract_cmdline { 21 // Boiler plate stuff. Conversion from string to other formats adjust_double_si_suffix(double & res,const char * suffix)22 static bool adjust_double_si_suffix(double &res, const char *suffix) { 23 if(*suffix == '\0') 24 return true; 25 if(*(suffix + 1) != '\0') 26 return false; 27 28 switch(*suffix) { 29 case 'a': res *= 1e-18; break; 30 case 'f': res *= 1e-15; break; 31 case 'p': res *= 1e-12; break; 32 case 'n': res *= 1e-9; break; 33 case 'u': res *= 1e-6; break; 34 case 'm': res *= 1e-3; break; 35 case 'k': res *= 1e3; break; 36 case 'M': res *= 1e6; break; 37 case 'G': res *= 1e9; break; 38 case 'T': res *= 1e12; break; 39 case 'P': res *= 1e15; break; 40 case 'E': res *= 1e18; break; 41 default: return false; 42 } 43 return true; 44 } 45 conv_double(const char * str,::std::string & err,bool si_suffix)46 static double conv_double(const char *str, ::std::string &err, bool si_suffix) { 47 char *endptr = 0; 48 errno = 0; 49 double res = strtod(str, &endptr); 50 if(errno) { 51 err.assign(strerror(errno)); 52 return (double)0.0; 53 } 54 bool invalid = 55 si_suffix ? !adjust_double_si_suffix(res, endptr) : *endptr != '\0'; 56 if(invalid) { 57 err.assign("Invalid character"); 58 return (double)0.0; 59 } 60 return res; 61 } 62 conv_enum(const char * str,::std::string & err,const char * const strs[])63 static int conv_enum(const char* str, ::std::string& err, const char* const strs[]) { 64 int res = 0; 65 for(const char* const* cstr = strs; *cstr; ++cstr, ++res) 66 if(!strcmp(*cstr, str)) 67 return res; 68 err += "Invalid constant '"; 69 err += str; 70 err += "'. Expected one of { "; 71 for(const char* const* cstr = strs; *cstr; ++cstr) { 72 if(cstr != strs) 73 err += ", "; 74 err += *cstr; 75 } 76 err += " }"; 77 return -1; 78 } 79 80 template<typename T> adjust_int_si_suffix(T & res,const char * suffix)81 static bool adjust_int_si_suffix(T &res, const char *suffix) { 82 if(*suffix == '\0') 83 return true; 84 if(*(suffix + 1) != '\0') 85 return false; 86 87 switch(*suffix) { 88 case 'k': res *= (T)1000; break; 89 case 'M': res *= (T)1000000; break; 90 case 'G': res *= (T)1000000000; break; 91 case 'T': res *= (T)1000000000000; break; 92 case 'P': res *= (T)1000000000000000; break; 93 case 'E': res *= (T)1000000000000000000; break; 94 default: return false; 95 } 96 return true; 97 } 98 99 template<typename T> conv_int(const char * str,::std::string & err,bool si_suffix)100 static T conv_int(const char *str, ::std::string &err, bool si_suffix) { 101 char *endptr = 0; 102 errno = 0; 103 long long int res = strtoll(str, &endptr, 0); 104 if(errno) { 105 err.assign(strerror(errno)); 106 return (T)0; 107 } 108 bool invalid = 109 si_suffix ? !adjust_int_si_suffix(res, endptr) : *endptr != '\0'; 110 if(invalid) { 111 err.assign("Invalid character"); 112 return (T)0; 113 } 114 if(res > ::std::numeric_limits<T>::max() || 115 res < ::std::numeric_limits<T>::min()) { 116 err.assign("Value out of range"); 117 return (T)0; 118 } 119 return (T)res; 120 } 121 122 template<typename T> conv_uint(const char * str,::std::string & err,bool si_suffix)123 static T conv_uint(const char *str, ::std::string &err, bool si_suffix) { 124 char *endptr = 0; 125 errno = 0; 126 while(isspace(*str)) { ++str; } 127 if(*str == '-') { 128 err.assign("Negative value"); 129 return (T)0; 130 } 131 unsigned long long int res = strtoull(str, &endptr, 0); 132 if(errno) { 133 err.assign(strerror(errno)); 134 return (T)0; 135 } 136 bool invalid = 137 si_suffix ? !adjust_int_si_suffix(res, endptr) : *endptr != '\0'; 138 if(invalid) { 139 err.assign("Invalid character"); 140 return (T)0; 141 } 142 if(res > ::std::numeric_limits<T>::max()) { 143 err.assign("Value out of range"); 144 return (T)0; 145 } 146 return (T)res; 147 } 148 149 template<typename T> vec_str(const std::vector<T> & vec)150 static ::std::string vec_str(const std::vector<T> &vec) { 151 ::std::ostringstream os; 152 for(typename ::std::vector<T>::const_iterator it = vec.begin(); 153 it != vec.end(); ++it) { 154 if(it != vec.begin()) 155 os << ","; 156 os << *it; 157 } 158 return os.str(); 159 } 160 161 class string : public ::std::string { 162 public: string()163 string() : ::std::string() {} string(const::std::string & s)164 explicit string(const ::std::string &s) : std::string(s) {} string(const char * s)165 explicit string(const char *s) : ::std::string(s) {} as_enum(const char * const strs[])166 int as_enum(const char* const strs[]) { 167 ::std::string err; 168 int res = conv_enum((const char*)this->c_str(), err, strs); 169 if(!err.empty()) 170 throw ::std::runtime_error(err); 171 return res; 172 } 173 174 as_uint32_suffix() const175 uint32_t as_uint32_suffix() const { return as_uint32(true); } as_uint32(bool si_suffix=false) const176 uint32_t as_uint32(bool si_suffix = false) const { 177 ::std::string err; 178 uint32_t res = conv_uint<uint32_t>((const char*)this->c_str(), err, si_suffix); 179 if(!err.empty()) { 180 ::std::string msg("Invalid conversion of '"); 181 msg += *this; 182 msg += "' to uint32_t: "; 183 msg += err; 184 throw ::std::runtime_error(msg); 185 } 186 return res; 187 } as_uint64_suffix() const188 uint64_t as_uint64_suffix() const { return as_uint64(true); } as_uint64(bool si_suffix=false) const189 uint64_t as_uint64(bool si_suffix = false) const { 190 ::std::string err; 191 uint64_t res = conv_uint<uint64_t>((const char*)this->c_str(), err, si_suffix); 192 if(!err.empty()) { 193 ::std::string msg("Invalid conversion of '"); 194 msg += *this; 195 msg += "' to uint64_t: "; 196 msg += err; 197 throw ::std::runtime_error(msg); 198 } 199 return res; 200 } as_int32_suffix() const201 int32_t as_int32_suffix() const { return as_int32(true); } as_int32(bool si_suffix=false) const202 int32_t as_int32(bool si_suffix = false) const { 203 ::std::string err; 204 int32_t res = conv_int<int32_t>((const char*)this->c_str(), err, si_suffix); 205 if(!err.empty()) { 206 ::std::string msg("Invalid conversion of '"); 207 msg += *this; 208 msg += "' to int32_t: "; 209 msg += err; 210 throw ::std::runtime_error(msg); 211 } 212 return res; 213 } as_int64_suffix() const214 int64_t as_int64_suffix() const { return as_int64(true); } as_int64(bool si_suffix=false) const215 int64_t as_int64(bool si_suffix = false) const { 216 ::std::string err; 217 int64_t res = conv_int<int64_t>((const char*)this->c_str(), err, si_suffix); 218 if(!err.empty()) { 219 ::std::string msg("Invalid conversion of '"); 220 msg += *this; 221 msg += "' to int64_t: "; 222 msg += err; 223 throw ::std::runtime_error(msg); 224 } 225 return res; 226 } as_int_suffix() const227 int as_int_suffix() const { return as_int(true); } as_int(bool si_suffix=false) const228 int as_int(bool si_suffix = false) const { 229 ::std::string err; 230 int res = conv_int<int>((const char*)this->c_str(), err, si_suffix); 231 if(!err.empty()) { 232 ::std::string msg("Invalid conversion of '"); 233 msg += *this; 234 msg += "' to int_t: "; 235 msg += err; 236 throw ::std::runtime_error(msg); 237 } 238 return res; 239 } as_long_suffix() const240 long as_long_suffix() const { return as_long(true); } as_long(bool si_suffix=false) const241 long as_long(bool si_suffix = false) const { 242 ::std::string err; 243 long res = conv_int<long>((const char*)this->c_str(), err, si_suffix); 244 if(!err.empty()) { 245 ::std::string msg("Invalid conversion of '"); 246 msg += *this; 247 msg += "' to long_t: "; 248 msg += err; 249 throw ::std::runtime_error(msg); 250 } 251 return res; 252 } as_double_suffix() const253 double as_double_suffix() const { return as_double(true); } as_double(bool si_suffix=false) const254 double as_double(bool si_suffix = false) const { 255 ::std::string err; 256 double res = conv_double((const char*)this->c_str(), err, si_suffix); 257 if(!err.empty()) { 258 ::std::string msg("Invalid conversion of '"); 259 msg += *this; 260 msg += "' to double_t: "; 261 msg += err; 262 throw ::std::runtime_error(msg); 263 } 264 return res; 265 } 266 }; 267 268 public: 269 bool invert_match_flag; 270 ::std::vector<string> name_arg; 271 typedef ::std::vector<string>::iterator name_arg_it; 272 typedef ::std::vector<string>::const_iterator name_arg_const_it; 273 bool name_given; 274 ::std::vector<const char *> name_file_arg; 275 typedef ::std::vector<const char *>::iterator name_file_arg_it; 276 typedef ::std::vector<const char *>::const_iterator name_file_arg_const_it; 277 bool name_file_given; 278 double probabilistic_arg; 279 bool probabilistic_given; 280 uint64_t max_count_arg; 281 bool max_count_given; 282 uint64_t start_arg; 283 bool start_given; 284 uint64_t end_arg; 285 bool end_given; 286 ::std::vector<const char *> file_arg; 287 typedef ::std::vector<const char *>::iterator file_arg_it; 288 typedef ::std::vector<const char *>::const_iterator file_arg_const_it; 289 290 enum { 291 START_OPT = 1000 292 }; 293 extract_cmdline()294 extract_cmdline() : 295 invert_match_flag(false), 296 name_arg(), name_given(false), 297 name_file_arg(), name_file_given(false), 298 probabilistic_arg(0.0), probabilistic_given(false), 299 max_count_arg(0), max_count_given(false), 300 start_arg(0), start_given(false), 301 end_arg(0), end_given(false), 302 file_arg() 303 { } 304 extract_cmdline(int argc,char * argv[])305 extract_cmdline(int argc, char* argv[]) : 306 invert_match_flag(false), 307 name_arg(), name_given(false), 308 name_file_arg(), name_file_given(false), 309 probabilistic_arg(0.0), probabilistic_given(false), 310 max_count_arg(0), max_count_given(false), 311 start_arg(0), start_given(false), 312 end_arg(0), end_given(false), 313 file_arg() 314 { parse(argc, argv); } 315 parse(int argc,char * argv[])316 void parse(int argc, char* argv[]) { 317 static struct option long_options[] = { 318 {"invert-match", 0, 0, 'v'}, 319 {"name", 1, 0, 'n'}, 320 {"name-file", 1, 0, 'f'}, 321 {"probabilistic", 1, 0, 'p'}, 322 {"max-count", 1, 0, 'm'}, 323 {"start", 1, 0, 's'}, 324 {"end", 1, 0, 'e'}, 325 {"help", 0, 0, 'h'}, 326 {"usage", 0, 0, 'U'}, 327 {"version", 0, 0, 'V'}, 328 {0, 0, 0, 0} 329 }; 330 static const char *short_options = "hVUvn:f:p:m:s:e:"; 331 332 ::std::string err; 333 #define CHECK_ERR(type,val,which) if(!err.empty()) { ::std::cerr << "Invalid " #type " '" << val << "' for [" which "]: " << err << "\n"; exit(1); } 334 while(true) { 335 int index = -1; 336 int c = getopt_long(argc, argv, short_options, long_options, &index); 337 if(c == -1) break; 338 switch(c) { 339 case ':': 340 ::std::cerr << "Missing required argument for " 341 << (index == -1 ? ::std::string(1, (char)optopt) : std::string(long_options[index].name)) 342 << ::std::endl; 343 exit(1); 344 case 'h': 345 ::std::cout << usage() << "\n\n" << help() << std::endl; 346 exit(0); 347 case 'U': 348 ::std::cout << usage() << "\nUse --help for more information." << std::endl; 349 exit(0); 350 case 'V': 351 print_version(); 352 exit(0); 353 case '?': 354 ::std::cerr << "Use --usage or --help for some help\n"; 355 exit(1); 356 case 'v': 357 invert_match_flag = true; 358 break; 359 case 'n': 360 name_given = true; 361 name_arg.push_back(string(optarg)); 362 break; 363 case 'f': 364 name_file_given = true; 365 name_file_arg.push_back(optarg); 366 break; 367 case 'p': 368 probabilistic_given = true; 369 probabilistic_arg = conv_double((const char*)optarg, err, false); 370 CHECK_ERR(double_t, optarg, "-p, --probabilistic=PROBA") 371 break; 372 case 'm': 373 max_count_given = true; 374 max_count_arg = conv_uint<uint64_t>((const char*)optarg, err, false); 375 CHECK_ERR(uint64_t, optarg, "-m, --max-count=NUM") 376 break; 377 case 's': 378 start_given = true; 379 start_arg = conv_uint<uint64_t>((const char*)optarg, err, false); 380 CHECK_ERR(uint64_t, optarg, "-s, --start=NUM") 381 break; 382 case 'e': 383 end_given = true; 384 end_arg = conv_uint<uint64_t>((const char*)optarg, err, false); 385 CHECK_ERR(uint64_t, optarg, "-e, --end=NUM") 386 break; 387 } 388 } 389 390 // Parse arguments 391 if(argc - optind < 0) 392 error("Requires at least 0 argument."); 393 for( ; optind < argc; ++optind) { 394 file_arg.push_back(argv[optind]); 395 } 396 } usage()397 static const char * usage() { return "Usage: extract_cmdline [options] file:string+"; } 398 class error { 399 int code_; 400 std::ostringstream msg_; 401 402 // Select the correct version (GNU or XSI) version of 403 // strerror_r. strerror_ behaves like the GNU version of strerror_r, 404 // regardless of which version is provided by the system. strerror__(char * buf,int res)405 static const char* strerror__(char* buf, int res) { 406 return res != -1 ? buf : "Invalid error"; 407 } strerror__(char * buf,char * res)408 static const char* strerror__(char* buf, char* res) { 409 return res; 410 } strerror_(int err,char * buf,size_t buflen)411 static const char* strerror_(int err, char* buf, size_t buflen) { 412 return strerror__(buf, strerror_r(err, buf, buflen)); 413 } 414 struct no_t { }; 415 416 public: 417 static no_t no; error(int code=EXIT_FAILURE)418 error(int code = EXIT_FAILURE) : code_(code) { } error(const char * msg,int code=EXIT_FAILURE)419 explicit error(const char* msg, int code = EXIT_FAILURE) : code_(code) 420 { msg_ << msg; } error(const std::string & msg,int code=EXIT_FAILURE)421 error(const std::string& msg, int code = EXIT_FAILURE) : code_(code) 422 { msg_ << msg; } operator <<(no_t)423 error& operator<<(no_t) { 424 char buf[1024]; 425 msg_ << ": " << strerror_(errno, buf, sizeof(buf)); 426 return *this; 427 } 428 template<typename T> operator <<(const T & x)429 error& operator<<(const T& x) { msg_ << x; return (*this); } ~error()430 ~error() { 431 ::std::cerr << "Error: " << msg_.str() << "\n" 432 << usage() << "\n" 433 << "Use --help for more information" 434 << ::std::endl; 435 exit(code_); 436 } 437 }; help()438 static const char * help() { return 439 "Match a header and output the content.\n\n" 440 "Options (default value in (), *required):\n" 441 " -v, --invert-match Invert the sense of matching, to select non-matching headers (false)\n" 442 " -n, --name=NAME Extract read with NAME, exact match\n" 443 " -f, --name-file=path File of read names to extract\n" 444 " -p, --probabilistic=PROBA Select sequences with probability PROBA\n" 445 " -m, --max-count=NUM Stop reading after NUM matching headers\n" 446 " -s, --start=NUM Output content starting at byte NUM, 0-based\n" 447 " -e, --end=NUM Output content up to byte NUM\n" 448 " -U, --usage Usage\n" 449 " -h, --help This message\n" 450 " -V, --version Version"; 451 } hidden()452 static const char* hidden() { return ""; } print_version(::std::ostream & os=std::cout) const453 void print_version(::std::ostream &os = std::cout) const { 454 #ifndef PACKAGE_VERSION 455 #define PACKAGE_VERSION "0.0.0" 456 #endif 457 os << PACKAGE_VERSION << "\n"; 458 } dump(::std::ostream & os=std::cout)459 void dump(::std::ostream &os = std::cout) { 460 os << "invert_match_flag:" << invert_match_flag << "\n"; 461 os << "name_given:" << name_given << " name_arg:" << vec_str(name_arg) << "\n"; 462 os << "name_file_given:" << name_file_given << " name_file_arg:" << vec_str(name_file_arg) << "\n"; 463 os << "probabilistic_given:" << probabilistic_given << " probabilistic_arg:" << probabilistic_arg << "\n"; 464 os << "max_count_given:" << max_count_given << " max_count_arg:" << max_count_arg << "\n"; 465 os << "start_given:" << start_given << " start_arg:" << start_arg << "\n"; 466 os << "end_given:" << end_given << " end_arg:" << end_arg << "\n"; 467 os << "file_arg:" << vec_str(file_arg) << "\n"; 468 } 469 }; 470 #endif // __EXTRACT_CMDLINE_HPP__" 471