File indexing completed on 2025-09-16 09:03:56
0001
0002
0003
0004
0005
0006 #ifndef Pythia8_InputParser_H
0007 #define Pythia8_InputParser_H
0008
0009
0010 #include "Pythia8/PythiaStdlib.h"
0011
0012 namespace Pythia8 {
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 class InputParser {
0026 public:
0027
0028
0029
0030
0031
0032
0033
0034
0035 InputParser(string usage = "", vector<string> examples = {},
0036 string extra = "", ostream* stream = &cout,
0037 string optName = "h", set<string> aliases = {"-help","H"}) :
0038 usageText(usage), examplesText(examples), extraText(extra),
0039 streamPtr(stream), helpFlag(optName) {
0040 add(optName, "false", "Show this help message and exit.", aliases);
0041 }
0042
0043
0044
0045
0046
0047
0048
0049 bool add(const string& optName, const string& defString,
0050 const string& helpText = "", set<string> aliases = {}) {
0051
0052 if (options.find(optName) != options.end() ||
0053 aliasMap.find(optName) != aliasMap.end()) {
0054 print("Name conflict for '" + optName + "'.\n");
0055 return false;
0056 }
0057
0058 OptionInfo optInfo(optName, defString, helpText, aliases);
0059 options[optName] = optInfo;
0060
0061 for (const string& alias : aliases) {
0062 if (options.find(alias) != options.end() ||
0063 aliasMap.find(alias) != aliasMap.end()) {
0064 print("Name conflict for alias '" + alias + "'.\n");
0065 return false;
0066 }
0067 aliasMap[alias] = optName;
0068 }
0069 return true;
0070 }
0071
0072
0073 bool require(const string& optName, const string& helpText = "",
0074 set<string> aliases = {}) {
0075 if (!add(optName, "", helpText, aliases)) return false;
0076 options[optName].required = true;
0077 return true;
0078 }
0079
0080
0081
0082 enum Status {Valid = -1, Invalid = EXIT_FAILURE, Help = EXIT_SUCCESS};
0083 Status init(int& argc, char** argv) {
0084
0085
0086 bool valid = parse(argc, argv);
0087 if (!valid) return Status::Invalid;
0088
0089
0090 if (options.find(helpFlag) != options.end() && get<bool>(helpFlag)) {
0091 string out;
0092 if (usageText != "") out = "Usage: " + usageText;
0093 if (examplesText.size() > 0) {
0094 out += "\nExample" + string(examplesText.size() > 1 ? "s:" : ":");
0095 for (const string& text: examplesText) out += "\n\t" + text;
0096 }
0097 if (options.size() > 0) {
0098 out += "\nOption" + string(options.size() > 1 ? "s:\n" : ":\n")
0099 + help() + "\n";
0100 }
0101 print(out + extraText);
0102 return Status::Help;
0103 }
0104
0105
0106 for (map<string, OptionInfo>::iterator opt = options.begin();
0107 opt != options.end(); opt++) {
0108 if (opt->second.required && !opt->second.provided) {
0109 print("Option '-" + opt->first + "' is required but was not set.\n"
0110 "\t -" + opt->first + " " + opt->second.helpText + "\n");
0111 valid = false;
0112 }
0113 }
0114 return valid ? Status::Valid : Status::Invalid;
0115
0116 }
0117
0118
0119
0120
0121
0122 bool parse(int& argc, char** argv) {
0123 for (int i = 1; i < argc; ++i) {
0124 string arg = argv[i];
0125
0126 if (arg[0] == '-') {
0127 string optName = arg.substr(1);
0128
0129 if (aliasMap.find(optName) != aliasMap.end())
0130 optName = aliasMap[optName];
0131
0132 if (options.find(optName) != options.end()) {
0133
0134
0135 if (i + 1 < argc && argv[i + 1][0] != '-') {
0136 options[optName].stringValues.push_back(argv[++i]);
0137 options[optName].provided = true;
0138 } else {
0139
0140 const string& def = options[optName].defaultValue;
0141 if (def == "false" || def == "False" || def == "0"
0142 || def == "off") {
0143 options[optName].stringValues.push_back("true");
0144 options[optName].provided = true;
0145 } else if (def == "true" || def == "True" || def == "1"
0146 || def == "on") {
0147 options[optName].stringValues.push_back("false");
0148 options[optName].provided = true;
0149 } else {
0150 print("Failed to parse command line arguments.\n"
0151 "No value passed for option '" + string(arg) + "'.\n");
0152 return false;
0153 }
0154 }
0155 } else {
0156 print("Failed to parse command line arguments.\n"
0157 "Unknown option '" + string(arg) + "'.\n");
0158 return false;
0159 }
0160 }
0161 }
0162 return true;
0163 }
0164
0165
0166
0167 bool has(const string& optName) const {
0168 return options.find(optName) != options.end();
0169 }
0170
0171
0172
0173 template<typename T>
0174 T get(const string& optName) {
0175 if (!has(optName)) {
0176 print("Failed to find option '" + optName + "'.\n");
0177 return T();
0178 }
0179
0180 const OptionInfo& optInfo = options.at(optName);
0181
0182 if (optInfo.stringValues.empty()) return T();
0183 if (optInfo.stringValues.back().empty()) return T();
0184
0185 stringstream conv(optInfo.stringValues.back());
0186 T value;
0187 conv >> std::boolalpha >> value;
0188
0189 if (conv.fail()) {
0190 print("Failed to convert '" + optInfo.optName + "'.\n");
0191 return T();
0192 }
0193 return value;
0194 }
0195
0196
0197 template<typename T>
0198 vector<T> getVector(const string& optName) {
0199 vector<T> values;
0200 if (!has(optName)) {
0201 print("Failed to find option '" + optName + "'.\n");
0202 return values;
0203 }
0204
0205 const OptionInfo& optInfo = options.at(optName);
0206
0207 if (optInfo.stringValues.empty()) return values;
0208
0209 for (const string& stringValue: optInfo.stringValues) {
0210 if (stringValue.empty()) {
0211 values.push_back(T());
0212 continue;
0213 }
0214 stringstream conv(stringValue);
0215 T value;
0216 conv >> std::boolalpha >> value;
0217
0218 if (conv.fail()) {
0219 print("Failed to convert '" + optInfo.optName + "'.\n");
0220 return values;
0221 }
0222 values.push_back(value);
0223 }
0224 return values;
0225 }
0226
0227
0228
0229 const string help() const {
0230 stringstream out;
0231 auto oItr = options.cbegin();
0232 while (oItr != options.cend()) {
0233 out << "\t-" << oItr->second.optName;
0234 if (!oItr->second.aliases.empty()) {
0235 out << " (";
0236 auto aItr = oItr->second.aliases.cbegin();
0237 while(aItr != oItr->second.aliases.cend()) {
0238 out << "-" << *aItr;
0239 if (++aItr != oItr->second.aliases.cend()) out << ", ";
0240 }
0241 out << ")";
0242 }
0243 else out << "\t";
0244 out << "\t" << oItr->second.helpText;
0245 if (oItr->second.required)
0246 out << " (required)";
0247 else if (oItr->second.defaultValue != "")
0248 out << " (default: " << oItr->second.defaultValue << ")";
0249 if (++oItr != options.cend()) out << "\n";
0250 }
0251 return out.str();
0252 }
0253
0254 private:
0255
0256
0257 struct OptionInfo {
0258
0259 OptionInfo() {}
0260
0261 OptionInfo(const string& n, const string& v, const string& h,
0262 set<string> a) : optName(n), defaultValue(v),
0263 stringValues(1, v), helpText(h), aliases(a) {}
0264 string optName;
0265 string defaultValue;
0266 vector<string> stringValues;
0267 string helpText;
0268 set<string> aliases;
0269 bool required{false};
0270 bool provided{false};
0271 };
0272
0273
0274 string usageText{};
0275 vector<string> examplesText{};
0276 string extraText{};
0277 ostream* streamPtr{};
0278 string helpFlag{};
0279
0280
0281 void print(string out) {if (streamPtr != nullptr) *streamPtr << out;}
0282
0283
0284 map<string, OptionInfo> options;
0285
0286 map<string, string> aliasMap;
0287
0288 };
0289
0290 }
0291
0292 #endif