poafloc

Parser Of Arguments For Lines Of Commands
git clone git://git.dimitrijedobrota.com/poafloc.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

help.cpp (5626B)


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