00001
00002
00003
00004
00005
00006
00007
00008
00009 static const char rcsid[] __attribute__((used)) = "$Id: CommandLine.cpp 1230 2014-11-16 02:32:01Z sella $";
00010
00011 #include "CommandLine.h"
00012 #include "CommandLineOption.h"
00013
00014 #include <unistd.h>
00015 #include <getopt.h>
00016 #include <stdio.h>
00017
00018 #include <exception>
00019 #include <string>
00020 #include <vector>
00021 #include <list>
00022 #include <map>
00023
00024 using namespace sella::util;
00025
00026 CommandLine::CommandLine(int argc, char **argv) throw () :
00027 argc(argc),
00028 argv(argv),
00029
00030 option(),
00031 argument(),
00032
00033 width(0)
00034 { }
00035
00036 CommandLine::CommandLine(const CommandLine ©) throw () :
00037 argc(copy.argc),
00038 argv(copy.argv),
00039
00040 option(copy.option),
00041 argument(copy.argument),
00042
00043 width(copy.width)
00044 { }
00045
00046 CommandLine::~CommandLine() throw () {
00047 this->option.clear();
00048 this->argument.clear();
00049 }
00050
00051 CommandLine &sella::util::CommandLine::operator=(const CommandLine &other) throw () {
00052 if (this != &other) {
00053 this->argc = other.argc;
00054 this->argv = other.argv;
00055
00056 this->option = other.option;
00057 this->argument = other.argument;
00058
00059 this->width = other.width;
00060 }
00061
00062 return *this;
00063 }
00064
00065 void CommandLine::add(char opt, const std::string &option, const std::string &usage, const std::string &label, const std::string &value) throw () {
00066 this->add(CommandLineOption(opt, option, usage, label, value));
00067 }
00068
00069 void CommandLine::add(char opt, const std::string &option, const std::string &usage, const std::string &label, long value, long min, long max) throw () {
00070 char buf[31];
00071 std::string v;
00072
00073 if (min != MINLONG &&value < min) {
00074 value = min;
00075 } else if (max != MINLONG &&value > max) {
00076 value = max;
00077 }
00078
00079 snprintf(buf, sizeof(buf), "%lu", value);
00080 v = buf;
00081
00082 this->add(CommandLineOption(opt, option, usage, label, v));
00083 }
00084
00085 void CommandLine::add(const CommandLineOption &option) throw () {
00086 if (this->width < option.getTags().size()) {
00087 this->width = option.getTags().size();
00088 }
00089
00090 this->option.push_back(option);
00091 }
00092
00093 void CommandLine::add(const std::string &argument, const std::string &usage) throw () {
00094 if (this->width < (argument.size() + 4)) {
00095 this->width = argument.size() + 4;
00096 }
00097
00098 this->argument.push_back(std::pair<std::string, std::string>(argument, usage));
00099 }
00100
00101 void CommandLine::usage(FILE *stream, int result) const throw () {
00102 std::string left;
00103 left.resize(this->width, ' ');
00104
00105
00106 if (this->option.size() > 0) {
00107 fprintf(stream, "\nUSAGE: %s [OPTIONS]", this->argv[0]);
00108 } else {
00109 fprintf(stream, "\nUSAGE: %s", this->argv[0]);
00110 }
00111
00112 for (auto iter = this->argument.cbegin(); iter != this->argument.cend(); iter++) {
00113 fprintf(stream, " %s", iter->first.c_str());
00114 }
00115
00116
00117 if (this->argument.size() > 0) {
00118 fprintf(stream, "\n ARGUMENTS\n");
00119 }
00120
00121 for (auto iter = this->argument.cbegin(); iter != this->argument.cend(); iter++) {
00122 std::string argument(iter->first);
00123 argument.insert(0, 4, ' ');
00124 argument.resize(this->width, ' ');
00125
00126 fprintf(stream, "%s %s\n", argument.c_str(), iter->second.c_str());
00127 }
00128
00129
00130 if (this->option.size() > 0) {
00131 fprintf(stream, "\n OPTIONS\n");
00132 }
00133
00134 for (auto iter = this->option.cbegin(); iter != this->option.cend(); iter++) {
00135 std::string tags(iter->getTags());
00136
00137 if (tags.size() > 0) {
00138 tags.resize(this->width, ' ');
00139
00140 #if 0
00141 fprintf(stream, "%s %s\n", tags.c_str(), iter->getUsage().c_str());
00142
00143 if (iter->getValue().size() > 0) {
00144 fprintf(stream, "%s [DEFAULT: %s]\n", left.c_str(), iter->getValue().c_str());
00145 }
00146 #else
00147 if (iter->getValue().size() > 0) {
00148 fprintf(stream, "%s %s (default: %s)\n", tags.c_str(), iter->getUsage().c_str(), iter->getValue().c_str());
00149 } else {
00150 fprintf(stream, "%s %s\n", tags.c_str(), iter->getUsage().c_str());
00151 }
00152 #endif
00153 } else {
00154 fprintf(stream, "\n");
00155 }
00156 }
00157
00158 fprintf(stream, "\n");
00159
00160
00161 _exit(result);
00162 }
00163
00164 std::map<std::string, std::string> CommandLine::parse(FILE *stream) const throw () {
00165 std::map<std::string, std::string> result;
00166 std::map<char, std::string> lookup;
00167
00168 std::vector<struct option> long_option;
00169 std::string option;
00170
00171 int index;
00172 int c;
00173
00174
00175 for (auto iter = this->option.cbegin(); iter != this->option.cend(); iter++) {
00176 if (iter->getTags().size() > 0) {
00177 long_option.push_back(this->build(iter->getOpt(), iter->getOption(), iter->getArgumented()));
00178 option.append(this->tag(iter->getOpt(), iter->getArgumented()));
00179
00180 if (iter->getValue().size() > 0) {
00181 result[iter->getOption()] = iter->getValue();
00182 }
00183
00184 lookup[iter->getOpt()] = iter->getOption();
00185 }
00186 }
00187
00188 long_option.push_back(this->build(0, std::string(), 0));
00189
00190
00191 while ((c = getopt_long(this->argc, this->argv, option.c_str(), &(long_option[0]), &index)) >= 0) {
00192 if (lookup.find(c) != lookup.end()) {
00193 if (optarg != 0) {
00194 result[lookup[c]] = std::string(optarg);
00195 } else {
00196 result[lookup[c]] = std::string();
00197 }
00198 } else {
00199 this->usage(stream, -1);
00200 }
00201 }
00202
00203
00204 if (argc != (optind + (int)(this->argument.size()))) {
00205 this->usage(stream, -2);
00206 } else {
00207 for (auto iter = this->argument.cbegin(); iter != this->argument.cend(); iter++) {
00208 result[iter->first] = argv[optind++];
00209 }
00210 }
00211
00212 return std::map<std::string, std::string>(result);
00213 }
00214
00215 struct option CommandLine::build(char tag, const std::string &name, bool argument) const throw () {
00216 struct option option = { (name.size() > 0) ? name.c_str() : NULL, (argument == true) ? 1 : 0, NULL, tag };
00217
00218 return option;
00219 }
00220
00221 const std::string CommandLine::tag(char tag, bool argument) const throw () {
00222 char buffer[4];
00223
00224 if (((tag >= 'a') &&(tag <= 'z')) || ((tag >= 'A') &&(tag <= 'Z')) || ((tag >= '0') &&(tag <= '9'))) {
00225 if (argument) {
00226 snprintf(buffer, 4, "%c:", tag);
00227 } else {
00228 snprintf(buffer, 4, "%c", tag);
00229 }
00230 } else {
00231 buffer[0] = 0;
00232 }
00233
00234 return std::string(buffer);
00235 }
00236
00237
00238
00239