1 #include "bamtools_options.h"
8 using namespace BamTools;
10 string Options::m_programName; // the program name
11 string Options::m_description; // the main description
12 string Options::m_exampleArguments; // the example arguments
13 vector<OptionGroup> Options::m_optionGroups; // stores the option groups
14 map<string, OptionValue> Options::m_optionsMap; // stores the options in a map
15 string Options::m_stdin = "stdin"; // string representation of stdin
16 string Options::m_stdout = "stdout"; // string representation of stdout
18 // adds a simple option to the parser
19 void Options::AddOption(const string& argument, const string& optionDescription, bool& foundArgument, OptionGroup* group) {
22 o.Argument = argument;
23 o.Description = optionDescription;
25 group->Options.push_back(o);
28 ov.pFoundArgument = &foundArgument;
29 ov.StoreValue = false;
31 m_optionsMap[argument] = ov;
34 // creates an option group
35 OptionGroup* Options::CreateOptionGroup(const string& groupName) {
38 m_optionGroups.push_back(og);
39 return &m_optionGroups[m_optionGroups.size() - 1];
42 // displays the help menu
43 void Options::DisplayHelp(void) {
46 char argumentBuffer[ARGUMENT_LENGTH + 1];
49 char indentBuffer[MAX_LINE_LENGTH - DESC_LENGTH + 1];
50 memset(indentBuffer, ' ', MAX_LINE_LENGTH - DESC_LENGTH);
51 indentBuffer[MAX_LINE_LENGTH - DESC_LENGTH] = 0;
54 printf("Description: %s.\n\n", m_description.c_str());
57 printf("%s", m_programName.c_str());
58 printf(" %s\n\n", m_exampleArguments.c_str());
60 vector<Option>::const_iterator optionIter;
61 vector<OptionGroup>::const_iterator groupIter;
63 for (groupIter = m_optionGroups.begin(); groupIter != m_optionGroups.end(); ++groupIter) {
65 printf("%s:\n", groupIter->Name.c_str());
67 for (optionIter = groupIter->Options.begin(); optionIter != groupIter->Options.end(); ++optionIter) {
69 if (optionIter->StoreValue)
70 snprintf(argumentBuffer, ARGUMENT_LENGTH + 1, " %s <%s>", optionIter->Argument.c_str(), optionIter->ValueDescription.c_str());
72 snprintf(argumentBuffer, ARGUMENT_LENGTH + 1, " %s", optionIter->Argument.c_str());
73 printf("%-35s ", argumentBuffer);
75 string description = optionIter->Description;
77 // handle default values
78 if (optionIter->HasDefaultValue) {
81 sb << description << " [";
83 if (optionIter->DefaultValue.is_type<unsigned int>()) {
84 sb << (unsigned int)optionIter->DefaultValue;
85 } else if (optionIter->DefaultValue.is_type<unsigned char>()) {
86 sb << (unsigned short)(unsigned char)optionIter->DefaultValue;
87 } else if (optionIter->DefaultValue.is_type<float>()) {
88 sb << std::fixed << std::setprecision(2) << (float)optionIter->DefaultValue;
89 } else if (optionIter->DefaultValue.is_type<double>()) {
90 sb << std::fixed << std::setprecision(4) << (double)optionIter->DefaultValue;
91 } else if (optionIter->DefaultValue.is_type<std::string>()) {
92 const std::string stringValue = optionIter->DefaultValue;
95 printf("ERROR: Found an unsupported data type for argument %s when casting the default value.\n", optionIter->Argument.c_str());
100 description = sb.str();
103 if (description.size() <= DESC_LENGTH_FIRST_ROW) {
104 printf("%s\n", description.c_str());
107 // handle the first row
108 const char* pDescription = description.data();
109 unsigned int cutIndex = DESC_LENGTH_FIRST_ROW;
110 while(pDescription[cutIndex] != ' ') cutIndex--;
111 printf("%s\n", description.substr(0, cutIndex).c_str());
112 description = description.substr(cutIndex + 1);
114 // handle subsequent rows
115 while(description.size() > DESC_LENGTH) {
116 pDescription = description.data();
117 cutIndex = DESC_LENGTH;
118 while(pDescription[cutIndex] != ' ') cutIndex--;
119 printf("%s%s\n", indentBuffer, description.substr(0, cutIndex).c_str());
120 description = description.substr(cutIndex + 1);
124 printf("%s%s\n", indentBuffer, description.c_str());
132 printf(" --help, -h shows this help text\n");
136 // parses the command line
137 void Options::Parse(int argc, char* argv[], int offset) {
140 map<string, OptionValue>::const_iterator ovMapIter;
141 map<string, OptionValue>::const_iterator checkMapIter;
142 const int LAST_INDEX = argc - 1;
143 ostringstream errorBuilder;
144 bool foundError = false;
145 char* end_ptr = NULL;
146 const string ERROR_SPACER(7, ' ');
148 // check if we should show the help menu
149 bool showHelpMenu = false;
151 for (int i = 1; i < argc; i++) {
152 const std::string argument = argv[i];
153 if ( (argument == "-h") || (argument == "--help") || (argument == "help") )
156 } else showHelpMenu = true;
161 // check each argument
162 for (int i = offset+1; i < argc; i++) {
164 const string argument = argv[i];
165 ovMapIter = m_optionsMap.find(argument);
167 if (ovMapIter == m_optionsMap.end()) {
168 errorBuilder << ERROR_SPACER << "An unrecognized argument was found: " << argument << std::endl;
173 *ovMapIter->second.pFoundArgument = true;
176 if (ovMapIter->second.StoreValue) {
178 if (i < LAST_INDEX) {
180 // check if the next argument is really a command line option
181 const string val = argv[i + 1];
182 checkMapIter = m_optionsMap.find(val);
184 if (checkMapIter == m_optionsMap.end()) {
188 if (ovMapIter->second.VariantValue.is_type<unsigned int>()) {
189 const unsigned int uint32 = (unsigned int)strtoul(val.c_str(), &end_ptr, 10);
190 unsigned int* varValue = (unsigned int*)ovMapIter->second.pValue;
192 } else if (ovMapIter->second.VariantValue.is_type<unsigned char>()) {
193 const unsigned char uint8 = (unsigned char)strtoul(val.c_str(), &end_ptr, 10);
194 unsigned char* varValue = (unsigned char*)ovMapIter->second.pValue;
196 } else if (ovMapIter->second.VariantValue.is_type<uint64_t>()) {
197 const uint64_t uint64 = strtoui64(val.c_str(), &end_ptr, 10);
198 uint64_t* varValue = (uint64_t*)ovMapIter->second.pValue;
200 } else if (ovMapIter->second.VariantValue.is_type<double>()) {
201 const double d = strtod(val.c_str(), &end_ptr);
202 double* varValue = (double*)ovMapIter->second.pValue;
204 } else if (ovMapIter->second.VariantValue.is_type<float>()) {
205 const float f = (float)strtod(val.c_str(), &end_ptr);
206 float* varValue = (float*)ovMapIter->second.pValue;
208 } else if (ovMapIter->second.VariantValue.is_type<string>()) {
209 string* pStringValue = (string*)ovMapIter->second.pValue;
211 } else if (ovMapIter->second.VariantValue.is_type<vector<string> >()) {
212 vector<string>* pVectorValue = (vector<string>*)ovMapIter->second.pValue;
213 pVectorValue->push_back(val);
215 printf("ERROR: Found an unsupported data type for argument %s when parsing the arguments.\n", argument.c_str());
219 errorBuilder << ERROR_SPACER << "The argument (" << argument << ") expects a value, but none was found." << endl;
223 errorBuilder << ERROR_SPACER << "The argument (" << argument << ") expects a value, but none was found." << endl;
230 // check if we missed any required parameters
231 for (ovMapIter = m_optionsMap.begin(); ovMapIter != m_optionsMap.end(); ++ovMapIter) {
232 if (ovMapIter->second.IsRequired && !*ovMapIter->second.pFoundArgument) {
233 errorBuilder << ERROR_SPACER << ovMapIter->second.ValueTypeDescription << " was not specified. Please use the " << ovMapIter->first << " parameter." << endl;
238 // print the errors if any were found
240 printf("ERROR: Some problems were encountered when parsing the command line options:\n");
241 printf("%s\n", errorBuilder.str().c_str());
242 printf("For a complete list of command line options, type \"%s help %s\"\n", argv[0], argv[1]);
247 // sets the program info
248 void Options::SetProgramInfo(const string& programName, const string& description, const string& arguments) {
249 m_programName = programName;
250 m_description = description;
251 m_exampleArguments = arguments;
254 // return string representations of stdin
255 const string& Options::StandardIn(void) { return m_stdin; }
257 // return string representations of stdout
258 const string& Options::StandardOut(void) { return m_stdout; }