44 std::size_t maxLineLengthWithoutDescription = 0;
47 std::stringstream lineSchema;
48 const auto shortOption =
"?";
49 const auto longOption =
"";
50 const auto arguments =
"";
51 const auto description =
"";
52 lineSchema << TWO_SPACES <<
"-" << shortOption <<
"," << ONE_SPACE <<
"--" << longOption <<
"=<"
53 << arguments <<
">" << TWO_SPACES << description;
54 maxLineLengthWithoutDescription = lineSchema.str().size();
58 std::size_t maxLongOptionPlusArgumentLength = 0;
59 for (
const MainOption& opt : mainOptions) {
60 if (opt.longName.empty()) {
63 const auto longOptionPlusArgumentLength = opt.longName.size() + opt.argument.size();
64 if (longOptionPlusArgumentLength > maxLongOptionPlusArgumentLength) {
65 maxLongOptionPlusArgumentLength = longOptionPlusArgumentLength;
68 maxLineLengthWithoutDescription += maxLongOptionPlusArgumentLength;
73 for (
const MainOption& opt : mainOptions) {
75 std::stringstream line;
78 if (opt.longName.empty()) {
84 if (isalpha(opt.shortName) != 0) {
85 line <<
"-" << opt.shortName <<
",";
91 line << ONE_SPACE <<
"--" << opt.longName;
94 if (!opt.argument.empty()) {
95 line <<
"=<" << opt.argument <<
">";
99 for (std::size_t lineLength = line.str().size(); lineLength < maxLineLengthWithoutDescription;
105 line << opt.description << std::endl;
120 option longNames[mainOptions.size()];
122 std::string shortNames =
"";
124 std::map<const char, const MainOption*> optionTable;
128 for (
const MainOption& opt : mainOptions) {
129 assert(opt.shortName !=
'?' &&
"short name for option cannot be '?'");
131 optionTable[opt.shortName] = &opt;
133 if (!opt.byDefault.empty()) {
134 set(opt.longName, opt.byDefault);
137 if (opt.longName.empty()) {
141 longNames[
i] = {opt.longName.c_str(), opt.argument.empty() ? 0 : 1,
nullptr, opt.shortName};
143 shortNames += opt.shortName;
145 if (!opt.argument.empty()) {
152 longNames[
i] = {
nullptr, 0,
nullptr, 0};
157 while ((c = getopt_long(argc, argv, shortNames.c_str(), longNames,
nullptr)) != EOF) {
161 throw std::runtime_error(
"Error: Unknown command line option.");
164 auto iter = optionTable.find(c);
166 assert(iter != optionTable.end() &&
"unexpected case in getopt");
169 std::string arg = optarg !=
nullptr ? std::string(optarg) :
std::string();
171 if (iter->second->takesMany) {
174 set(iter->second->longName,
get(iter->second->longName) +
' ' + arg);
178 if (
has(iter->second->longName) &&
179 (iter->second->byDefault.empty() ||
180 !
has(iter->second->longName, iter->second->byDefault))) {
181 throw std::runtime_error(
182 "Error: Only one argument allowed for option '" + iter->second->longName +
"'");
184 set(iter->second->longName, arg);
191 std::string filename =
"";
193 if (argc > 1 && optind >= argc) {
195 throw std::runtime_error(
"Error: Unknown command line option.");
198 if (mainOptions[0].longName.empty() && mainOptions[0].takesMany) {
201 set(
"", std::string(argv[optind]));
204 std::string filenames =
"";
206 for (; optind < argc; optind++) {
208 if (filenames.empty()) {
209 filenames = argv[optind];
211 filenames = filenames +
" " + std::string(argv[optind]);