source: trunk/lib/yat/CommandLine.cc @ 1027

Last change on this file since 1027 was 983, checked in by Peter Johansson, 12 years ago

fetch yat files. refs #429

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