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

Last change on this file since 2265 was 2265, checked in by Peter, 13 years ago

adding two functions sort in CommandLine? that can be used to (re)sort the order of option in help output.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.5 KB
Line 
1// $Id: CommandLine.cc 2265 2010-06-05 23:12:10Z peter $
2
3/*
4  Copyright (C) 2007 Jari Häkkinen, Peter Johansson, Markus Ringnér
5  Copyright (C) 2008 Jari Häkkinen, Peter Johansson
6  Copyright (C) 2009 Peter Johansson
7  Copyright (C) 2010 Jari Häkkinen, Peter Johansson
8
9  This file is part of the yat library, http://dev.thep.lu.se/yat
10
11  The yat library is free software; you can redistribute it and/or
12  modify it under the terms of the GNU General Public License as
13  published by the Free Software Foundation; either version 3 of the
14  License, or (at your option) any later version.
15
16  The yat library is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20
21  You should have received a copy of the GNU General Public License
22  along with yat. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "CommandLine.h"
26
27#include "ColumnStream.h"
28#include "Exception.h"
29#include "Option.h"
30#include "OptionSwitch.h"
31#include "utility.h"
32
33#include <algorithm>
34#include <cassert>
35#include <functional>
36#include <fstream>
37#include <ostream>
38#include <sstream>
39#include <stdexcept>
40#include <string>
41#include <vector>
42
43namespace theplu {
44namespace yat {
45namespace utility {
46
47  CommandLine::CommandLine(std::string str)
48    : description_(str), free_arg_max_(0), parsed_(false)
49  {}
50
51
52  CommandLine::~CommandLine(void)
53  {
54  }
55
56
57  void CommandLine::add(Option& option)
58  {
59    if (option.long_name().size()) {
60      if (long_options_.find(option.long_name())!=long_options_.end()) {
61        std::stringstream ss;
62        ss << "yat::utility::Commandline: two options with long_name: "
63           << option.long_name();
64        throw runtime_error(ss.str());
65      }
66      long_options_[option.long_name()] = &option;
67    }
68    if (option.short_name()) {
69      if (short_options_.find(option.short_name())!=short_options_.end()) {
70        std::stringstream ss;
71        ss << "yat::utility::Commandline: two options with short_name: "
72           << option.short_name();
73        throw runtime_error(ss.str());
74      }
75      short_options_[option.short_name()] = &option;
76    }
77    if (option.long_name().size() || option.short_name())
78      options_.push_back(&option);
79  }
80
81
82  void CommandLine::allow_free_args(size_t n)
83  {
84    free_arg_max_ = n;
85  }
86
87
88  const std::vector<std::string>& CommandLine::free_args(void) const
89  {
90    return free_arg_;
91  }
92
93
94  bool CommandLine::is_long_option(std::string str) const
95  {
96    return (str.size()>2 && str[0]=='-' && str[1]=='-');
97  }
98
99
100  bool CommandLine::is_short_option(std::string str) const
101  {
102    return (str.size()>=2 && str[0]=='-' && str[1]!='-');
103  }
104
105
106  void CommandLine::parse(int argc, char* argv[])
107  {   
108    parsed_=true;
109    using namespace std;
110    // just in case it is not pristine
111    for_each(options_.begin(), options_.end(),std::mem_fun(&Option::reset)); 
112
113    std::vector<std::string> arguments;
114    arguments.reserve(argc);
115    for (int i=0; i<argc; ++i)
116      arguments.push_back(argv[i]);
117    std::vector<std::string>::iterator arg(arguments.begin());   
118    stringstream ss(*arg++);
119    // keeping string after last /
120    while (getline(ss, program_name_,'/')) {}
121
122    try {
123      for (; arg!=arguments.end(); ++arg) {
124        if (is_long_option(*arg)) {
125          std::string key(arg->substr(2));
126          std::stringstream ss2(key);
127          getline(ss2, key, '=');
128          std::string value;
129          getline(ss2, value, '\0');
130          if (!value.empty()){
131            *arg = value;
132            *(--arg) = std::string("--")+key;
133          }         
134          else
135            *arg = key;
136          std::map<std::string, Option*>::const_iterator
137            iter(long_options_.find(key));
138          if (iter!=long_options_.end())
139            iter->second->parse(arg, arguments.end());
140          else if (key.size()>3 && key.substr(0,3)=="no-") { 
141            iter = long_options_.find(key.substr(3));
142            if (iter!=long_options_.end())
143              iter->second->parse(arg, arguments.end());
144          }           
145          else if (iter==long_options_.end()) {
146            std::stringstream ss3;
147            ss3 << ": unrecognized option `" << key << "'\n" << try_help();
148            throw cmd_error(ss3.str());
149          }
150        }
151        else if (is_short_option(*arg)) {
152          size_t size=arg->size();
153          for (size_t i=1; i<size; ++i){
154            std::map<char, Option*>::const_iterator
155              iter(short_options_.find((*arg)[i]));
156            if (iter==short_options_.end()) {
157              std::stringstream ss2;
158              ss2 << ": invalid option -- " << (*arg)[i] << "\n"
159                  << try_help() << "\n";
160              throw cmd_error(ss2.str());
161            }       
162            else 
163              iter->second->parse(arg, arguments.end());
164          }
165        }
166        else {
167          free_arg_.push_back(*arg);
168          if (free_arg_.size()>free_arg_max_) {
169            std::stringstream ss2;
170            ss2 << ": invalid option -- " << *arg << "\n"
171                << try_help() << "\n";
172            throw cmd_error(ss2.str());
173          }
174        }
175      }
176      for_each(options_.begin(),options_.end(),
177               std::mem_fun(&Option::validate)); 
178    }
179    catch (cmd_error& e){
180      std::stringstream ss2;
181      ss2 << program_name_ << ": " << e.what();
182      throw cmd_error(ss2.str());
183    }
184     
185  }
186
187
188  bool CommandLine::parsed(void) const
189  {
190    return parsed_;
191  }
192
193
194  std::string CommandLine::program_name(void) const
195  {
196    return program_name_;
197  }
198
199
200  void CommandLine::sort(void)
201  {
202    sort(OptionCompare());
203  }
204
205
206  std::vector<std::string> CommandLine::split(std::string str, char del) const
207  {
208    std::vector<std::string> vec;
209    std::stringstream ss(str);
210    while (std::getline(ss, str, del)){
211      vec.push_back(str);
212    }
213    return vec;
214  }
215
216  std::string CommandLine::try_help(void) const
217  {
218    return std::string("Try `"+program_name()+" --help' for more information.");
219  }
220
221
222  std::ostream& operator<<(std::ostream& os, const CommandLine& cmd)
223  {
224    os << cmd.description_ << "\n";
225    ColumnStream cs2(os, 2);
226    std::string::size_type width = 0;
227    for (std::vector<Option*>::const_iterator i(cmd.options_.begin()); 
228         i!=cmd.options_.end();++i) {
229      std::stringstream ss((*i)->print());
230      std::string str;
231      getline(ss, str, '\t');
232      width = std::max(width, str.size()+3);       
233    }
234    cs2.width(0)=width;
235    cs2.width(1)=76-width;
236    cs2.margin(0)=2;
237
238    for (std::vector<Option*>::const_iterator i(cmd.options_.begin()); 
239         i!=cmd.options_.end();++i) 
240      cs2 << (*i)->print() << "\n";
241
242    return os;
243  }
244
245
246  bool CommandLine::OptionCompare::operator()(const Option* lhs, 
247                                              const Option* rhs) const
248  {
249    assert(lhs);
250    assert(rhs);
251    std::string lhs_str = lhs->long_name();
252    if (lhs_str.empty())
253      lhs_str = lhs->short_name();
254    std::string rhs_str = rhs->long_name();
255    if (rhs_str.empty())
256      rhs_str = rhs->short_name();
257    return lhs_str < rhs_str;
258  }
259
260
261}}} // of namespace utility, yat, and theplu
Note: See TracBrowser for help on using the repository browser.