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