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

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

Clean up of namespace comments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.1 KB
Line 
1// $Id: CommandLine.cc 687 2006-10-16 23:51:10Z jari $
2
3/*
4  Copyright (C) 2006 Peter Johansson
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::parse(int argc,const char* argv[])
111  {
112    using namespace std;
113    stringstream ss(argv[0]);
114    // keeping string after last /
115    while (getline(ss,app_name_,'/')) {}
116
117    for (int k=1; k<argc; ++k) {
118      string key(argv[k]);
119      string value = string();
120      // argument
121      if (key.size()<2 || key[0]!='-'){
122        arguments_.push_back(key);       
123        continue;
124      }
125      // short name '-o'
126      if (key[1]!='-'){
127        if (k<argc-1)
128          value = argv[k+1];
129        for (size_t i = 1; i<key.size(); ++i)
130          if (update(key.substr(i,1),value))//update used one argv as argument
131            ++k; 
132      }
133      // long name '--option'
134      else{
135        key.erase(0,2);
136        // find first '='
137        size_t i = key.find('=');
138        if (i!=std::string::npos){
139          std::string q = key.substr(0,1);
140          value = key.substr(i+1,key.size()-i+1); // everything after first '='
141          key = key.substr(0,i); // everything before first '='
142        }
143        if (value.empty() && k<argc-1)
144          value = argv[++k];
145        update(key,value);
146      }
147    }
148  }
149 
150
151  bool CommandLine::update(const std::string& key, 
152                           const std::string& value)
153  {
154    key2option::iterator i = param_.find(key);
155    // Can't find key
156    if (i == param_.end()){
157      std::cerr << app_name_ << ": invalid option -- " 
158                << key << std::endl;
159      print_try_help();
160      exit(-1);
161    }
162    if (i->second==help_option_){
163      usage();
164      exit(0);
165    }
166
167    i->second->present()=true;
168
169    if (i->second->arg_type()==Option::no_arg)
170      return false;
171
172    // value is required
173    if (value.empty() || value[0]=='-'){
174      std::cerr << app_name_ << ": option "; 
175      if (i->first.size()>1)
176        std::cerr << "`--" << i->first << "' "
177                  << "requires an argument\n";
178      else 
179        std::cerr << "requires an argument -- " << i->first << "\n";
180      print_try_help();
181      exit(-1);
182    }
183    // wrong type of value
184    if ( (i->second->arg_type()==Option::double_arg&&!is_double(value))||
185         (i->second->arg_type()==Option::int_arg&&!is_int(value)) ){
186      std::cerr << app_name_ << ": invalid value `" << value << "'" 
187                << std::endl;
188      exit(-1);
189    }
190    i->second->value()=value;
191    return true;
192  }
193
194
195  void CommandLine::print_try_help(void) const
196  {
197    if (help_option_){
198      std::cerr << "Type '" << app_name_ ;
199      if (!help_option_->long_name().empty()) 
200        std::cerr << " --" << help_option_->long_name(); 
201      else
202        std::cerr << " -" << help_option_->name(); 
203      std::cerr << "' for more information.\n";
204    }
205  }
206
207
208  void CommandLine::set_help(char shortname,
209                             const std::string& longname,
210                             const std::string& descr) 
211  {
212    help_option_ = add(shortname, longname, Option::no_arg, descr);
213  }
214
215
216
217  std::string CommandLine::split(std::string& str, char del) const
218  {
219    size_t i = str.find(del);
220    if (i==std::string::npos)
221      return std::string();
222    std::string my_str(str);
223    str = str.substr(0,i);
224    return my_str.substr(i+1,str.size()-i-1);
225  }
226
227
228  void CommandLine::usage(void) const
229  {
230    using std::cerr;
231    cerr << "Usage: " << app_name_; 
232    if (!param_.empty()){
233      //cerr << " [OPTION]...\n";
234      cerr << "\n\n";
235      cerr << "Mandatory arguments to long options are mandatory for " 
236           << "short options too.\n";
237      std::for_each(options_.begin(), options_.end(), 
238                    std::mem_fun(&Option::print));
239
240    }
241    cerr << std::endl;
242
243  }
244
245
246  bool CommandLine::present(const std::string& key) const
247  {
248    key2option::const_iterator i = param_.find(key);
249    if (i==param_.end())
250      return false;
251    return i->second->present();
252     
253  }
254
255
256  std::string CommandLine::value(const std::string& key) const
257  {
258    key2option::const_iterator i = param_.find(key);
259    if (i==param_.end()){
260      std::cerr << "error: illegal key: value(\"" << key << "\"): \n";
261      exit(-1);
262    }
263   
264    return i->second->value();
265  }
266
267
268  double CommandLine::value_double(const std::string& key) const
269  {
270    key2option::const_iterator i = param_.find(key);
271    if (i->second->arg_type()!=Option::double_arg)
272      std::cerr << "error: option " << key << " does not take double argument"
273                << std::endl;
274    std::string str = value(key);
275    double value;
276    std::stringstream ss(str);
277    ss>>value;
278    return value;
279  }
280
281
282  int CommandLine::value_int(const std::string& key) const
283  {
284    std::string str = value(key);
285    key2option::const_iterator i = param_.find(key);
286    if (i->second->arg_type()!=Option::int_arg)
287      std::cerr << "error: option " << key << " does not take int argument"
288                << std::endl;
289    int value;
290    std::stringstream ss(str);
291    ss>>value;
292    return value;
293  }
294
295}}} // of namespace utility, yat, and theplu
Note: See TracBrowser for help on using the repository browser.