libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/base/arg_parser.hpp
Go to the documentation of this file.
00001 
00011 /*
00012  *  Copyright (C) 2007, 2009 Juan Pedro BolĂ­var Puente
00013  *
00014  *  This file is part of Psychosynth.
00015  *   
00016  *  Psychosynth is free software: you can redistribute it and/or modify
00017  *  it under the terms of the GNU General Public License as published by
00018  *  the Free Software Foundation, either version 3 of the License, or
00019  *  (at your option) any later version.
00020  *
00021  *  Psychosynth is distributed in the hope that it will be useful,
00022  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  *  GNU General Public License for more details.
00025  *
00026  *  You should have received a copy of the GNU General Public License
00027  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00028  *
00029  */
00030 
00031 #ifndef PSYNTH_ARG_PARSER_H
00032 #define PSYNTH_ARG_PARSER_H
00033 
00034 #include <sstream>
00035 #include <cstring>
00036 #include <string>
00037 #include <limits>
00038 #include <list>
00039 #include <map>
00040 
00041 #include <psynth/base/exception.hpp>
00042 #include <psynth/base/iterator.hpp>
00043 #include <psynth/base/util.hpp>
00044 
00045 namespace psynth
00046 {
00047 namespace base
00048 {
00049 
00053 PSYNTH_DECLARE_ERROR (error, arg_parser_error)
00054 PSYNTH_DECLARE_ERROR (arg_parser_error, unknown_option_error)
00055 PSYNTH_DECLARE_ERROR (arg_parser_error, parse_option_error)
00056 
00061 class parse_error : public std::exception {};
00062 
00063 namespace detail
00064 {
00065 
00069 struct ltstr
00070 {
00077     bool operator  () (const char *s1, const char *s2) const
00078     {
00079         return strcmp (s1, s2) < 0;
00080     }
00081 };
00082 
00086 struct atoi_func
00087 {
00088     int operator () (const char *str)
00089     {
00090         char* end = 0;
00091         int res = strtol (str, &end, 10);
00092         if (end <= str)
00093             throw parse_error ();
00094         return res;
00095     }
00096 };
00097 
00101 struct atof_func
00102 {
00103     float operator () (const char *str)
00104     {
00105         char* end = 0;
00106         float res = strtof (str, &end);
00107         
00108         if (end <= str)
00109             throw parse_error ();
00110         return res;
00111     }
00112 };
00113 
00118 template <class T>
00119 struct atoany_func
00120 {
00121     T operator () (const char *str)
00122     {
00123         return T (str);
00124     }
00125 };
00126 
00127 } /* namespace detail */
00128 
00132 class option
00133 {
00134 public:
00138     virtual ~option ()
00139     {
00140     }
00141 
00148     virtual bool parse (const char *arg)
00149     {
00150         return false;
00151     };
00152 
00158     virtual bool parse ()
00159     {
00160         return false;
00161     };
00162 };
00163 
00170 template <class T, class ConvFunc = detail::atoany_func <T> >
00171 class option_generic : public option
00172 {
00173 public:
00178     option_generic (T* data)
00179         : _data (data)
00180     {}
00181 
00187     bool parse (const char *arg)
00188     {
00189         *_data = ConvFunc ()(arg);
00190         return true;
00191     }
00192 
00193 private:
00194     T* _data;
00195 };
00196 
00200 class option_flag : public option
00201 {
00202     bool* _flag;
00203 
00204 public:
00209     option_flag (bool* f)
00210         : _flag (f)
00211     {}
00212 
00217     bool parse ()
00218     {
00219         *_flag = true;
00220         return true;
00221     }
00222 };
00223 
00227 class option_not_flag : public option
00228 {
00229     bool* _flag;
00230 
00231 public:
00236     option_not_flag (bool* f)
00237         : _flag (f)
00238     {}
00239 
00244     bool parse ()
00245     {
00246         *_flag = false;
00247         return true;
00248     }
00249 };
00250 
00255 template <class T>
00256 class option_stream : public option
00257 {
00258     T *m_data;
00259 
00260 public:
00265     option_stream (T * data):
00266         m_data (data)
00267     {}
00268 
00274     bool parse (const char *arg)
00275     {
00276         std::stringstream stream (std::string (arg), std::ios_base::in);
00277         stream.exceptions (std::stringstream::eofbit |
00278                            std::stringstream::failbit |
00279                            std::stringstream::badbit);
00280         try {
00281             stream >> *m_data;
00282         } catch (...) {
00283             throw parse_error ();
00284         }
00285         
00286         return true;
00287     }
00288 };
00289 
00291 typedef option_generic <int, detail::atoi_func> option_int;
00293 typedef option_generic <float, detail::atof_func> option_float;
00295 typedef option_generic <std::string> option_string;
00297 typedef option_generic <const char*> option_cstring;
00298 
00306 class arg_parser : public boost::noncopyable
00307 {
00308 public:
00312     typedef std::list <const char*>::iterator iterator;
00313 
00317     typedef std::list <const char*>::const_iterator const_iterator;
00318 
00324     void add (unsigned char flag, const char* str, int* data)
00325     {
00326         add (flag, str, data ? new option_int (data) : 0);
00327     }
00328 
00335     void add (unsigned char flag, const char* str, float* data)
00336     {
00337         add (flag, str, data ? new option_float (data) : 0);
00338     }
00339 
00346     void add (unsigned char flag, const char* str, bool* data)
00347     {
00348         add (flag, str, data ? new option_flag (data) : 0);
00349     }
00350 
00357     void add (unsigned char flag, const char* str, std::string* data)
00358     {
00359         add (flag, str, data ? new option_string (data) : 0);
00360     }
00361 
00368     void add (unsigned char flag, const char* str, const char** data)
00369     {
00370         add (flag, str, data ? new option_cstring (data) : 0);
00371     }
00372 
00381     void add (unsigned char flag, const char* str, option* op);
00382     
00394     void parse (int argc, const char* argv[]);
00395 
00399     iterator begin ()
00400     {
00401         return _free.begin ();
00402     }
00403 
00407     const_iterator begin () const
00408     {
00409         return _free.begin ();
00410     }
00411 
00415     iterator end ()
00416     {
00417         return _free.end ();
00418     }
00419 
00423     const_iterator end () const
00424     {
00425         return _free.end ();
00426     }
00427 
00431     size_t free_args () const
00432     {
00433         return _free.size ();
00434     }
00435 
00439     bool has_free_args () const
00440     {
00441         return !_free.empty ();
00442     }
00443 
00444 private:
00445     typedef ptr_iterator<std::list<option*>::iterator> option_iterator;
00446     typedef std::list<option*> option_list;
00447     typedef std::list<std::unique_ptr<option> > unique_option_list;
00448     typedef std::map <const char*, option_list, detail::ltstr>
00449     option_map;
00450 
00451     static const unsigned char null_flag = '\0';
00452     
00453     option_list              _short [256];
00454     option_map               _long;
00455     unique_option_list       _all;
00456     std::list <const char *> _free;
00457 
00458     const char** parse_short (const char** argv, const char** argv_end);
00459     const char** parse_long (const char** argv, const char** argv_end);    
00460 };
00461 
00462 } /* namespace base */
00463 } /* namespace psynth */
00464 
00465 #endif /* PSYNTH_ARGPARSER_H */