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

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

adding function to get free args - refs #413

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