#include "Usage.h"
#include "utility.h"
#include <cstdlib>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
extern "C"{
#include <unistd.h>
}
namespace meow{
inline Usage::Usage(): name("nobody") { }
inline Usage::Usage(Usage::String const& _name): name(_name){ }
inline bool Usage::import(Usage const& usage){
OptionsIterator it;
for(it = usage.options.begin(); it != usage.options.end(); it++){
unsigned char const& chr = it->first;
Option const& opt = it->second;
if(options.find(chr) == options.end()){
options[chr] = opt;
}else{
return false;
}
}
for(size_t i = 0; i < usage.usage_begin.size(); i++){
usage_begin.push_back(usage.usage_begin[i]);
}
for(size_t i = 0; i < usage.usage_end.size(); i++){
usage_end.push_back(usage.usage_end[i]);
}
return true;
}
inline bool Usage::update(Usage const& usage){
OptionsIterator it;
for(it = usage.options.begin(); it != usage.options.end(); it++){
unsigned char const& chr = it->first;
if(options.find(chr) == options.end()){
continue;
}
options[chr] = it->second;
}
return true;
}
inline bool Usage::addOption(unsigned char opt, Usage::String const& des){
if(options.find(opt) != options.end()){
return false;
}
options[opt] = Option(des);
return true;
}
inline bool Usage::addOption(unsigned char opt, Usage::String const& des,
Usage::String const& val_type,
Usage::String const& val_default,
bool must){
if(options.find(opt) != options.end()){
return false;
}
options[opt] = Option(des, val_type, val_default, must);
return true;
}
inline bool Usage::addOptionValueAccept(unsigned char opt,
Usage::String const& val,
Usage::String const& des){
if(options.find(opt) == options.end()){
return false;
}
return options[opt].addValueAccept(val, des);
}
inline bool Usage::hasOptionSetup(unsigned char opt) const {
return (options.find(opt) != options.end() &&
options.find(opt)->second.hasSetup());
}
inline size_t Usage::getOptionValuesCount(unsigned char opt) const {
if(options.find(opt) == options.end()){
return 0;
}
return options.find(opt)->second.getValuesCount();
}
inline Usage::String Usage::getOptionValue(unsigned char opt,
size_t index) const {
if(options.find(opt) == options.end()){
return Usage::String();
}
return options.find(opt)->second.getValue(index);
}
inline size_t Usage::getProcArgsCount() const{
return proc_arguments.size();
}
inline Usage::String Usage::getProcArg(size_t index) const {
if(index >= proc_arguments.size()){
return Usage::String();
}
return proc_arguments[index];
}
inline Usage::Strings Usage::getProcArgs() const {
return proc_arguments;
}
inline void Usage::addUsageBegin(Usage::String const& des){
usage_begin.push_back(stringReplace(des, "<name>", name));
}
inline void Usage::addUsageEnd(Usage::String const& des){
usage_end.push_back(stringReplace(des, "<name>", name));
}
inline Usage::String Usage::getUsage() const {
Usage::String out = stringPrintf("USAGE\n %s", name.c_str());
OptionsIterator it;
for(it = options.begin(); it != options.end(); it++){
out += " " + it->second.getUsage(it->first, false);
}
out += "\n\nDESCRIPTION\n";
for(size_t i = 0; i < usage_begin.size(); i++){
out += " " + usage_begin[i] + "\n\n";
}
for(it = options.begin(); it != options.end(); it++){
out += it->second.getUsage(it->first, true);
}
for(size_t i = 0; i < usage_end.size(); i++){
out += " " + usage_end[i] + "\n\n";
}
return out;
}
inline bool Usage::setArguments(int argc, char** argv, Usage::String *errmsg){
opterr = 0;
Usage::String s;
OptionsIterator it;
Usage::String zzz;
Usage::String& err = (errmsg == NULL ? zzz : *errmsg);
for(it = options.begin(); it != options.end(); it++){
s += (char)(it->first);
if(it->second.hasValue()){
s += ":";
}
}
for(int opt; (opt = getopt(argc, argv, s.c_str())) != -1; ){
if(options.find(opt) == options.end()){
if(options.find(optopt) == options.end()){
err += stringPrintf("Unknown option '-%c'\n", optopt);
}else{
err += stringPrintf("No specify argument to '-%c'\n",
optopt);
}
opt = optopt;
return false;
}
if(options[opt].setValue(optarg == NULL ? "" : optarg) == false){
err += stringPrintf(
"Option argument '%s' to '-%c' is not allowed\n"
, optarg, opt);
return false;
}
}
for(it = options.begin(); it != options.end(); it++){
if(it->second.chkSetup() == false){
err += stringPrintf("No specify argument to '-%c'\n",
it->first);
return false;
}
}
for(int i = optind; i < argc; i++){
proc_arguments.push_back(Usage::String(argv[i]));
}
return true;
}
//
inline Usage::Value::Value(){ }
inline Usage::Value::Value(Usage::String const& v){
value = v;
description = "";
}
inline Usage::Value::Value(Usage::String const& v, Usage::String const& d){
value = v;
description = stringReplace(d, "<value>", v);
}
inline Usage::String Usage::Value::getUsage() const {
return stringPrintf("%8s%s : %s\n",
" ", value.c_str(), description.c_str());
}
inline Usage::String Usage::Value::getValue() const {
return value;
}
inline bool Usage::Value::operator==(Value const& b) const {
return (value == b.value);
}
//
inline Usage::Option::Option(){ }
inline Usage::Option::Option(Usage::String const& des){
has_setup = false;
has_value = false;
description = des;
must_setup = false;
}
inline Usage::Option::Option(Usage::String const& des,
Usage::String const& typ,
Usage::String const& def,
bool must){
has_setup = false;
has_value = true;
description = des;
value_type = typ;
value_default = def;
must_setup = must;
}
inline bool Usage::Option::setValue(Usage::String const& str){
if(has_value){
if(values_accept.size() > 0 &&
std::find(values_accept.begin(), values_accept.end(),
Value(str, "")) == values_accept.end()){
return false;
}
values.push_back(str);
}
has_setup = true;
return true;
}
inline size_t Usage::Option::getValuesCount()const{return values.size();}
inline Usage::String Usage::Option::getValue(size_t index) const{
if(!has_value){
return "";
}
if(!has_setup || index >= values.size()){
return value_default;
}
return values[index];
}
inline bool Usage::Option::addValueAccept(Usage::String const& val,
Usage::String const& des){
if(!has_value){
return false;
}
if(std::find(values_accept.begin(), values_accept.end(), Value(val))
== values_accept.end()){
values_accept.push_back(Value(val, des));
}
return true;
}
inline bool Usage::Option::hasSetup() const { return has_setup; }
inline bool Usage::Option::hasValue() const { return has_value; }
inline bool Usage::Option::chkSetup() const {
return !(must_setup && !has_setup);
}
inline Usage::String Usage::Option::getUsage(unsigned char opt,
bool detail) const {
Usage::String ret;
if(!detail){
if(!has_value){
ret = stringPrintf("-%c", opt);
}else{
ret = stringPrintf("-%c %s", opt, value_type.c_str());
}
if(!must_setup){
ret = stringPrintf("[%s]", ret.c_str());
}
}else{
Usage::String tmp;
if(has_value){
Usage::String tmp2;
if(value_default != ""){
tmp2=stringPrintf("defuault='%s'",value_default.c_str());
}
Usage::String tmp3 = must_setup ? "" : "optional";
if(tmp2.length() + tmp3.length() > 0){
if(tmp2.length() > 0 && tmp3.length() > 0){
tmp = "(" + tmp3 + ", " + tmp2 + ")";
}else{
tmp = "(" + tmp3 + tmp2 + ")";
}
}
tmp = value_type + " " + tmp;
}
ret = stringPrintf(" -%c %s\n", opt, tmp.c_str());
tmp = stringReplace(description, "<type>", value_type);
Usage::String vs;
for(size_t i = 0; i < values_accept.size(); i++){
if(i > 0){
vs += (i + 1 < values_accept.size() ? ", " : " or ");
}
vs += "'" + values_accept[i].getValue() + "'";
}
if(vs.length() == 0){
vs = "... (anything)";
}
tmp = stringReplace(tmp, "<values>", vs);
ret += " " + tmp + "\n";
for(size_t i = 0; i < values_accept.size(); i++){
ret += values_accept[i].getUsage();
}
ret += "\n";
}
return ret;
}
}