OpenCores
URL https://opencores.org/ocsvn/sqmusic/sqmusic/trunk

Subversion Repositories sqmusic

[/] [sqmusic/] [trunk/] [cpp/] [args.h] - Blame information for rev 23

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 16 gryzor
/*
2
  (c) Jose Tejada Gomez, 9th May 2013
3
  You can use this file following the GNU GENERAL PUBLIC LICENSE version 3
4
  Read the details of the license in:
5
  http://www.gnu.org/licenses/gpl.txt
6
 
7
  Send comments to: jose.tejada at ieee.org
8
 
9
*/
10
 
11
#include <string>
12
#include <vector>
13
#include <algorithm>
14
#include <cstdlib>
15
#include <iostream>
16
 
17
typedef std::vector<struct argument_t*> arg_vector_t;
18
 
19
struct argument_t {
20 23 gryzor
protected:
21
        int imin, imax;
22
        float fmin, fmax;
23
        bool limits;
24
        template<typename A> bool pass( A a, A b, A x ) { return x>=a && x<=b; }
25
public:
26 16 gryzor
  std::string short_name, long_name;
27 17 gryzor
  typedef enum { integer, text, flag, real } arg_type;
28 16 gryzor
  arg_type type;
29
  std::string description;
30
  // possible states
31
  int integer_value;
32
  std::string string_value;
33 17 gryzor
  float real_value;
34 16 gryzor
  bool state, req;
35 23 gryzor
 
36
        bool parse_hex;
37 16 gryzor
 
38
  argument_t( arg_vector_t& av, const char* long_name, arg_type type,
39 17 gryzor
    const char* desc="", bool required=false )
40 16 gryzor
    : long_name(long_name), type( type ), description( desc ),
41 23 gryzor
      req(required), state(false), integer_value(0), real_value(0),
42
                        parse_hex(false), limits(false)
43 16 gryzor
  {
44
    if( !this->long_name.empty() ) {
45
      this->short_name = "-" + this->long_name.substr(0,1);
46
      this->long_name = "--" + this->long_name;
47
    }
48
    av.push_back(this);
49
  }
50
  void set() { state=true; }
51
  bool is_set() { return state; }
52 23 gryzor
        // range control
53
        void setlimits( int min, int max ) {
54
                if( type == integer ) {
55
                        imin = min;
56
                        imax = max;
57
                        limits = true;
58
                }
59
                else if( type == real ) {
60
                        fmin = (float) min;
61
                        fmax = (float) max;
62
                        limits = true;
63
                }
64
                else throw "Cannot apply integer limits to this type of input argument";
65
        }
66
        void setlimits( float min, float max ) {
67
                if( type == real ) {
68
                        fmin = min;
69
                        fmax = max;
70
                        limits = true;
71
                }
72
                else throw "Cannot apply real limits to this type of input argument";
73
        }
74
        bool passlimits() {
75
                if( !limits ) return true;
76
                if( type == real ) return pass( fmin, fmax, real_value );
77
                else if ( type == integer ) return pass( imin, imax, integer_value );
78
                return false;
79
        }
80 16 gryzor
};
81
 
82 23 gryzor
 
83
 
