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