38 {
39 std::stringstream out;
40 std::string commentLead;
41 commentLead.push_back(commentChar);
42 commentLead.push_back(' ');
43
44 std::vector<std::string> groups = app->get_groups();
45 bool defaultUsed = false;
46 groups.insert(groups.begin(), std::string("Options"));
47 for (const auto& group : groups) {
48 if (group == "Options" || group.empty()) {
49 if (defaultUsed) {
50 continue;
51 }
52 defaultUsed = true;
53 }
54 if (write_description && group != "Options" && !group.empty() &&
55 !app->get_options([group](const Option* opt) -> bool {
56 return opt->get_group() == group && opt->get_configurable();
57 })
58 .empty()) {
59 out << '\n' << commentChar << commentLead << group << "\n";
60 }
61 for (const Option* opt : app->get_options({})) {
62
63 if (opt->get_configurable()) {
64 if (opt->get_group() != group) {
65 if (!(group == "Options" && opt->get_group().empty())) {
66 continue;
67 }
68 }
69 const std::string name = prefix + opt->get_single_name();
70 std::string value =
71 detail::ini_join(opt->reduced_results(), arraySeparator, arrayStart, arrayEnd, stringQuote, characterQuote);
72
73 std::string defaultValue{};
74 if (default_also) {
75 static_assert(std::string::npos + static_cast<std::string::size_type>(1) == 0,
76 "std::string::npos + static_cast<std::string::size_type>(1) != 0");
77 if (!value.empty() && opt->get_default_str() == value) {
78 value.clear();
79 }
80 if (!opt->get_default_str().empty()) {
81 defaultValue = detail::convert_arg_for_ini(opt->get_default_str(), stringQuote, characterQuote);
82 } else if (opt->get_expected_min() == 0) {
83 defaultValue = "false";
84 } else if (opt->get_run_callback_for_default()) {
85 defaultValue = "\"\"";
86 } else if (opt->get_required()) {
87 defaultValue = "\"<REQUIRED>\"";
88 } else {
89 defaultValue = "\"\"";
90 }
91 }
92 if (write_description && opt->has_description() && (default_also || !value.empty())) {
93 out << commentLead << detail::fix_newlines(commentLead, opt->get_description()) << '\n';
94 }
95 if (default_also) {
96 out << commentChar << name << valueDelimiter << defaultValue << "\n";
97 }
98 if (!value.empty()) {
99 if (!opt->get_fnames().empty()) {
100 value = opt->get_flag_value(name, value);
101 }
102 out << name << valueDelimiter << value << "\n\n";
103 } else {
104 out << '\n';
105 }
106 }
107 }
108 }
109 auto subcommands = app->get_subcommands({});
110 for (const App* subcom : subcommands) {
111 if (subcom->get_name().empty()) {
112 if (write_description && !subcom->get_group().empty()) {
113 out << '\n' << commentLead << subcom->get_group() << " Options\n";
114 }
115 out <<
to_config(subcom, default_also, write_description, prefix);
116 }
117 }
118
119 for (const App* subcom : subcommands) {
120 if (!subcom->get_name().empty()) {
121 if (subcom->get_configurable() && app->got_subcommand(subcom)) {
122 if (!prefix.empty() || app->get_parent() == nullptr) {
123 out << '[' << prefix << subcom->get_name() << "]\n";
124 } else {
125 std::string subname = app->get_name() + parentSeparatorChar + subcom->get_name();
126 const auto* p = app->get_parent();
127 while (p->get_parent() != nullptr) {
128 subname = p->get_name() + parentSeparatorChar + subname;
129 p = p->get_parent();
130 }
131 out << '[' << subname << "]\n";
132 }
133 out <<
to_config(subcom, default_also, write_description,
"");
134 } else {
135 out <<
to_config(subcom, default_also, write_description, prefix + subcom->get_name() + parentSeparatorChar);
136 }
137 }
138 }
139
140 std::string outString;
141 if (write_description && !out.str().empty()) {
142 outString =
143 commentChar + std::string("#") + commentLead + detail::fix_newlines(commentChar + commentLead, app->get_description());
144 }
145
146 return outString + out.str();
147 }