1 | /* |
2 | Copyright (c) 2009, Kevin Rogovin All rights reserved. |
3 | |
4 | Redistribution and use in source and binary forms, with or without |
5 | modification, are permitted provided that the following conditions are |
6 | met: |
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 | |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | OF 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 |
37 | command_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 | |
56 | void |
57 | command_line_register:: |
58 | parse_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 | |
69 | void |
70 | command_line_register:: |
71 | parse_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 | |
108 | void |
109 | command_line_register:: |
110 | print_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 | |
129 | void |
130 | command_line_register:: |
131 | print_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 |
150 | command_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 | |
161 | std::string |
162 | command_line_argument:: |
163 | tabs_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 | |
183 | std::string |
184 | command_line_argument:: |
185 | produce_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 | |
194 | std::string |
195 | command_line_argument:: |
196 | format_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 | |