1 /***** This code was generated by Yaggo. Do not edit ******/ 2 3 /* This file is part of Jellyfish. 4 5 This work is dual-licensed under 3-Clause BSD License or GPL 3.0. 6 You can choose between one of them if you use this work. 7 8 `SPDX-License-Identifier: BSD-3-Clause OR GPL-3.0` 9 */ 10 11 #ifndef __HISTO_MAIN_CMDLINE_HPP__ 12 #define __HISTO_MAIN_CMDLINE_HPP__ 13 14 #include <stdint.h> 15 #include <unistd.h> 16 #include <stdlib.h> 17 #include <getopt.h> 18 #include <errno.h> 19 #include <string.h> 20 #include <stdexcept> 21 #include <string> 22 #include <limits> 23 #include <vector> 24 #include <iostream> 25 #include <sstream> 26 #include <memory> 27 28 class histo_main_cmdline { 29 // Boiler plate stuff. Conversion from string to other formats adjust_double_si_suffix(double & res,const char * suffix)30 static bool adjust_double_si_suffix(double &res, const char *suffix) { 31 if(*suffix == '\0') 32 return true; 33 if(*(suffix + 1) != '\0') 34 return false; 35 36 switch(*suffix) { 37 case 'a': res *= 1e-18; break; 38 case 'f': res *= 1e-15; break; 39 case 'p': res *= 1e-12; break; 40 case 'n': res *= 1e-9; break; 41 case 'u': res *= 1e-6; break; 42 case 'm': res *= 1e-3; break; 43 case 'k': res *= 1e3; break; 44 case 'M': res *= 1e6; break; 45 case 'G': res *= 1e9; break; 46 case 'T': res *= 1e12; break; 47 case 'P': res *= 1e15; break; 48 case 'E': res *= 1e18; break; 49 default: return false; 50 } 51 return true; 52 } 53 conv_double(const char * str,::std::string & err,bool si_suffix)54 static double conv_double(const char *str, ::std::string &err, bool si_suffix) { 55 char *endptr = 0; 56 errno = 0; 57 double res = strtod(str, &endptr); 58 if(endptr == str) { 59 err.assign("Invalid floating point string"); 60 return (double)0.0; 61 } 62 if(errno) { 63 err.assign(strerror(errno)); 64 return (double)0.0; 65 } 66 bool invalid = 67 si_suffix ? !adjust_double_si_suffix(res, endptr) : *endptr != '\0'; 68 if(invalid) { 69 err.assign("Invalid character"); 70 return (double)0.0; 71 } 72 return res; 73 } 74 conv_enum(const char * str,::std::string & err,const char * const strs[])75 static int conv_enum(const char* str, ::std::string& err, const char* const strs[]) { 76 int res = 0; 77 for(const char* const* cstr = strs; *cstr; ++cstr, ++res) 78 if(!strcmp(*cstr, str)) 79 return res; 80 err += "Invalid constant '"; 81 err += str; 82 err += "'. Expected one of { "; 83 for(const char* const* cstr = strs; *cstr; ++cstr) { 84 if(cstr != strs) 85 err += ", "; 86 err += *cstr; 87 } 88 err += " }"; 89 return -1; 90 } 91 92 template<typename T> adjust_int_si_suffix(T & res,const char * suffix)93 static bool adjust_int_si_suffix(T &res, const char *suffix) { 94 if(*suffix == '\0') 95 return true; 96 if(*(suffix + 1) != '\0') 97 return false; 98 99 switch(*suffix) { 100 case 'k': res *= (T)1000; break; 101 case 'M': res *= (T)1000000; break; 102 case 'G': res *= (T)1000000000; break; 103 case 'T': res *= (T)1000000000000; break; 104 case 'P': res *= (T)1000000000000000; break; 105 case 'E': res *= (T)1000000000000000000; break; 106 default: return false; 107 } 108 return true; 109 } 110 111 template<typename T> conv_int(const char * str,::std::string & err,bool si_suffix)112 static T conv_int(const char *str, ::std::string &err, bool si_suffix) { 113 char *endptr = 0; 114 errno = 0; 115 long long int res = strtoll(str, &endptr, 0); 116 if(endptr == str) { 117 err.assign("Invalid signed int string"); 118 return (T)0; 119 } 120 if(errno) { 121 err.assign(strerror(errno)); 122 return (T)0; 123 } 124 bool invalid = 125 si_suffix ? !adjust_int_si_suffix(res, endptr) : *endptr != '\0'; 126 if(invalid) { 127 err.assign("Invalid character"); 128 return (T)0; 129 } 130 if(res > ::std::numeric_limits<T>::max() || 131 res < ::std::numeric_limits<T>::min()) { 132 err.assign("Value out of range"); 133 return (T)0; 134 } 135 return (T)res; 136 } 137 138 template<typename T> conv_uint(const char * str,::std::string & err,bool si_suffix)139 static T conv_uint(const char *str, ::std::string &err, bool si_suffix) { 140 char *endptr = 0; 141 errno = 0; 142 while(isspace(*str)) { ++str; } 143 if(*str == '-') { 144 err.assign("Negative value"); 145 return (T)0; 146 } 147 unsigned long long int res = strtoull(str, &endptr, 0); 148 if(endptr == str) { 149 err.assign("Invalid unsigned int string"); 150 return (T)0; 151 } 152 if(errno) { 153 err.assign(strerror(errno)); 154 return (T)0; 155 } 156 bool invalid = 157 si_suffix ? !adjust_int_si_suffix(res, endptr) : *endptr != '\0'; 158 if(invalid) { 159 err.assign("Invalid character"); 160 return (T)0; 161 } 162 if(res > ::std::numeric_limits<T>::max()) { 163 err.assign("Value out of range"); 164 return (T)0; 165 } 166 return (T)res; 167 } 168 169 template<typename T> vec_str(const std::vector<T> & vec)170 static ::std::string vec_str(const std::vector<T> &vec) { 171 ::std::ostringstream os; 172 for(typename ::std::vector<T>::const_iterator it = vec.begin(); 173 it != vec.end(); ++it) { 174 if(it != vec.begin()) 175 os << ","; 176 os << *it; 177 } 178 return os.str(); 179 } 180 181 class string : public ::std::string { 182 public: string()183 string() : ::std::string() {} string(const::std::string & s)184 explicit string(const ::std::string &s) : std::string(s) {} string(const char * s)185 explicit string(const char *s) : ::std::string(s) {} as_enum(const char * const strs[])186 int as_enum(const char* const strs[]) { 187 ::std::string err; 188 int res = conv_enum((const char*)this->c_str(), err, strs); 189 if(!err.empty()) 190 throw ::std::runtime_error(err); 191 return res; 192 } 193 194 as_uint32_suffix() const195 uint32_t as_uint32_suffix() const { return as_uint32(true); } as_uint32(bool si_suffix=false) const196 uint32_t as_uint32(bool si_suffix = false) const { 197 ::std::string err; 198 uint32_t res = conv_uint<uint32_t>((const char*)this->c_str(), err, si_suffix); 199 if(!err.empty()) { 200 ::std::string msg("Invalid conversion of '"); 201 msg += *this; 202 msg += "' to uint32_t: "; 203 msg += err; 204 throw ::std::runtime_error(msg); 205 } 206 return res; 207 } as_uint64_suffix() const208 uint64_t as_uint64_suffix() const { return as_uint64(true); } as_uint64(bool si_suffix=false) const209 uint64_t as_uint64(bool si_suffix = false) const { 210 ::std::string err; 211 uint64_t res = conv_uint<uint64_t>((const char*)this->c_str(), err, si_suffix); 212 if(!err.empty()) { 213 ::std::string msg("Invalid conversion of '"); 214 msg += *this; 215 msg += "' to uint64_t: "; 216 msg += err; 217 throw ::std::runtime_error(msg); 218 } 219 return res; 220 } as_int32_suffix() const221 int32_t as_int32_suffix() const { return as_int32(true); } as_int32(bool si_suffix=false) const222 int32_t as_int32(bool si_suffix = false) const { 223 ::std::string err; 224 int32_t res = conv_int<int32_t>((const char*)this->c_str(), err, si_suffix); 225 if(!err.empty()) { 226 ::std::string msg("Invalid conversion of '"); 227 msg += *this; 228 msg += "' to int32_t: "; 229 msg += err; 230 throw ::std::runtime_error(msg); 231 } 232 return res; 233 } as_int64_suffix() const234 int64_t as_int64_suffix() const { return as_int64(true); } as_int64(bool si_suffix=false) const235 int64_t as_int64(bool si_suffix = false) const { 236 ::std::string err; 237 int64_t res = conv_int<int64_t>((const char*)this->c_str(), err, si_suffix); 238 if(!err.empty()) { 239 ::std::string msg("Invalid conversion of '"); 240 msg += *this; 241 msg += "' to int64_t: "; 242 msg += err; 243 throw ::std::runtime_error(msg); 244 } 245 return res; 246 } as_int_suffix() const247 int as_int_suffix() const { return as_int(true); } as_int(bool si_suffix=false) const248 int as_int(bool si_suffix = false) const { 249 ::std::string err; 250 int res = conv_int<int>((const char*)this->c_str(), err, si_suffix); 251 if(!err.empty()) { 252 ::std::string msg("Invalid conversion of '"); 253 msg += *this; 254 msg += "' to int_t: "; 255 msg += err; 256 throw ::std::runtime_error(msg); 257 } 258 return res; 259 } as_long_suffix() const260 long as_long_suffix() const { return as_long(true); } as_long(bool si_suffix=false) const261 long as_long(bool si_suffix = false) const { 262 ::std::string err; 263 long res = conv_int<long>((const char*)this->c_str(), err, si_suffix); 264 if(!err.empty()) { 265 ::std::string msg("Invalid conversion of '"); 266 msg += *this; 267 msg += "' to long_t: "; 268 msg += err; 269 throw ::std::runtime_error(msg); 270 } 271 return res; 272 } as_double_suffix() const273 double as_double_suffix() const { return as_double(true); } as_double(bool si_suffix=false) const274 double as_double(bool si_suffix = false) const { 275 ::std::string err; 276 double res = conv_double((const char*)this->c_str(), err, si_suffix); 277 if(!err.empty()) { 278 ::std::string msg("Invalid conversion of '"); 279 msg += *this; 280 msg += "' to double_t: "; 281 msg += err; 282 throw ::std::runtime_error(msg); 283 } 284 return res; 285 } 286 }; 287 288 public: 289 uint64_t low_arg; 290 bool low_given; 291 uint64_t high_arg; 292 bool high_given; 293 uint64_t increment_arg; 294 bool increment_given; 295 uint32_t threads_arg; 296 bool threads_given; 297 bool full_flag; 298 const char * output_arg; 299 bool output_given; 300 uint64_t buffer_size_arg; 301 bool buffer_size_given; 302 bool verbose_flag; 303 const char * db_arg; 304 305 enum { 306 START_OPT = 1000, 307 FULL_HELP_OPT, 308 HELP_OPT 309 }; 310 histo_main_cmdline()311 histo_main_cmdline() : 312 low_arg((uint64_t)1), low_given(false), 313 high_arg((uint64_t)10000), high_given(false), 314 increment_arg((uint64_t)1), increment_given(false), 315 threads_arg((uint32_t)1), threads_given(false), 316 full_flag(false), 317 output_arg(""), output_given(false), 318 buffer_size_arg((uint64_t)10000000), buffer_size_given(false), 319 verbose_flag(false), 320 db_arg("") 321 { } 322 histo_main_cmdline(int argc,char * argv[])323 histo_main_cmdline(int argc, char* argv[]) : 324 low_arg((uint64_t)1), low_given(false), 325 high_arg((uint64_t)10000), high_given(false), 326 increment_arg((uint64_t)1), increment_given(false), 327 threads_arg((uint32_t)1), threads_given(false), 328 full_flag(false), 329 output_arg(""), output_given(false), 330 buffer_size_arg((uint64_t)10000000), buffer_size_given(false), 331 verbose_flag(false), 332 db_arg("") 333 { parse(argc, argv); } 334 parse(int argc,char * argv[])335 void parse(int argc, char* argv[]) { 336 static struct option long_options[] = { 337 {"low", 1, 0, 'l'}, 338 {"high", 1, 0, 'h'}, 339 {"increment", 1, 0, 'i'}, 340 {"threads", 1, 0, 't'}, 341 {"full", 0, 0, 'f'}, 342 {"output", 1, 0, 'o'}, 343 {"buffer-size", 1, 0, 's'}, 344 {"verbose", 0, 0, 'v'}, 345 {"help", 0, 0, HELP_OPT}, 346 {"full-help", 0, 0, FULL_HELP_OPT}, 347 {"usage", 0, 0, 'U'}, 348 {"version", 0, 0, 'V'}, 349 {0, 0, 0, 0} 350 }; 351 static const char *short_options = "VUl:h:i:t:fo:s:v"; 352 353 ::std::string err; 354 #define CHECK_ERR(type,val,which) if(!err.empty()) { ::std::cerr << "Invalid " #type " '" << val << "' for [" which "]: " << err << "\n"; exit(1); } 355 while(true) { 356 int index = -1; 357 int c = getopt_long(argc, argv, short_options, long_options, &index); 358 if(c == -1) break; 359 switch(c) { 360 case ':': 361 ::std::cerr << "Missing required argument for " 362 << (index == -1 ? ::std::string(1, (char)optopt) : std::string(long_options[index].name)) 363 << ::std::endl; 364 exit(1); 365 case HELP_OPT: 366 ::std::cout << usage() << "\n\n" << help() << std::endl; 367 exit(0); 368 case 'U': 369 ::std::cout << usage() << "\nUse --help for more information." << std::endl; 370 exit(0); 371 case 'V': 372 print_version(); 373 exit(0); 374 case '?': 375 ::std::cerr << "Use --usage or --help for some help\n"; 376 exit(1); 377 case FULL_HELP_OPT: 378 ::std::cout << usage() << "\n\n" << help() << "\n\n" << hidden() << std::flush; 379 exit(0); 380 case 'l': 381 low_given = true; 382 low_arg = conv_uint<uint64_t>((const char*)optarg, err, false); 383 CHECK_ERR(uint64_t, optarg, "-l, --low=uint64") 384 break; 385 case 'h': 386 high_given = true; 387 high_arg = conv_uint<uint64_t>((const char*)optarg, err, false); 388 CHECK_ERR(uint64_t, optarg, "-h, --high=uint64") 389 break; 390 case 'i': 391 increment_given = true; 392 increment_arg = conv_uint<uint64_t>((const char*)optarg, err, false); 393 CHECK_ERR(uint64_t, optarg, "-i, --increment=uint64") 394 break; 395 case 't': 396 threads_given = true; 397 threads_arg = conv_uint<uint32_t>((const char*)optarg, err, false); 398 CHECK_ERR(uint32_t, optarg, "-t, --threads=uint32") 399 break; 400 case 'f': 401 full_flag = true; 402 break; 403 case 'o': 404 output_given = true; 405 output_arg = optarg; 406 break; 407 case 's': 408 buffer_size_given = true; 409 buffer_size_arg = conv_uint<uint64_t>((const char*)optarg, err, true); 410 CHECK_ERR(uint64_t, optarg, "-s, --buffer-size=Buffer length") 411 break; 412 case 'v': 413 verbose_flag = true; 414 break; 415 } 416 } 417 418 // Parse arguments 419 if(argc - optind != 1) 420 error("Requires exactly 1 argument."); 421 db_arg = argv[optind]; 422 ++optind; 423 } usage()424 static const char * usage() { return "Usage: jellyfish histo [options] db:path"; } 425 class error { 426 int code_; 427 std::ostringstream msg_; 428 429 // Select the correct version (GNU or XSI) version of 430 // strerror_r. strerror_ behaves like the GNU version of strerror_r, 431 // regardless of which version is provided by the system. strerror__(char * buf,int res)432 static const char* strerror__(char* buf, int res) { 433 return res != -1 ? buf : "Invalid error"; 434 } strerror__(char * buf,char * res)435 static const char* strerror__(char* buf, char* res) { 436 return res; 437 } strerror_(int err,char * buf,size_t buflen)438 static const char* strerror_(int err, char* buf, size_t buflen) { 439 return strerror__(buf, strerror_r(err, buf, buflen)); 440 } 441 struct no_t { }; 442 443 public: 444 static no_t no; error(int code=EXIT_FAILURE)445 error(int code = EXIT_FAILURE) : code_(code) { } error(const char * msg,int code=EXIT_FAILURE)446 explicit error(const char* msg, int code = EXIT_FAILURE) : code_(code) 447 { msg_ << msg; } error(const std::string & msg,int code=EXIT_FAILURE)448 error(const std::string& msg, int code = EXIT_FAILURE) : code_(code) 449 { msg_ << msg; } operator <<(no_t)450 error& operator<<(no_t) { 451 char buf[1024]; 452 msg_ << ": " << strerror_(errno, buf, sizeof(buf)); 453 return *this; 454 } 455 template<typename T> operator <<(const T & x)456 error& operator<<(const T& x) { msg_ << x; return (*this); } ~error()457 ~error() { 458 ::std::cerr << "Error: " << msg_.str() << "\n" 459 << usage() << "\n" 460 << "Use --help for more information" 461 << ::std::endl; 462 exit(code_); 463 } 464 }; help()465 static const char * help() { return 466 "Create an histogram of k-mer occurrences\n\nCreate an histogram with the number of k-mers having a given\n" \ 467 "count. In bucket 'i' are tallied the k-mers which have a count 'c'\n" \ 468 "satisfying 'low+i*inc <= c < low+(i+1)*inc'. Buckets in the output are\n" \ 469 "labeled by the low end point (low+i*inc).\n" \ 470 "\n" \ 471 "The last bucket in the output behaves as a catchall: it tallies all\n" \ 472 "k-mers with a count greater or equal to the low end point of this\n" \ 473 "bucket.\n\n" 474 "Options (default value in (), *required):\n" 475 " -l, --low=uint64 Low count value of histogram (1)\n" 476 " -h, --high=uint64 High count value of histogram (10000)\n" 477 " -i, --increment=uint64 Increment value for buckets (1)\n" 478 " -t, --threads=uint32 Number of threads (1)\n" 479 " -f, --full Full histo. Don't skip count 0. (false)\n" 480 " -o, --output=string Output file\n" 481 " -v, --verbose Output information (false)\n" 482 " -U, --usage Usage\n" 483 " --help This message\n" 484 " --full-help Detailed help\n" 485 " -V, --version Version"; 486 } hidden()487 static const char* hidden() { return 488 "Hidden options:\n" 489 " -s, --buffer-size=Buffer length Length in bytes of input buffer (10000000)\n" 490 ""; 491 } print_version(::std::ostream & os=std::cout) const492 void print_version(::std::ostream &os = std::cout) const { 493 #ifndef PACKAGE_VERSION 494 #define PACKAGE_VERSION "0.0.0" 495 #endif 496 os << PACKAGE_VERSION << "\n"; 497 } dump(::std::ostream & os=std::cout)498 void dump(::std::ostream &os = std::cout) { 499 os << "low_given:" << low_given << " low_arg:" << low_arg << "\n"; 500 os << "high_given:" << high_given << " high_arg:" << high_arg << "\n"; 501 os << "increment_given:" << increment_given << " increment_arg:" << increment_arg << "\n"; 502 os << "threads_given:" << threads_given << " threads_arg:" << threads_arg << "\n"; 503 os << "full_flag:" << full_flag << "\n"; 504 os << "output_given:" << output_given << " output_arg:" << output_arg << "\n"; 505 os << "buffer_size_given:" << buffer_size_given << " buffer_size_arg:" << buffer_size_arg << "\n"; 506 os << "verbose_flag:" << verbose_flag << "\n"; 507 os << "db_arg:" << db_arg << "\n"; 508 } 509 }; 510 #endif // __HISTO_MAIN_CMDLINE_HPP__" 511