Mercurial > code
comparison C++/modules/OptionParser/OptionParser.cpp @ 334:0b576ee64d45
* Create brand new hierarchy
* Rename DynLib to Dynlib
* Remove some warnings
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 08 Mar 2015 14:26:33 +0100 |
parents | C++/OptionParser.cpp@99e83685d4da |
children | 3a1380b4428c |
comparison
equal
deleted
inserted
replaced
333:412ca7a5e1ea | 334:0b576ee64d45 |
---|---|
1 /* | |
2 * OptionParser.cpp -- command line option parser | |
3 * | |
4 * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #include <algorithm> | |
20 | |
21 #include "OptionParser.h" | |
22 | |
23 bool OptionParser::isShort(const std::string &arg) const | |
24 { | |
25 return arg.size() >= 2 && arg[0] == '-' && arg[1] != '-'; | |
26 } | |
27 | |
28 bool OptionParser::isLong(const std::string &arg) const | |
29 { | |
30 return arg.size() >= 3 && arg[0] == '-' && arg[1] == '-' && arg[2] != '-'; | |
31 } | |
32 | |
33 bool OptionParser::isOption(const std::string &arg) const | |
34 { | |
35 return isShort(arg) || isLong(arg); | |
36 } | |
37 | |
38 std::string OptionParser::key(const std::string &arg) const | |
39 { | |
40 if (isShort(arg)) | |
41 return arg.substr(1, 1); | |
42 | |
43 return arg.substr(2); | |
44 } | |
45 | |
46 bool OptionParser::isShortCompacted(const std::string &arg) const | |
47 { | |
48 return arg.size() >= 3; | |
49 } | |
50 | |
51 bool OptionParser::isDefined(const std::string &arg) const | |
52 { | |
53 auto n = key(arg); | |
54 auto it = std::find_if(m_options.begin(), m_options.end(), [&] (const Option &o) -> bool { | |
55 return o.key() == n || o.full() == n; | |
56 }); | |
57 | |
58 return it != m_options.end(); | |
59 } | |
60 | |
61 const Option &OptionParser::get(const std::string &arg) const | |
62 { | |
63 std::string n = key(arg); | |
64 | |
65 return *std::find_if(m_options.begin(), m_options.end(), [&] (const Option &o) -> bool { | |
66 return o.key() == n || o.full() == n; | |
67 }); | |
68 } | |
69 | |
70 bool OptionParser::isToggle(const std::string &arg) const | |
71 { | |
72 return (get(arg).flags() & Option::NoArg); | |
73 } | |
74 | |
75 void OptionParser::readShort(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const | |
76 { | |
77 /* | |
78 * There are many options when passing a short option: | |
79 * | |
80 * 1. -cmyconfig Takes on argument but parsed as unique, | |
81 * 2. -c myconfig Takes on argument but parsed as two strings | |
82 * 3. -abc If a is not a toggle option, its argument is `bc' | |
83 * 4. -abc If a is a toggle option and b, c are toggle, they are added | |
84 */ | |
85 | |
86 std::string v = it->substr(2); | |
87 std::string k = key(*it); | |
88 const Option &option = get(std::string("-") + k); | |
89 | |
90 if (isToggle(*it)) { | |
91 // 3. and optionally 4. | |
92 pack.push_back(OptionValue(option, "")); | |
93 pack.m_argsParsed += 1; | |
94 | |
95 if (isShortCompacted(*it)) { | |
96 for (char c : v) { | |
97 if (!isDefined("-" + std::string(1, c))) { | |
98 pack.m_error = "-" + std::string(1, c) + " is not a valid option"; | |
99 break; | |
100 } | |
101 | |
102 const Option &sub = get("-" + std::string(1, c)); | |
103 | |
104 pack.push_back(OptionValue(sub, "")); | |
105 } | |
106 } | |
107 | |
108 ++ it; | |
109 } else { | |
110 // 1. | |
111 if (isShortCompacted(*it++)) { | |
112 pack.push_back(OptionValue(option, v)); | |
113 pack.m_argsParsed += 1; | |
114 } else { | |
115 // 2. | |
116 if (it == end) { | |
117 pack.m_error = option.key() + " requires an option"; | |
118 } else { | |
119 pack.push_back(OptionValue(option, *it++)); | |
120 pack.m_argsParsed += 2; | |
121 } | |
122 } | |
123 } | |
124 } | |
125 | |
126 void OptionParser::readFull(OptionPack &pack, Args::const_iterator &it, Args::const_iterator end) const | |
127 { | |
128 /* | |
129 * Long options can't be compacted, there are only two possibilities: | |
130 * | |
131 * 1. --fullscreen No argument | |
132 * 2. --config foo One argument | |
133 */ | |
134 const Option &option = get(*it); | |
135 | |
136 if (!isToggle(*it)) { | |
137 // 2. | |
138 if (++it == end) { | |
139 pack.m_error = "--" + option.full() + " requires an option"; | |
140 } else { | |
141 pack.push_back(OptionValue(option, *it++)); | |
142 pack.m_argsParsed += 2; | |
143 } | |
144 } else { | |
145 pack.push_back(OptionValue(option, "")); | |
146 pack.m_argsParsed ++; | |
147 | |
148 ++ it; | |
149 } | |
150 } | |
151 | |
152 OptionParser::OptionParser(std::initializer_list<Option> options) | |
153 : m_options(options.begin(), options.end()) | |
154 { | |
155 } | |
156 | |
157 OptionParser::OptionParser(std::vector<Option> options) | |
158 : m_options(std::move(options)) | |
159 { | |
160 } | |
161 | |
162 OptionPack OptionParser::parse(Args::const_iterator it, Args::const_iterator end, int flags) const | |
163 { | |
164 OptionPack pack; | |
165 | |
166 while (it != end) { | |
167 if (!isOption(*it)) { | |
168 if (flags & Unstrict) { | |
169 pack.m_argsParsed ++; | |
170 it ++; | |
171 continue; | |
172 } else { | |
173 pack.m_error = *it + " is not an option"; | |
174 return pack; | |
175 } | |
176 } | |
177 | |
178 if (!isDefined(*it)) { | |
179 pack.m_error = "Invalid option"; | |
180 return pack; | |
181 } | |
182 | |
183 if (isShort(*it)) { | |
184 readShort(pack, it, end); | |
185 } else { | |
186 readFull(pack, it, end); | |
187 } | |
188 | |
189 // Read failure | |
190 if (pack.m_error != "No error") { | |
191 return pack; | |
192 } | |
193 } | |
194 | |
195 return pack; | |
196 } | |
197 | |
198 OptionPack OptionParser::parse(int argc, char **argv, int flags) const | |
199 { | |
200 std::vector<std::string> args; | |
201 | |
202 for (int i = 0; i < argc; ++i) | |
203 args.push_back(argv[i]); | |
204 | |
205 return parse(args, flags); | |
206 } | |
207 | |
208 OptionPack OptionParser::parse(const std::vector<std::string> &args, int flags) const | |
209 { | |
210 return parse(args.begin(), args.end(), flags); | |
211 } |