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

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

fixing bug in OptionFile?. Dont try to create FileUtil? for option not present in commandline

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 4.9 KB
Line 
1// $Id: CommandLine.cc 979 2007-10-21 19:46:14Z 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(),
138               std::mem_fun(&Option::validate)); 
139    }
140    catch (std::runtime_error& e){
141      std::stringstream ss;
142      ss << program_name_ << ": " << e.what();
143      throw std::runtime_error(ss.str());
144    }
145     
146  }
147
148
149  std::string CommandLine::program_name(void) const
150  {
151    return program_name_;
152  }
153
154
155  std::vector<std::string> CommandLine::split(std::string str, char del) const
156  {
157    std::vector<std::string> vec;
158    std::stringstream ss(str);
159    while (std::getline(ss, str, del)){
160      vec.push_back(str);
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.