21 return std::string(2,
'"');
24 if(arg ==
"true" || arg ==
"false" || arg ==
"nan" || arg ==
"inf") {
28 if(arg.compare(0, 2,
"0x") != 0 && arg.compare(0, 2,
"0X") != 0) {
36 return std::string(
"'") + arg +
'\'';
39 if(arg.front() ==
'0') {
41 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) {
42 return (x >=
'0' && x <=
'9') || (x >=
'A' && x <=
'F') || (x >=
'a' && x <=
'f');
46 }
else if(arg[1] ==
'o') {
47 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) { return (x >=
'0' && x <=
'7'); })) {
50 }
else if(arg[1] ==
'b') {
51 if(std::all_of(arg.begin() + 2, arg.end(), [](
char x) { return (x ==
'0' || x ==
'1'); })) {
56 if(arg.find_first_of(
'"') == std::string::npos) {
57 return std::string(
"\"") + arg +
'"';
59 return std::string(
"'") + arg +
'\'';
65 ini_join(
const std::vector<std::string> &args,
char sepChar =
',',
char arrayStart =
'[',
char arrayEnd =
']') {
67 if(args.size() > 1 && arrayStart !=
'\0') {
68 joined.push_back(arrayStart);
70 std::size_t start = 0;
71 for(
const auto &arg : args) {
73 joined.push_back(sepChar);
74 if(isspace(sepChar) == 0) {
75 joined.push_back(
' ');
80 if(args.size() > 1 && arrayEnd !=
'\0') {
81 joined.push_back(arrayEnd);
86 inline std::vector<std::string>
generate_parents(
const std::string §ion, std::string &name) {
87 std::vector<std::string> parents;
89 if(section.find(
'.') != std::string::npos) {
95 if(name.find(
'.') != std::string::npos) {
100 parents.insert(parents.end(), plist.begin(), plist.end());
104 for(
auto &parent : parents) {
115 if(!output.empty() && output.back().name ==
"--") {
116 std::size_t msize = (parents.size() > 1U) ? parents.size() : 2;
117 while(output.back().parents.size() >= msize) {
118 output.push_back(output.back());
119 output.back().parents.pop_back();
122 if(parents.size() > 1) {
123 std::size_t common = 0;
124 std::size_t mpair = (std::min)(output.back().parents.size(), parents.size() - 1);
125 for(std::size_t ii = 0; ii < mpair; ++ii) {
126 if(output.back().parents[ii] != parents[ii]) {
131 if(common == mpair) {
134 while(output.back().parents.size() > common + 1) {
135 output.push_back(output.back());
136 output.back().parents.pop_back();
139 for(std::size_t ii = common; ii < parents.size() - 1; ++ii) {
140 output.emplace_back();
141 output.back().parents.assign(parents.begin(), parents.begin() +
static_cast<std::ptrdiff_t
>(ii) + 1);
142 output.back().name =
"++";
145 }
else if(parents.size() > 1) {
146 for(std::size_t ii = 0; ii < parents.size() - 1; ++ii) {
147 output.emplace_back();
148 output.back().parents.assign(parents.begin(), parents.begin() +
static_cast<std::ptrdiff_t
>(ii) + 1);
149 output.back().name =
"++";
154 output.emplace_back();
155 output.back().parents = std::move(parents);
156 output.back().name =
"++";
162 std::string section =
"default";
164 std::vector<ConfigItem> output;
166 char aStart = (defaultArray) ?
'[' :
arrayStart;
167 char aEnd = (defaultArray) ?
']' :
arrayEnd;
170 while(getline(input, line)) {
171 std::vector<std::string> items_buffer;
175 std::size_t len = line.length();
176 if(len > 1 && line.front() ==
'[' && line.back() ==
']') {
177 if(section !=
"default") {
179 output.emplace_back();
181 output.back().name =
"--";
183 section = line.substr(1, len - 2);
185 if(section.size() > 1 && section.front() ==
'[' && section.back() ==
']') {
186 section = section.substr(1, section.size() - 2);
199 if(line.front() ==
';' || line.front() ==
'#' || line.front() ==
commentChar) {
205 if(pos != std::string::npos) {
208 if(item.size() > 1 && item.front() == aStart && item.back() == aEnd) {
210 }
else if(defaultArray && item.find_first_of(aSep) != std::string::npos) {
212 }
else if(defaultArray && item.find_first_of(
' ') != std::string::npos) {
215 items_buffer = {item};
219 items_buffer = {
"true"};
221 if(name.find(
'.') == std::string::npos) {
225 for(
auto &it : items_buffer) {
231 if(!output.empty() && name == output.back().name && parents == output.back().parents) {
232 output.back().inputs.insert(output.back().inputs.end(), items_buffer.begin(), items_buffer.end());
234 output.emplace_back();
235 output.back().parents = std::move(parents);
236 output.back().name = std::move(name);
237 output.back().inputs = std::move(items_buffer);
240 if(section !=
"default") {
243 output.emplace_back();
245 output.back().name =
"--";
246 while(output.back().parents.size() > 1) {
247 output.push_back(output.back());
248 output.back().parents.pop_back();
256 std::stringstream out;
257 std::string commentLead;
259 commentLead.push_back(
' ');
261 std::vector<std::string> groups = app->
get_groups();
262 bool defaultUsed =
false;
263 groups.insert(groups.begin(), std::string(
"Options"));
264 if(write_description) {
267 for(
auto &group : groups) {
268 if(group ==
"Options" || group.empty()) {
274 if(write_description && group !=
"Options" && !group.empty()) {
275 out <<
'\n' << commentLead << group <<
" Options\n";
280 if(!opt->get_lnames().empty() && opt->get_configurable()) {
281 if(opt->get_group() != group) {
282 if(!(group ==
"Options" && opt->get_group().empty())) {
286 std::string name = prefix + opt->get_lnames()[0];
289 if(value.empty() && default_also) {
290 if(!opt->get_default_str().empty()) {
292 }
else if(opt->get_expected_min() == 0) {
298 if(write_description && opt->has_description()) {
308 for(
const App *subcom : subcommands) {
309 if(subcom->get_name().empty()) {
310 if(write_description && !subcom->get_group().empty()) {
311 out <<
'\n' << commentLead << subcom->get_group() <<
" Options\n";
313 out <<
to_config(subcom, default_also, write_description, prefix);
317 for(
const App *subcom : subcommands) {
318 if(!subcom->get_name().empty()) {
320 if(!prefix.empty() || app->
get_parent() ==
nullptr) {
321 out <<
'[' << prefix << subcom->get_name() <<
"]\n";
323 std::string subname = app->
get_name() +
"." + subcom->get_name();
325 while(p->get_parent() !=
nullptr) {
326 subname = p->
get_name() +
"." + subname;
329 out <<
'[' << subname <<
"]\n";
331 out <<
to_config(subcom, default_also, write_description,
"");
333 out <<
to_config(subcom, default_also, write_description, prefix + subcom->get_name() +
".");