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

Last change on this file since 972 was 972, checked in by Peter, 15 years ago

well to be correct

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.0 KB
Line 
1// $Id: CommandLine.cc 972 2007-10-17 00:11:42Z peter $
2
3/*
4  Copyright (C) 2007 Peter Johansson
5
6  This file is part of the yat library, http://trac.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 "ColumnStream.h"
27#include "Option.h"
28#include "OptionSwitch.h"
29#include "utility.h"
30
31#include <algorithm>
32#include <functional>
33#include <fstream>
34#include <iostream>
35#include <sstream>
36#include <stdexcept>
37#include <string>
38#include <vector>
39
40namespace theplu {
41namespace yat {
42namespace utility {
43
44  CommandLine::CommandLine(void)
45  {}
46
47
48  CommandLine::~CommandLine(void)
49  {
50  }
51
52
53  void CommandLine::add(Option& option)
54  {
55    if (option.long_name().size())
56      long_options_[option.long_name()] = &option;
57    if (option.short_name())
58      short_options_[option.short_name()] = &option;
59    if (option.long_name().size() || option.short_name())
60      options_.push_back(&option);
61    // allow `no-switch' for option `switch'
62    OptionSwitch* o = dynamic_cast<OptionSwitch*>(&option);
63    if (option.long_name().size() && o && 
64        !( o->long_name().size()>2 && o->long_name().substr(0,3)=="no-"))
65      long_options_[std::string("no-")+option.long_name()] = &option;
66  }
67
68
69  bool CommandLine::is_long_option(std::string str) const
70  {
71    return (str.size()>2 && str[0]=='-' && str[1]=='-');
72  }
73
74
75  bool CommandLine::is_short_option(std::string str) const
76  {
77    return (str.size()>=2 && str[0]=='-' && str[1]!='-');
78  }
79
80
81  void CommandLine::parse(int argc, char* argv[])
82  {   
83    using namespace std;
84    // just in case it is not pristine
85    for_each(options_.begin(), options_.end(),std::mem_fun(&Option::reset)); 
86
87    std::vector<std::string> arguments;
88    arguments.reserve(argc);
89    for (int i=0; i<argc; ++i)
90      arguments.push_back(argv[i]);
91    std::vector<std::string>::iterator arg(arguments.begin());   
92    stringstream ss(*arg++);
93    // keeping string after last /
94    while (getline(ss, program_name_,'/')) {}
95
96    try {
97      for (; arg!=arguments.end(); ++arg) {
98        if (is_long_option(*arg)) {
99          std::string key(arg->substr(2));
100          std::stringstream ss(key);
101          getline(ss, key, '=');
102          std::string value;
103          getline(ss, value, '\0');
104          if (!value.empty()){
105            *arg = value;
106            *(--arg) = std::string("--")+key;
107          }         
108          else
109            *arg = key;
110          std::map<std::string, Option*>::const_iterator
111            iter(long_options_.find(key));
112          if (iter==long_options_.end()) {
113            std::stringstream ss;
114            ss << program_name_ << ": unrecognized option `" << key << "'\n"
115               << try_help();
116            throw std::runtime_error(ss.str());
117          }
118          else 
119            iter->second->parse(arg, arguments.end());
120        }
121       
122        if (is_short_option(*arg)) {
123          for (size_t i=1; i<arg->size(); ++i){
124            std::map<char, Option*>::const_iterator
125              iter(short_options_.find((*arg)[i]));
126            if (iter==short_options_.end()) {
127              std::stringstream ss;
128              ss << program_name_ << ": invalid option -- " << (*arg)[i] << "\n"
129                 << try_help() << "\n";
130              throw std::runtime_error(ss.str());
131            }       
132            else 
133              iter->second->parse(arg, arguments.end());
134          }
135        }
136      }
137      for_each(options_.begin(),options_.end(),std::mem_fun(&Option::validate)); 
138    }
139    catch (std::runtime_error& e){
140      std::stringstream ss;
141      ss << program_name_ << ": " << e.what() << "\n" << try_help();
142      throw std::runtime_error(ss.str());
143    }
144     
145  }
146
147
148  std::string CommandLine::program_name(void) const
149  {
150    return program_name_;
151  }
152
153
154  std::vector<std::string> CommandLine::split(std::string str, char del) const
155  {
156    std::vector<std::string> vec;
157    std::stringstream ss(str);
158    while (std::getline(ss, str, del)){
159      vec.push_back(str);
160      std::cout << "split: push_back() " << vec.back() << std::endl;
161    }
162    return vec;
163  }
164
165  std::string CommandLine::try_help(void) const
166  {
167    return std::string("Try `"+program_name()+"' --help for more information.");
168  }
169
170
171  std::ostream& operator<<(std::ostream& os, CommandLine& cmd)
172  {
173    ColumnStream cs2(os, 2);
174    std::string::size_type width = 0;
175    for (std::vector<Option*>::const_iterator i(cmd.options_.begin()); 
176         i!=cmd.options_.end();++i) {
177      std::stringstream ss((*i)->print());
178      std::string str;
179      getline(ss, str, '\t');
180      width = std::max(width, str.size()+3);       
181    }
182    cs2.width(0)=width;
183    cs2.width(1)=76-width;
184    cs2.margin(0)=2;
185
186    for (std::vector<Option*>::const_iterator i(cmd.options_.begin()); 
187         i!=cmd.options_.end();++i) 
188      cs2 << (*i)->print() << "\n";
189
190    return os;
191  }
192
193
194}}} // of namespace utility, yat, and theplu
Note: See TracBrowser for help on using the repository browser.