84 16 gryzor
class Args {
85
  arg_vector_t& legal_args;
86
  argument_t* def_arg;
87
  std::string program_name;
88
  argument_t help_arg;
89 18 gryzor
  void clean_args() {
90
    for( int j=0; j<legal_args.size(); j++ ) {
91
      argument_t& a = *legal_args[j];
92
      if( a.short_name=="-h" && a.long_name!="help" )
93
        { help_arg.short_name.clear(); break; } // remove -h for help if already used
94
    }
95
  }
96
  void throw_error( std::string x ) /*throw const char**/ { throw x.c_str(); }
97 16 gryzor
public:
98
  Args( int argc, char *argv[], arg_vector_t& legal_args ) //throw const char *
99
  : legal_args( legal_args ),
100
    help_arg( legal_args, "help", argument_t::flag, "Display usage information")
101 18 gryzor
  {
102
    clean_args(); // eliminate duplicated values
103 16 gryzor
    // look for default argument
104
    def_arg=NULL;
105
    for( int j=0; j<legal_args.size(); j++ ) {
106
      if ( legal_args[j]->short_name.empty() && legal_args[j]->long_name.empty() )
107
        if( def_arg==NULL ) def_arg = legal_args[j];
108
        else throw "Cannot set more than one default argument.";
109
    }
110
    if( def_arg && def_arg->type!=argument_t::integer && def_arg->type!=argument_t::text )
111 23 gryzor
      throw "Default arguments can only be integer or text";
112 16 gryzor
 
113
    program_name = argv[0];
114
    for( int k=1; k<argc; k++ ) {
115
      bool matched=false;
116
      for( int j=0; j<legal_args.size(); j++ ) {
117
        argument_t& a = *legal_args[j];
118
        if( a.long_name==argv[k] || a.short_name==argv[k] ) {
119
          if( a.type == argument_t::flag ) { a.set(); matched=true; continue; }
120
          if( a.type == argument_t::text ) {
121
            k++;
122
            if( k>=argc ) throw_error("Expecting input after "+a.long_name+" param");
123
            a.string_value = argv[k];
124
            a.set();
125
            matched=true;
126
            continue;
127
          }
128
          if( a.type == argument_t::integer ) {
129
            k++;
130
            if( k>=argc ) throw_error("Expecting input after "+a.long_name+" param");
131 23 gryzor
                                                if( !a.parse_hex )
132
                    a.integer_value = atoi(argv[k]);
133
                                                else {
134
                                                        errno = 0;
135
                                                        a.integer_value = strtol( argv[k], NULL, 16 );
136
                                                        if( errno ) throw "Cannot parse hexadecimal argument";
137
                                                }
138
                                                if( !a.passlimits() ) throw_error("Argument "+a.long_name+" is not within its allowed range");
139 16 gryzor
            a.set();
140
            matched=true;
141
            continue;
142
          }
143 17 gryzor
          if( a.type == argument_t::real ) {
144
            k++;
145
            if( k>=argc ) throw_error("Expecting input after "+a.long_name+" param");
146
            a.real_value = atof(argv[k]);
147 23 gryzor
                                                if( !a.passlimits() ) throw_error("Argument "+a.long_name+" is not within its allowed range");
148 17 gryzor
            a.set();
149
            matched=true;
150
            continue;
151
          }
152 16 gryzor
        }
153
      }
154
      if( !matched && def_arg!=NULL )
155
        if( def_arg->state )
156
          throw_error( "Unknown parameter " + std::string(argv[k] ));
157
        else {
158
          if( def_arg->type==argument_t::integer ) def_arg->integer_value=atoi(argv[k]);
159
          if( def_arg->type==argument_t::text ) def_arg->string_value=argv[k];
160
          def_arg->set();
161
        }
162
    }
163
    if( help_arg.is_set() ) return; // do not perform more checks
164
    // check that all required parameters are present
165
    for( int j=0; j<legal_args.size(); j++ ) {
166
      argument_t& a = *legal_args[j];
167
      if( a.req && !a.state ) {
168
        std::string pname;
169
        if( !a.long_name.empty() ) pname=a.long_name;
170
        else if( !a.short_name.empty() ) pname=a.short_name;
171
        throw_error("Parameter "+pname+" is required.");
172
      }
173
    }
174
  }
175 21 gryzor
  void check_ilegal_combinations( arg_vector_t& ilegal ) {
176
    int count=0;
177
    std::string names;
178
    for( int k=0; k < ilegal.size(); k++ )
179
      if( ilegal[k]->is_set() ) { count++; names += " " + ilegal[k]->long_name; }
180
    if( count>1 ) throw_error( "Parameters" + names + " cannot be used together" );
181
  }
182 17 gryzor
  bool help_request() { if( help_arg.is_set() ) show_help(); return help_arg.is_set(); }
183 16 gryzor
  std::string brackets( const argument_t& a, std::string s ) {
184
    return a.req ?  "<"+s+">" : "["+s+"]";
185
  }
186
  void show_help() {
187
    std::cout << "Usage: " << program_name << " ";
188
    if( def_arg!=NULL )
189
      std::cout << brackets( *def_arg, def_arg->description.empty() ? "parameter " : def_arg->description);
190
    std::cout << "\n";
191
    for( int j=0; j<legal_args.size(); j++ ) {
192
      argument_t& a = *legal_args[j];
193
      if( a.long_name.empty() && a.long_name.empty() ) continue;
194
      std::cout << "\t";
195
      std::string aux;
196
      if( !a.long_name.empty() ) aux = a.long_name;
197 18 gryzor
      if( !a.long_name.empty() && !a.short_name.empty() ) aux += " | ";
198 16 gryzor
      if( !a.short_name.empty() ) aux+= a.short_name;
199
      std::cout << brackets( a, aux );
200 17 gryzor
      switch( a.type ) {
201
        case argument_t::integer: std::cout << " followed by integer number. "; break;
202
        case argument_t::real   : std::cout << " followed by real number. "; break;
203
        case argument_t::text   : std::cout << " followed by string. "; break;
204
      }
205 16 gryzor
      if( !a.description.empty() ) std::cout << ":  " << a.description;
206
      std::cout << "\n";
207
    }
208
  }
209
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.