source: trunk/yat/utility/CommandLine.cc @ 718

Last change on this file since 718 was 718, checked in by Jari Häkkinen, 15 years ago

Addresses #170.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.9 KB
Line 
1// $Id: CommandLine.cc 718 2006-12-26 09:56:26Z jari $
2
3/*
4  Copyright (C) 2006 Peter Johansson, Jari Hakkinen
5
6  This file is part of the yat library, http://lev.thep.lu.se/trac/yat
7
8  The yat library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version.
12
13  The yat library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  02111-1307, USA.
22*/
23
24#include "CommandLine.h"
25
26#include "Option.h"
27#include "utility.h"
28
29#include <algorithm>
30#include <functional>
31#include <fstream>
32#include <iostream>
33#include <sstream>
34
35
36namespace theplu {
37namespace yat {
38namespace utility {
39
40  CommandLine::CommandLine(void)
41    : max_argument_(0), min_argument_(0)
42  {
43  }
44
45
46  CommandLine::~CommandLine(void)
47  {
48    // Cleaning up
49    for (std::list<Option*>::iterator i=options_.begin();i!=options_.end();++i)
50      delete *(i);
51  }
52
53
54  Option* CommandLine::add(char short_name,
55                           const std::string& long_name,
56                           Option::argument_type arg,
57                           const std::string& describtion)
58  {
59    using namespace std;
60    if (short_name=='\0' && long_name.empty()){
61      cerr << "warning: cannot add parameter with no name" << endl;
62      return NULL;
63    }
64    Option* o = new Option(short_name, long_name, arg, describtion);
65
66    if (!long_name.empty()){
67      key2option::iterator i = param_.lower_bound(long_name);
68      if (i!=param_.end() && i->first == string(1,short_name)){
69        cerr << "warning: " << long_name << " already defined.\n";
70        delete o;
71        return NULL;
72      }
73      else
74        param_.insert(i, make_pair(long_name, o));
75    }
76    if (short_name!='\0'){
77      key2option::iterator i = param_.lower_bound(string(1,short_name));
78      if (i!=param_.end() && i->first == string(1,short_name)){
79        cerr << "warning: " << short_name << " already defined.\n";
80        delete o;
81        return NULL;
82      }
83      else
84        param_.insert(i, make_pair(string(1,short_name), o));
85    }
86    options_.push_back(o);
87    return o;
88  }
89
90
91  void CommandLine::add_parameter(const std::string& name,
92                                  Option::argument_type arg,
93                                  const std::string& description)
94  {
95    if (name.size()==1)
96      add(name[0], "", arg, description);
97    else
98      add('\0', name, arg, description);
99  }
100
101
102  void CommandLine::add_parameter(char name,
103                                  Option::argument_type arg,
104                                  const std::string& description)
105  {
106    add(name, "", arg, description);
107  }
108 
109
110  void CommandLine::add_parameter(char short_name, const std::string& long_name,
111                                  Option::argument_type arg,
112                                  const std::string& description)
113  {
114    add(short_name, long_name, arg, description);
115  }
116
117
118  bool CommandLine::is_long_option(const std::string& str)
119  {
120    return (str.size()>3 && str[0]=='-' && str[1]=='-');
121  }
122
123
124  bool CommandLine::is_short_option(const std::string& str)
125  {
126    return (str.size()==2 && str[0]=='-' && isalpha(str[1]));
127  }
128
129
130  u_int& CommandLine::max_argument(void)
131  {
132    return max_argument_;
133  }
134
135
136  u_int& CommandLine::min_argument(void)
137  {
138    return min_argument_;
139  }
140
141
142  void CommandLine::parse(int argc,const char* argv[])
143  {
144    using namespace std;
145    stringstream ss(argv[0]);
146    // keeping string after last /
147    while (getline(ss,app_name_,'/')) {}
148
149    for (int k=1; k<argc; ++k) {
150      string key(argv[k]);
151      string value = string();
152      // argument
153      if (key.size()<2 || key[0]!='-'){
154        arguments_.push_back(key);       
155        continue;
156      }
157      // short name '-o'
158      if (key[1]!='-'){
159        if (k<argc-1)
160          value = argv[k+1];
161        for (size_t i = 1; i<key.size(); ++i)
162          if (update(key.substr(i,1),value))//update used one argv as argument
163            ++k; 
164      }
165      // long name '--option'
166      else{
167        key.erase(0,2);
168        // find first '='
169        size_t i = key.find('=');
170        if (i!=std::string::npos){
171          std::string q = key.substr(0,1);
172          value = key.substr(i+1,key.size()-i+1); // everything after first '='
173          key = key.substr(0,i); // everything before first '='
174        }
175        if (value.empty() && k<argc-1)
176          value = argv[++k];
177        update(key,value);
178      }
179    }
180  }
181
182
183  void CommandLine::set_general_description(const std::string& description)
184  {
185    general_description_=description;
186  }
187
188
189  bool CommandLine::update(const std::string& key, 
190                           const std::string& value)
191  {
192    key2option::iterator i = param_.find(key);
193    // Can't find key
194    if (i == param_.end()){
195      std::cerr << app_name_ << ": invalid option -- " 
196                << key << std::endl;
197      print_try_help();
198      exit(-1);
199    }
200    if (i->second==help_option_){
201      usage();
202      exit(0);
203    }
204
205    i->second->present()=true;
206
207    if (i->second->arg_type()==Option::no_arg)
208      return false;
209
210    // value is required
211    if (value.empty() || value[0]=='-'){
212      std::cerr << app_name_ << ": option "; 
213      if (i->first.size()>1)
214        std::cerr << "`--" << i->first << "' "
215                  << "requires an argument\n";
216      else 
217        std::cerr << "requires an argument -- " << i->first << "\n";
218      print_try_help();
219      exit(-1);
220    }
221    // wrong type of value
222    if ( (i->second->arg_type()==Option::double_arg&&!is_double(value))||
223         (i->second->arg_type()==Option::int_arg&&!is_int(value)) ){
224      std::cerr << app_name_ << ": invalid value `" << value << "'" 
225                << std::endl;
226      exit(-1);
227    }
228    i->second->value()=value;
229    return true;
230  }
231
232
233  void CommandLine::print_try_help(void) const
234  {
235    if (help_option_){
236      std::cerr << "Type '" << app_name_ ;
237      if (!help_option_->long_name().empty()) 
238        std::cerr << " --" << help_option_->long_name(); 
239      else
240        std::cerr << " -" << help_option_->name(); 
241      std::cerr << "' for more information.\n";
242    }
243  }
244
245
246  void CommandLine::set_help(char shortname,
247                             const std::string& longname,
248                             const std::string& descr) 
249  {
250    help_option_ = add(shortname, longname, Option::no_arg, descr);
251  }
252
253
254
255  std::string CommandLine::split(std::string& str, char del) const
256  {
257    size_t i = str.find(del);
258    if (i==std::string::npos)
259      return std::string();
260    std::string my_str(str);
261    str = str.substr(0,i);
262    return my_str.substr(i+1,str.size()-i-1);
263  }
264
265
266  void CommandLine::usage(void) const
267  {
268    using std::cerr;
269    cerr << "Usage: " << app_name_; 
270    if (!param_.empty()){
271      //cerr << " [OPTION]...\n";
272      cerr << "\n\n";
273      cerr << "Mandatory arguments to long options are mandatory for " 
274           << "short options too.\n";
275      std::for_each(options_.begin(), options_.end(), 
276                    std::mem_fun(&Option::print));
277
278    }
279    cerr << std::endl;
280
281  }
282
283
284  bool CommandLine::present(const std::string& key) const
285  {
286    key2option::const_iterator i = param_.find(key);
287    if (i==param_.end())
288      return false;
289    return i->second->present();
290     
291  }
292
293
294  std::string CommandLine::value(const std::string& key) const
295  {
296    key2option::const_iterator i = param_.find(key);
297    if (i==param_.end()){
298      std::cerr << "error: illegal key: value(\"" << key << "\"): \n";
299      exit(-1);
300    }
301   
302    return i->second->value();
303  }
304
305
306  double CommandLine::value_double(const std::string& key) const
307  {
308    key2option::const_iterator i = param_.find(key);
309    if (i->second->arg_type()!=Option::double_arg)
310      std::cerr << "error: option " << key << " does not take double argument"
311                << std::endl;
312    std::string str = value(key);
313    double value;
314    std::stringstream ss(str);
315    ss>>value;
316    return value;
317  }
318
319
320  int CommandLine::value_int(const std::string& key) const
321  {
322    std::string str = value(key);
323    key2option::const_iterator i = param_.find(key);
324    if (i->second->arg_type()!=Option::int_arg)
325      std::cerr << "error: option " << key << " does not take int argument"
326                << std::endl;
327    int value;
328    std::stringstream ss(str);
329    ss>>value;
330    return value;
331  }
332
333}}} // of namespace utility, yat, and theplu
Note: See TracBrowser for help on using the repository browser.