26 return std::string(2,
'"');
29 if(arg ==
"true" || arg ==
"false" || arg ==
"nan" || arg ==
"inf") {
33 if(arg.compare(0, 2,
"0x") != 0 && arg.compare(0, 2,
"0X") != 0) {
41 return std::string(
"'") + arg +
'\'';
44 if(arg.front() ==
'0') {
46 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) {
47 return (x >=
'0' && x <=
'9') || (x >=
'A' && x <=
'F') || (x >=
'a' && x <=
'f');
51 }
else if(arg[1] ==
'o') {
52 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) { return (x >=
'0' && x <=
'7'); })) {
55 }
else if(arg[1] ==
'b') {
56 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) { return (x ==
'0' || x ==
'1'); })) {
61 if(arg.find_first_of(
'"') == std::string::npos) {
62 return std::string(
"\"") + arg +
'"';
64 return std::string(
"'") + arg +
'\'';
70 ini_join(
const std::vector<std::string> &args,
char sepChar =
',',
char arrayStart =
'[',
char arrayEnd =
']') {
72 if(args.size() > 1 && arrayStart !=
'\0') {
73 joined.push_back(arrayStart);
75 std::size_t start = 0;
76 for(
const auto &arg : args) {
78 joined.push_back(sepChar);
79 if(isspace(sepChar) == 0) {
80 joined.push_back(
' ');
85 if(args.size() > 1 && arrayEnd !=
'\0') {
86 joined.push_back(arrayEnd);
91 inline std::vector<std::string>
generate_parents(
const std::string §ion, std::string &name) {
92 std::vector<std::string> parents;
94 if(section.find(
'.') != std::string::npos) {
100 if(name.find(
'.') != std::string::npos) {
105 parents.insert(parents.end(), plist.begin(), plist.end());
109 for(
auto &parent : parents) {
120 if(!output.empty() && output.back().name ==
"--") {
121 std::size_t msize = (parents.size() > 1U) ? parents.size() : 2;
122 while(output.back().parents.size() >= msize) {
123 output.push_back(output.back());
124 output.back().parents.pop_back();
127 if(parents.size() > 1) {
128 std::size_t common = 0;
129 std::size_t mpair = (std::min)(output.back().parents.size(), parents.size() - 1);
130 for(std::size_t ii = 0; ii < mpair; ++ii) {
131 if(output.back().parents[ii] != parents[ii]) {
136 if(common == mpair) {
139 while(output.back().parents.size() > common + 1) {
140 output.push_back(output.back());
141 output.back().parents.pop_back();
144 for(std::size_t ii = common; ii < parents.size() - 1; ++ii) {
145 output.emplace_back();
146 output.back().parents.assign(parents.begin(), parents.begin() +
static_cast<std::ptrdiff_t
>(ii) + 1);
147 output.back().name =
"++";
150 }
else if(parents.size() > 1) {
151 for(std::size_t ii = 0; ii < parents.size() - 1; ++ii) {
152 output.emplace_back();
153 output.back().parents.assign(parents.begin(), parents.begin() +
static_cast<std::ptrdiff_t
>(ii) + 1);
154 output.back().name =
"++";
159 output.emplace_back();
160 output.back().parents = std::move(parents);
161 output.back().name =
"++";
167 std::string section =
"default";
169 std::vector<ConfigItem> output;
171 char aStart = (defaultArray) ?
'[' :
arrayStart;
172 char aEnd = (defaultArray) ?
']' :
arrayEnd;
175 while(getline(input, line)) {
176 std::vector<std::string> items_buffer;
180 std::size_t len = line.length();
181 if(len > 1 && line.front() ==
'[' && line.back() ==
']') {
182 if(section !=
"default") {
184 output.emplace_back();
186 output.back().name =
"--";
188 section = line.substr(1, len - 2);
190 if(section.size() > 1 && section.front() ==
'[' && section.back() ==
']') {
191 section = section.substr(1, section.size() - 2);
204 if(line.front() ==
';' || line.front() ==
'#' || line.front() ==
commentChar) {
210 if(pos != std::string::npos) {
213 if(item.size() > 1 && item.front() == aStart && item.back() == aEnd) {
215 }
else if(defaultArray && item.find_first_of(aSep) != std::string::npos) {
217 }
else if(defaultArray && item.find_first_of(
' ') != std::string::npos) {
220 items_buffer = {item};
224 items_buffer = {
"true"};
226 if(name.find(
'.') == std::string::npos) {
230 for(
auto &it : items_buffer) {
236 if(!output.empty() && name == output.back().name && parents == output.back().parents) {
237 output.back().inputs.insert(output.back().inputs.end(), items_buffer.begin(), items_buffer.end());
239 output.emplace_back();
240 output.back().parents = std::move(parents);
241 output.back().name = std::move(name);
242 output.back().inputs = std::move(items_buffer);
245 if(section !=
"default") {
248 output.emplace_back();
250 output.back().name =
"--";
251 while(output.back().parents.size() > 1) {
252 output.push_back(output.back());
253 output.back().parents.pop_back();
261 std::stringstream out;
262 std::string commentLead;
264 commentLead.push_back(
' ');
266 std::vector<std::string> groups = app->
get_groups();
267 bool defaultUsed =
false;
268 groups.insert(groups.begin(), std::string(
"Options"));
269 if(write_description) {
272 for(
auto &group : groups) {
273 if(group ==
"Options" || group.empty()) {
279 if(write_description && group !=
"Options" && !group.empty()) {
280 out <<
'\n' << commentLead << group <<
" Options\n";
285 if(!opt->get_lnames().empty() && opt->get_configurable()) {
286 if(opt->get_group() != group) {
287 if(!(group ==
"Options" && opt->get_group().empty())) {
291 std::string name = prefix + opt->get_lnames()[0];
294 if(value.empty() && default_also) {
295 if(!opt->get_default_str().empty()) {
297 }
else if(opt->get_expected_min() == 0) {
303 if(write_description && opt->has_description()) {
313 for(
const App *subcom : subcommands) {
314 if(subcom->get_name().empty()) {
315 if(write_description && !subcom->get_group().empty()) {
316 out <<
'\n' << commentLead << subcom->get_group() <<
" Options\n";
318 out <<
to_config(subcom, default_also, write_description, prefix);
322 for(
const App *subcom : subcommands) {
323 if(!subcom->get_name().empty()) {
325 if(!prefix.empty() || app->
get_parent() ==
nullptr) {
326 out <<
'[' << prefix << subcom->get_name() <<
"]\n";
328 std::string subname = app->
get_name() +
"." + subcom->get_name();
330 while(p->get_parent() !=
nullptr) {
331 subname = p->
get_name() +
"." + subname;
334 out <<
'[' << subname <<
"]\n";
336 out <<
to_config(subcom, default_also, write_description,
"");
338 out <<
to_config(subcom, default_also, write_description, prefix + subcom->get_name() +
".");