1/*
2 Copyright (c) 2009, Kevin Rogovin All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
7
8 * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following
12 * disclaimer in the documentation and/or other materials provided
13 * with the distribution. Neither the name of the Kevin Rogovin or
14 * kRogue Technologies nor the names of its contributors may
15 * be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17
18THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29*/
30
31
32#include <ctype.h>
33#include "generic_command_line.hpp"
34
35/////////////////////////////////////
36// command_line_register methods
37command_line_register::
38~command_line_register()
39{
40 for(std::vector<command_line_argument*>::iterator
41 iter=m_children.begin(),
42 end=m_children.end();
43 iter!=end; ++iter)
44 {
45 command_line_argument *p(*iter);
46
47 if (p!=nullptr)
48 {
49 p->m_parent=nullptr;
50 p->m_location=-1;
51 }
52 }
53}
54
55
56void
57command_line_register::
58parse_command_line(int argc, char **argv)
59{
60 std::vector<std::string> arg_strings(argc);
61
62 for(int i=0;i<argc; ++i)
63 {
64 arg_strings[i]=argv[i];
65 }
66 parse_command_line(arg_strings);
67}
68
69void
70command_line_register::
71parse_command_line(const std::vector<std::string> &argv)
72{
73 int location(0);
74 int argc(argv.size());
75
76 while(location<argc)
77 {
78 bool arg_taken(false);
79
80 /*
81 we do not use the iterator interface because an argument
82 value may add new ones triggering a resize of m_children.
83 */
84 for(unsigned int i=0; !arg_taken and i<m_children.size(); ++i)
85 {
86 command_line_argument *p(m_children[i]);
87
88 if (p!=nullptr)
89 {
90 int incr;
91
92 incr=p->check_arg(argv, location);
93 if (incr>0)
94 {
95 location+=incr;
96 arg_taken=true;
97 }
98 }
99 }
100
101 if (!arg_taken)
102 {
103 ++location;
104 }
105 }
106}
107
108void
109command_line_register::
110print_help(std::ostream &ostr) const
111{
112 for(std::vector<command_line_argument*>::const_iterator
113 iter=m_children.begin(),
114 end=m_children.end();
115 iter!=end; ++iter)
116 {
117 command_line_argument *p(*iter);
118
119 if (p!=nullptr)
120 {
121 ostr << " ";
122 p->print_command_line_description(ostr);
123 }
124 }
125 ostr << "\n";
126}
127
128
129void
130command_line_register::
131print_detailed_help(std::ostream &ostr) const
132{
133 for(std::vector<command_line_argument*>::const_iterator
134 iter=m_children.begin(),
135 end=m_children.end();
136 iter!=end; ++iter)
137 {
138 command_line_argument *p(*iter);
139
140 if (p!=nullptr)
141 {
142 p->print_detailed_description(ostr);
143 }
144 }
145 ostr << "\n";
146}
147
148/////////////////////////////
149//command_line_argument methods
150command_line_argument::
151~command_line_argument()
152{
153 if (m_parent!=nullptr and m_location>=0)
154 {
155 m_parent->m_children[m_location]=nullptr;
156 }
157}
158
159#define TAB_LENGTH 4
160
161std::string
162command_line_argument::
163tabs_to_spaces(const std::string &v)
164{
165 std::vector<char> vc;
166 for(std::string::const_iterator iter=v.begin(), end=v.end(); iter!=end; ++iter)
167 {
168 if (*iter!='\t')
169 {
170 vc.push_back(*iter);
171 }
172 else
173 {
174 for(int i=0; i<TAB_LENGTH; ++i)
175 {
176 vc.push_back(' ');
177 }
178 }
179 }
180 return std::string(vc.begin(), vc.end());
181}
182
183std::string
184command_line_argument::
185produce_formatted_detailed_description(const std::string &cmd,
186 const std::string &desc)
187{
188 std::ostringstream ostr;
189 ostr << "\n\t" << cmd << " "
190 << format_description_string(cmd, desc);
191 return tabs_to_spaces(ostr.str());
192}
193
194std::string
195command_line_argument::
196format_description_string(const std::string &name, const std::string &desc)
197{
198 std::string empty(name);
199 std::ostringstream ostr;
200 int l, nl;
201 std::string::const_iterator iter, end;
202
203 nl=name.length();
204 std::fill(empty.begin(), empty.end(), ' ');
205
206 for(iter=desc.begin(), end=desc.end(); iter!=end;)
207 {
208 if (*iter!='\n')
209 {
210 ostr << "\n\t" << empty;
211 }
212
213 for(; iter!=end && *iter=='\n'; ++iter)
214 {
215 ostr << "\n\t" << empty;
216 }
217
218 for(;iter!=end && *iter==' '; ++iter)
219 {}
220
221 for(l=nl+TAB_LENGTH; l<70 && iter!=end && *iter!='\n'; ++iter)
222 {
223 ostr << *iter;
224 if (*iter=='\t')
225 {
226 l+=TAB_LENGTH;
227 }
228 else
229 {
230 ++l;
231 }
232 }
233
234 for(;iter!=end && !isspace(*iter); ++iter)
235 {
236 ostr << *iter;
237 }
238 }
239 ostr << "\n\t" << empty;
240 return tabs_to_spaces(ostr.str());
241}
242