help.cpp (5470B)
1 #include "poafloc.hpp" 2 3 #include <cstring> 4 #include <format> 5 #include <sstream> 6 7 namespace poafloc { 8 9 bool Parser::help_entry_t::operator<(const help_entry_t &rhs) const { 10 if (group != rhs.group) { 11 if (group && rhs.group) { 12 if (group < 0 && rhs.group < 0) return group < rhs.group; 13 if (group < 0 || rhs.group < 0) return rhs.group < 0; 14 return group < rhs.group; 15 } 16 17 return !group; 18 } 19 20 const char l1 = !opt_long.empty() ? opt_long.front()[0] 21 : !opt_short.empty() ? opt_short.front() 22 : '0'; 23 24 const char l2 = !rhs.opt_long.empty() ? rhs.opt_long.front()[0] 25 : !rhs.opt_short.empty() ? rhs.opt_short.front() 26 : '0'; 27 28 if (l1 != l2) return l1 < l2; 29 if (!opt_long.empty() || !rhs.opt_long.empty()) return !opt_long.empty(); 30 return std::strcmp(opt_long.front(), rhs.opt_long.front()) < 0; 31 } 32 33 void Parser::print_other_usages(FILE *stream) const { 34 if (argp->doc) { 35 std::istringstream iss(argp->doc); 36 std::string s; 37 38 std::getline(iss, s, '\n'); 39 std::fprintf(stream, " %s", s.c_str()); 40 41 while (std::getline(iss, s, '\n')) { 42 std::fprintf(stream, "\n or: %s [OPTIONS...] %s", m_name, 43 s.c_str()); 44 } 45 } 46 } 47 48 void Parser::help(FILE *stream) const { 49 std::string m1, m2; 50 if (argp->message) { 51 std::istringstream iss(argp->message); 52 std::getline(iss, m1, '\v'); 53 std::getline(iss, m2, '\v'); 54 } 55 56 std::fprintf(stream, "Usage: %s [OPTIONS...]", m_name); 57 print_other_usages(stream); 58 59 if (!m1.empty()) std::fprintf(stream, "\n%s", m1.c_str()); 60 std::fprintf(stream, "\n\n"); 61 62 bool first = true; 63 for (const auto &entry : help_entries) { 64 bool prev = false; 65 66 if (entry.opt_short.empty() && entry.opt_long.empty()) { 67 if (!first) std::putc('\n', stream); 68 if (entry.message) std::fprintf(stream, " %s:\n", entry.message); 69 continue; 70 } 71 72 first = false; 73 74 std::string message = " "; 75 for (const char c : entry.opt_short) { 76 if (!prev) prev = true; 77 else message += ", "; 78 79 message += std::format("-{}", c); 80 81 if (!entry.arg || !entry.opt_long.empty()) continue; 82 83 if (entry.opt) message += std::format("[{}]", entry.arg); 84 else message += std::format(" {}", entry.arg); 85 } 86 87 if (!prev) message += " "; 88 89 for (const auto l : entry.opt_long) { 90 if (!prev) prev = true; 91 else message += ", "; 92 93 message += std::format("--{}", l); 94 95 if (!entry.arg) continue; 96 97 if (entry.opt) message += std::format("[={}]", entry.arg); 98 else message += std::format("={}", entry.arg); 99 } 100 101 static const int limit = 30; 102 if (size(message) < limit) { 103 message += std::string(limit - size(message), ' '); 104 } 105 106 std::fprintf(stream, "%s", message.c_str()); 107 108 if (entry.message) { 109 std::istringstream iss(entry.message); 110 std::size_t count = 0; 111 std::string s; 112 113 std::fprintf(stream, " "); 114 while (iss >> s) { 115 count += size(s); 116 if (count > limit) { 117 std::fprintf(stream, "\n%*c", limit + 5, ' '); 118 count = size(s); 119 } 120 std::fprintf(stream, "%s ", s.c_str()); 121 } 122 } 123 std::putc('\n', stream); 124 } 125 126 if (!m2.empty()) std::fprintf(stream, "\n%s\n", m2.c_str()); 127 } 128 129 void Parser::usage(FILE *stream) const { 130 static const std::size_t limit = 60; 131 static std::size_t count = 0; 132 133 static const auto print = [&stream](const std::string &message) { 134 if (count + size(message) > limit) { 135 std::fprintf(stream, "\n "); 136 count = 6; 137 } 138 std::fprintf(stream, "%s", message.c_str()); 139 count += size(message); 140 }; 141 142 std::string message = std::format("Usage: {}", m_name); 143 144 message += " [-"; 145 for (const auto &entry : help_entries) { 146 if (entry.arg) continue; 147 for (const char c : entry.opt_short) { 148 message += c; 149 } 150 } 151 message += "]"; 152 153 std::fprintf(stream, "%s", message.c_str()); 154 count = size(message); 155 156 for (const auto &entry : help_entries) { 157 if (!entry.arg) continue; 158 for (const char c : entry.opt_short) { 159 if (entry.opt) print(std::format(" [-{}[{}]]", c, entry.arg)); 160 else print(std::format(" [-{} {}]", c, entry.arg)); 161 } 162 } 163 164 for (const auto &entry : help_entries) { 165 for (const char *name : entry.opt_long) { 166 if (!entry.arg) { 167 print(std::format(" [--{}]", name)); 168 continue; 169 } 170 171 if (entry.opt) { 172 print(std::format(" [--{}[={}]]", name, entry.arg)); 173 } else { 174 print(std::format(" [--{}={}]", name, entry.arg)); 175 } 176 } 177 } 178 179 print_other_usages(stream); 180 std::putc('\n', stream); 181 } 182 183 void Parser::see(FILE *stream) const { 184 std::fprintf(stream, 185 "Try '%s --help' or '%s --usage' for more information\n", 186 m_name, m_name); 187 } 188 189 } // namespace args