aboutsummaryrefslogblamecommitdiffstats
path: root/meowpp/Usage.hpp
blob: 40b933fb8f84de30ae269b7c8e7f5db94b9b1cbb (plain) (tree)








































































































































































































































































































                                                                                
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <cstdlib>

#include "utility.h"

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 {
    if(description.length() > 0)
      return stringPrintf("%8s%s : %s\n",
                          " ", value.c_str(), description.c_str());
    else
      return "";
  }
  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;
  }
}