See
- The definitions parameters.h
- The description Parameters
<project-file type=“source”/>
<content> #include “parameters.h” #include <string.h> #include <iostream> #include <fstream> #include <stdlib.h> #include <stdio.h>
Argument::Argument(const char *name, const char *help, Requirement required) {
Name = new char[strlen(name)+1]; strcpy(Name, name); Help = new char[strlen(help)+1]; strcpy(Help, help); Error = NULL; Set = false; Required = required;
}
Argument::~Argument() {
if (Name != NULL) delete Name; if (Help != NULL) delete Help; if (Error != NULL) delete Error;
}
void Argument::setError(const char *error) {
if (Error != NULL) delete Error; Error = new char[strlen(error)+1]; strcpy(Error, error);
}
const char *Argument::parsable(const char *s) const {
if (s == NULL) return NULL; char key[strlen(Name)+4]; sprintf(key, "--%s=", Name); if (strstr(s, key) != s) return NULL; return &s[strlen(key)];
}
IntArgument::IntArgument(const char *name, const char *help, Requirement required, int defaultvalue) : Argument(name, help, required) {
Value = defaultvalue;
}
bool IntArgument::parse(const char *s) {
if (sscanf(s, "%d", &Value) == 1) return true; setError("not a number"); return false;
}
void IntArgument::formatHelp(std::ostream &stream) const {
stream << "--" << Name << "=number\t"; if (Required == NOT_REQUIRED) stream << "optional, "; stream << Help << std::endl;
}
BoolArgument::BoolArgument(const char *name, const char *help, Requirement required, bool defaultvalue) : Argument(name, help, required) {
Value = defaultvalue;
}
bool BoolArgument::parse(const char *s) {
if (strcmp(s, "yes") == 0) Value = true; else if (strcmp(s, "no") == 0) Value = false; else { setError("value must be either yes or no"); return false; } return true;
}
void BoolArgument::formatHelp(std::ostream &stream) const {
stream << "--" << Name << "=yes/no\t"; if (Required == NOT_REQUIRED) stream << "optional, "; stream << Help << std::endl;
}
FloatArgument::FloatArgument(const char *name, const char *help, Requirement required, float defaultvalue) : Argument(name, help, required) {
Value = defaultvalue;
}
bool FloatArgument::parse(const char *s) {
if (sscanf(s, "%f", &Value) == 1) return true; setError("not a number"); return false;
}
void FloatArgument::formatHelp(std::ostream &stream) const {
stream << "--" << Name << "=number\t"; if (Required == NOT_REQUIRED) stream << "optional, "; stream << Help << std::endl;
}
LongArgument::LongArgument(const char *name, const char *help, Requirement required, long defaultvalue) : Argument(name, help, required) {
Value = defaultvalue;
}
bool LongArgument::parse(const char *s) {
if (sscanf(s, "%ld", &Value) == 1) return true; setError("not a number"); return false;
}
void LongArgument::formatHelp(std::ostream &stream) const {
stream << "--" << Name << "=number\t"; if (Required == NOT_REQUIRED) stream << "optional, "; stream << Help << std::endl;
}
StringArgument::StringArgument(const char *name, const char *help, Requirement required, const char *defaultvalue) : Argument(name, help, required) {
if (defaultvalue == NULL) Value = NULL; else { Value = new char[strlen(defaultvalue) + 1]; strcpy(Value, defaultvalue); }
}
StringArgument::~StringArgument() {
if (Value != NULL) delete Value;
}
bool StringArgument::parse(const char *s) {
if (Value != NULL) delete Value; Value = new char[strlen(s) + 1]; strcpy(Value, s); return true;
}
void StringArgument::formatHelp(std::ostream &stream) const {
stream << "--" << Name << "=string\t"; if (Required == NOT_REQUIRED) stream << "optional, "; stream << Help << std::endl;
}
DistributionArgument::DistributionArgument(const char *name, const char *help, Requirement required, SimDistribution *defaultvalue) : Argument(name, help, required) {
Value = defaultvalue; EnableExp = true; EnableGamma = true; EnableNormal = true; EnableDiscrete = true; EnableNULL = true;
}
DistributionArgument::~DistributionArgument() {
if (Value != NULL) delete Value;
}
bool DistributionArgument::parse(const char *s) {
if (Value != NULL) { delete Value; Value = NULL; } if (strstr(s, "exp,") == s) { if (!EnableExp) { setError("exponential distribution is not supported"); return false; } const char *arg = &s[strlen("exp,")]; float mean; if (sscanf(arg, "%f", &mean) != 1) { setError("the mean of the exponential distribution is not given"); return false; } Value = new SimExpDistribution(1 / mean); } else if (strstr(s, "gamma,") == s) { if (!EnableGamma) { setError("gamma distribution is not supported"); return false; } const char *arg = &s[strlen("gamma,")]; float mean, var; if (sscanf(arg, "%f,%f", &mean, &var) != 2) { setError("both the mean and the variance of the gamma distribution must be given"); return false; } float theta = var / mean; float shape = mean / theta; Value = new SimGammaDistribution(shape, theta); } else if (strstr(s, "normal,") == s) { if (!EnableNormal) { setError("normal distribution is not supported"); return false; } const char *arg = &s[strlen("normal,")]; float mean, std; if (sscanf(arg, "%f,%f", &mean, &std) != 2) { setError("both the mean and the standard deviation of the normal distribution must be given"); return false; } Value = new SimNormalDistribution(mean, std); } else if (strstr(s, "NULL") == s) { if (!EnableNULL) { setError("NULL is not supported"); return false; } } else { SimDiscreteDistribution *dist = new SimDiscreteDistribution(); float point, value; while (*s != 0) { if (sscanf(s, "%f,%f", &point, &value) == 2) { while (*s != 0 && *s != '/') s++; if (*s != 0) s++; dist->set(point, value); } else break; } if (*s != 0 && dist->points() > 0) { delete dist; setError("the format of the discrete distribution is wrong"); return false; } if (*s != 0) { delete dist; setError("unrecognized distribution format"); return false; } Value = dist; } return true;
}
void DistributionArgument::formatHelp(std::ostream &stream) const {
stream << "--" << Name << "=<distribution>\t"; if (Required == NOT_REQUIRED) stream << "optional, "; stream << Help << std::endl; stream << "\tallowed <distribution> includes:"; if (EnableExp) stream << " exponential"; if (EnableGamma) stream << " gamma"; if (EnableNormal) stream << " normal"; if (EnableDiscrete) stream << " discrete"; stream << std::endl;
}
void DistributionArgument::formatDistributionHelp(std::ostream &stream) {
stream << "<distribution> can be one of the following:" << std::endl; stream << "\texp,mean\texponential distribution, where mean is a number" << std::endl; stream << "\tgamma,mean,variance\tgamma distribution, where mean and variance are numbers" << std::endl; stream << "\tnormal,mean,std\tnormal distribution, where mean and std are numbers" << std::endl; stream << "\tvalue1,frequency1/value1,frequency2/...\tdiscrete distribution, where each number is the frequency for value1, value2,..." << std::endl;
}
Parameters::Parameters() { }
Parameters::~Parameters() { }
void Parameters::usage(const char *program) const {
std::cerr<<"Usage: "<<program<<" parameters"<<std::endl; std::cerr<<"Parameters can be:"<<std::endl; bool hasdist = false; for (std::map<std::string, Argument*>::const_iterator i = Arguments.begin(); i != Arguments.end(); i++) { if (!hasdist && dynamic_cast<DistributionArgument*>(i->second) != NULL) hasdist = true; i->second->formatHelp(std::cerr); } if (hasdist) { std::cerr<<std::endl; DistributionArgument::formatDistributionHelp(std::cerr); }
}
bool Parameters::parseFile(const char *file) {
std::ifstream f(file); if (f.bad()) { std::cerr<<"Cannot read parameter file "<<file<<std::endl; return false; } std::string line; while (!f.eof()) { getline(f, line); int l = line.length(); // skip empty lines if (l == 0) continue; char s[l + 3]; // prepend '--' to each line s[0] = s[1] = '-'; int nonspace = -1, k = 2; for (int i = 0; i < l; i++) { // trim the white space while (i < l && line[i] == ' ' || line[i] == '\t' || line[i] == '\r') i++; if (i == l) break; // if the spaces are between two wods, keep them if (nonspace >= 0 && (isalnum(line[nonspace]) || line[nonspace] == '_') && (isalnum(line[i]) || line[i] == '_')) { for (int j = nonspace + 1; j < i; j++) s[k++] = line[j]; } s[k++] = line[i]; nonspace = i; } // skip empty lines if (k == 0) continue; // skip comments, i.e., lines starting with # if (s[2] == '#') continue; s[k] = 0; if (!parseArgument(s)) return false; } return true;
}
bool Parameters::parseArgument(const char *arg) {
bool result; if (arg[0] != '-') return parseFile(arg); std::map<std::string, Argument*>::iterator i; for (i = Arguments.begin(); i != Arguments.end(); i++) { const char *arguments = i->second->parsable(arg); if (arguments != NULL) { result = i->second->parse(arguments); if (result) { i->second->setParsed(true); return true; } break; } } if (i == Arguments.end()) std::cerr << "unrecognized argument " << arg << std::endl; else std::cerr << i->second->error() << std::endl; return false;
}
bool Parameters::parse(int args, const char *argv[]) {
for (int i = 1; i < args; i++) if (!parseArgument(argv[i])) return false; std::map<std::string, Argument*>::iterator j; for (j = Arguments.begin(); j != Arguments.end(); j++) if (j->second->required() && !j->second->set()) { std::cerr << "Error: argument " << j->second->name() << " is required" << std::endl; return false; } return true;
}
void Parameters::addArgument(Argument &arg) {
std::string name(arg.name()); Arguments[name] = &arg;
}
const Argument *Parameters::value(const char *name) const {
std::string n(name); std::map<std::string, Argument*>::const_iterator i = Arguments.find(n); if (i == Arguments.end()) return NULL; return i->second;
}
const IntArgument *Parameters::intValue(const char *name) const {
return dynamic_cast<const IntArgument*>(value(name));
}
const LongArgument *Parameters::longValue(const char *name) const {
return dynamic_cast<const LongArgument*>(value(name));
}
const FloatArgument *Parameters::floatValue(const char *name) const {
return dynamic_cast<const FloatArgument*>(value(name));
}
const BoolArgument *Parameters::boolValue(const char *name) const {
return dynamic_cast<const BoolArgument*>(value(name));
}
const StringArgument *Parameters::stringValue(const char *name) const {
return dynamic_cast<const StringArgument*>(value(name));
}
const DistributionArgument *Parameters::distributionValue(const char *name) const {
return dynamic_cast<const DistributionArgument*>(value(name));
}
bool Parameters::set(const char *name) const {
const Argument *arg = value(name); return arg != NULL && arg->set();
} </content> <use name=“parameters.h”/>