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

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

fixes #344

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