cmdline.h命令行处理框架

cmdline.h命令行处理框架

源代码转载处:(https://github.com/tanakh/cmdline)

源代码中有部分存在问题无法编译,修改后在win11+vs2022可顺利编译

#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <sstream>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <vector>

namespace cmdline {

namespace detail {

template <typename Target, typename Source, bool Same>
class lexical_cast_t {
 public:
   //格式转换
  static Target cast(const Source &arg) {
    Target ret;
    std::stringstream ss;
    //将arg放入流ss中,从ss流中抽取数据放入ret中
    if (!(ss << arg && ss >> ret && ss.eof())) 
      throw std::bad_cast();
    return ret;
  }
};

template <typename Target, typename Source>
class lexical_cast_t<Target, Source, true> {
 public:
  static Target cast(const Source &arg) { return arg; }
};

template <typename Source>
class lexical_cast_t<std::string, Source, false> {
 public:
  static std::string cast(const Source &arg) {
    std::ostringstream ss;
    ss << arg;
    return ss.str();
  }
};

//将传入的string转换为Target类型后返回
template <typename Target>
class lexical_cast_t<Target, std::string, false> {
 public:
  static Target cast(const std::string &arg) {
    Target ret;
    // istringstream类用于执行C++风格的串流的输入操作
    std::istringstream ss(arg);
    if (!(ss >> ret && ss.eof())) throw std::bad_cast();
    return ret;
  }
};

template <typename T1, typename T2>
struct is_same {
  static const bool value = false;
};

template <typename T>
struct is_same<T, T> {
  static const bool value = true;
};

//类型转换
template <typename Target, typename Source>
Target lexical_cast(const Source &arg) {
  return lexical_cast_t<Target, Source,
                        detail::is_same<Target, Source>::value>::cast(arg);
}
//识别C++编译以后的函数名的过程,叫demangle
static inline std::string demangle(const std::string &name) {
#ifdef _MSC_VER
  return name;  // 为MSVC编译器时直接返回name
#elif
  // defined(__GNUC__)
  // 为gcc编译器时还调用原来的代码
  int status = 0;
  char *p = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
  std::string ret(p);
  free(p);
#endif
}

//返回类型名称
template <class T>
std::string readable_typename() {
  // typeid().name()获取目标类型
  return demangle(typeid(T).name());
}
//将传入参数转为string类型
template <class T>
std::string default_value(T def) {
  return detail::lexical_cast<std::string>(def);
}

//返回字符串"string"
template <>
inline std::string readable_typename<std::string>() {
  return "string";
}

}// ===================================================namespace detail



class cmdline_error : public std::exception {
 public:
  cmdline_error(const std::string &msg) : msg(msg) {}
  ~cmdline_error() throw() {}

  //返回字符串内容
  const char *what() const throw() { return msg.c_str(); }

 private:
  std::string msg;
};


//将传入字符串str转换类型
template <class T>
struct default_reader {
  T operator()(const std::string &str) { return detail::lexical_cast<T>(str); }
};

template <class T>
struct range_reader {
  range_reader(const T &low, const T &high) : low(low), high(high) {}
  //判断传入字符串是否在对应范围内
  T operator()(const std::string &s) const {
    T ret = default_reader<T>()(s);
    if (!(ret >= low && ret <= high))
      throw cmdline::cmdline_error("range_error");
    return ret;
  }
 private:
  T low, high;
};

//设置范围
template <class T>
range_reader<T> range(const T &low, const T &high) {
  return range_reader<T>(low, high);
}

//参数容器结构体
template <class T>
struct oneof_reader {

  //在参数容器中查找字符串并返回
  T operator()(const std::string &s) {
    T ret = default_reader<T>()(s);
    //在alt中没有找到ret,抛出命令行错误(空字符串)
    if (std::find(alt.begin(), alt.end(), ret) == alt.end())  
      throw cmdline_error("");
    return ret;
  }
  //向参数容器中添加内容
  void add(const T &v) { alt.push_back(v); }

 private:
  std::vector<T> alt;
};

//将传入的1个参数添加到一个oneof_reader结构体并返回
template <class T>
oneof_reader<T> oneof(T a1) {
  oneof_reader<T> ret;
  ret.add(a1);
  return ret;
}

//将传入的2个参数添加到一个oneof_reader结构体并返回
template <class T>
oneof_reader<T> oneof(T a1, T a2) {
  oneof_reader<T> ret;
  ret.add(a1);
  ret.add(a2);
  return ret;
}

//将传入的3个参数添加到一个oneof_reader结构体并返回
template <class T>
oneof_reader<T> oneof(T a1, T a2, T a3) {
  oneof_reader<T> ret;
  ret.add(a1);
  ret.add(a2);
  ret.add(a3);
  return ret;
}

//将传入的4个参数添加到一个oneof_reader结构体并返回
template <class T>
oneof_reader<T> oneof(T a1, T a2, T a3, T a4) {
  oneof_reader<T> ret;
  ret.add(a1);
  ret.add(a2);
  ret.add(a3);
  ret.add(a4);
  return ret;
}

//将传入的5个参数添加到一个oneof_reader结构体并返回
template <class T>
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5) {
  oneof_reader<T> ret;
  ret.add(a1);
  ret.add(a2);
  ret.add(a3);
  ret.add(a4);
  ret.add(a5);
  return ret;
}

//将传入的6个参数添加到一个oneof_reader结构体并返回
template <class T>
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6) {
  oneof_reader<T> ret;
  ret.add(a1);
  ret.add(a2);
  ret.add(a3);
  ret.add(a4);
  ret.add(a5);
  ret.add(a6);
  return ret;
}

//将传入的7个参数添加到一个oneof_reader结构体并返回
template <class T>
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7) {
  oneof_reader<T> ret;
  ret.add(a1);
  ret.add(a2);
  ret.add(a3);
  ret.add(a4);
  ret.add(a5);
  ret.add(a6);
  ret.add(a7);
  return ret;
}

//将传入的8个参数添加到一个oneof_reader结构体并返回
template <class T>
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8) {
  oneof_reader<T> ret;
  ret.add(a1);
  ret.add(a2);
  ret.add(a3);
  ret.add(a4);
  ret.add(a5);
  ret.add(a6);
  ret.add(a7);
  ret.add(a8);
  return ret;
}

//将传入的9个参数添加到一个oneof_reader结构体并返回
template <class T>
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9) {
  oneof_reader<T> ret;
  ret.add(a1);
  ret.add(a2);
  ret.add(a3);
  ret.add(a4);
  ret.add(a5);
  ret.add(a6);
  ret.add(a7);
  ret.add(a8);
  ret.add(a9);
  return ret;
}

//将传入的10个参数添加到一个oneof_reader结构体并返回
template <class T>
oneof_reader<T> oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9,
                      T a10) {
  oneof_reader<T> ret;
  ret.add(a1);
  ret.add(a2);
  ret.add(a3);
  ret.add(a4);
  ret.add(a5);
  ret.add(a6);
  ret.add(a7);
  ret.add(a8);
  ret.add(a9);
  ret.add(a10);
  return ret;
}

//解析器
class parser {
 public:
  parser() {}
  ~parser() {
    for (std::map<std::string, option_base *>::iterator p = options.begin();
         p != options.end(); p++)
      delete p->second;
  }

  void add(const std::string &name, char short_name = 0,const std::string &desc = "") {
    //如果name存在
    if (options.count(name))
      throw cmdline_error("multiple definition: " + name);
    options[name] = new option_without_value(name, short_name, desc);
    ordered.push_back(options[name]);
  }

  template <class T>
  void add(const std::string &name, char short_name = 0,const std::string &desc = "", bool need = true, const T def = T()) {
    add(name, short_name, desc, need, def, default_reader<T>());
  }

  template <class T, class F>
  void add(const std::string &name, char short_name = 0,
           const std::string &desc = "", bool need = true, const T def = T(),
           F reader = F()) {
    //如果name存在于option
    if (options.count(name))
      throw cmdline_error("multiple definition: " + name);
    options[name] = new option_with_value_with_reader<T, F>(
        name, short_name, need, def, desc, reader);
    ordered.push_back(options[name]);
  }

  void footer(const std::string &f) { ftr = f; }

  void set_program_name(const std::string &name) { prog_name = name; }

  bool exist(const std::string &name) const {
    //如果name不存在
    if (options.count(name) == 0)
      throw cmdline_error("there is no flag: --" + name);
    return options.find(name)->second->has_set();
  }

  //
  template <class T>
  const T &get(const std::string &name) const {
    //如果name不存在
    if (options.count(name) == 0)
      throw cmdline_error("there is no flag: --" + name);
    //指针类型转换
    const option_with_value<T> *p =
        dynamic_cast<const option_with_value<T> *>(options.find(name)->second);
    if (p == NULL) throw cmdline_error("type mismatch flag '" + name + "'");
    return p->get();
  }

  //返回others
  const std::vector<std::string> &rest() const { return others; }

  //接收字符串的解析函数:负责清除字符串中的双引号和空格
  bool parse(const std::string &arg) {
    std::vector<std::string> args;

    std::string buf;
    bool in_quote = false;
    for (std::string::size_type i = 0; i < arg.length(); i++) {
      
      //字符串中有奇数个",将in_quote设置为真
      if (arg[i] == '\"') {
        in_quote = !in_quote;
        continue;
      }

      //字符串中有空格且空格字符之前有偶数个”字符
      //args中放入空字符串(buf未初始化),占用一个位置
      if (arg[i] == ' ' && !in_quote) {
        args.push_back(buf);
        buf = "";
        continue;
      }

      //在字符串结尾为"\"
      if (arg[i] == '\\') {
        i++;
        if (i >= arg.length()) {
          errors.push_back("unexpected occurrence of '\\' at end of string");
          return false;
        }
      }

      //将字符串各字符拼接到buf中,除双引号和空格符
      buf += arg[i];
    }

    //字符串中有奇数个双引号
    if (in_quote) {
      errors.push_back("quote is not closed");
      return false;
    }

    //将非空buf放入args
    if (buf.length() > 0) args.push_back(buf);

    //打印args中字符串内容
    for (size_t i = 0; i < args.size(); i++)
      std::cout << "\"" << args[i] << "\"" << std::endl;

    //使用解析函数2
    return parse(args);
  }

  //接收字符串容器的解析函数2
  bool parse(const std::vector<std::string> &args) {
    int argc = static_cast<int>(args.size());
    std::vector<const char *> argv(argc);

    for (int i = 0; i < argc; i++) argv[i] = args[i].c_str();

    //使用解析函数3
    return parse(argc, &argv[0]);
  }

  //接收标准程序入口参数的解析函数3
  bool parse(int argc, const char *const argv[]) {
    errors.clear();
    others.clear();

    if (argc < 1) {
      errors.push_back("argument number must be longer than 0");
      return false;
    }
    
    if (prog_name == "") prog_name = argv[0];

    std::map<char, std::string> lookup;
    for (std::map<std::string, option_base *>::iterator p = options.begin();p != options.end(); p++) {
      if (p->first.length() == 0) continue;
      
      char initial = p->second->short_name();
      if (initial) {
        //如果lookup中存在initial
        if (lookup.count(initial) > 0) {
          lookup[initial] = "";
          errors.push_back(std::string("short option '") + initial +
                           "' is ambiguous");
          return false;
        } else
          lookup[initial] = p->first;
      }
    }

    for (int i = 1; i < argc; i++) {
      //如果argv[i]前两个字符为--
      if (strncmp(argv[i], "--", 2) == 0) {
        //查找字符"=",找到的话返回第一次出现的位置
        const char *p = strchr(argv[i] + 2, '=');
        //如果找到
        if (p) {
          std::string name(argv[i] + 2, p);
          std::string val(p + 1);
          set_option(name, val);
        } else {
          //argv[i]前两个字符不是--
          std::string name(argv[i] + 2);
          //如果option中没有name
          if (options.count(name) == 0) {
            errors.push_back("undefined option: --" + name);
            continue;
          }
          if (options[name]->has_value()) {
            if (i + 1 >= argc) {
              errors.push_back("option needs value: --" + name);
              continue;
            } else {
              i++;
              set_option(name, argv[i]);
            }
          } else {
            set_option(name);
          }
        }
      } else if (strncmp(argv[i], "-", 1) == 0) {
        if (!argv[i][1]) continue;
        char last = argv[i][1];
        for (int j = 2; argv[i][j]; j++) {
          last = argv[i][j];
          if (lookup.count(argv[i][j - 1]) == 0) {
            errors.push_back(std::string("undefined short option: -") +
                             argv[i][j - 1]);
            continue;
          }
          if (lookup[argv[i][j - 1]] == "") {
            errors.push_back(std::string("ambiguous short option: -") +
                             argv[i][j - 1]);
            continue;
          }
          set_option(lookup[argv[i][j - 1]]);
        }

        if (lookup.count(last) == 0) {
          errors.push_back(std::string("undefined short option: -") + last);
          continue;
        }
        if (lookup[last] == "") {
          errors.push_back(std::string("ambiguous short option: -") + last);
          continue;
        }

        if (i + 1 < argc && options[lookup[last]]->has_value()) {
          set_option(lookup[last], argv[i + 1]);
          i++;
        } else {
          set_option(lookup[last]);
        }
      } else {
        others.push_back(argv[i]);
      }
    }

    for (std::map<std::string, option_base *>::iterator p = options.begin();
         p != options.end(); p++)
      if (!p->second->valid())
        errors.push_back("need option: --" + std::string(p->first));

    return errors.size() == 0;
  }
  
  void parse_check(const std::string &arg) {
    if (!options.count("help")) add("help", '?', "print this message");
    check(0, parse(arg));
  }

  void parse_check(const std::vector<std::string> &args) {
    if (!options.count("help")) add("help", '?', "print this message");
    check(args.size(), parse(args));
  }

  void parse_check(int argc, char *argv[]) {
    if (!options.count("help")) add("help", '?', "print this message");
    check(argc, parse(argc, argv));
  }

  std::string error() const { return errors.size() > 0 ? errors[0] : ""; }

  std::string error_full() const {
    std::ostringstream oss;
    for (size_t i = 0; i < errors.size(); i++) oss << errors[i] << std::endl;
    return oss.str();
  }

  std::string usage() const {
    std::ostringstream oss;
    oss << "usage: " << prog_name << " ";
    for (size_t i = 0; i < ordered.size(); i++) {
      if (ordered[i]->must()) oss << ordered[i]->short_description() << " ";
    }

    oss << "[options] ... " << ftr << std::endl;
    oss << "options:" << std::endl;

    size_t max_width = 0;
    for (size_t i = 0; i < ordered.size(); i++) {
      max_width = std::max(max_width, ordered[i]->name().length());
    }
    for (size_t i = 0; i < ordered.size(); i++) {
      if (ordered[i]->short_name()) {
        oss << "  -" << ordered[i]->short_name() << ", ";
      } else {
        oss << "      ";
      }

      oss << "--" << ordered[i]->name();
      for (size_t j = ordered[i]->name().length(); j < max_width + 4; j++)
        oss << ' ';
      oss << ordered[i]->description() << std::endl;
    }
    return oss.str();
  }

 private:
  void check(int argc, bool ok) {
    if ((argc == 1 && !ok) || exist("help")) {
      std::cerr << usage();
      exit(0);
    }

    if (!ok) {
      std::cerr << error() << std::endl << usage();
      exit(1);
    }
  }

  void set_option(const std::string &name) {
    if (options.count(name) == 0) {
      errors.push_back("undefined option: --" + name);
      return;
    }
    if (!options[name]->set()) {
      errors.push_back("option needs value: --" + name);
      return;
    }
  }

  void set_option(const std::string &name, const std::string &value) {
    if (options.count(name) == 0) {
      errors.push_back("undefined option: --" + name);
      return;
    }
    if (!options[name]->set(value)) {
      errors.push_back("option value is invalid: --" + name + "=" + value);
      return;
    }
  }

  //基础选项类(抽象类)
  class option_base {
   public:
    virtual ~option_base() {}

    virtual bool has_value() const = 0;
    virtual bool set() = 0;
    virtual bool set(const std::string &value) = 0;
    virtual bool has_set() const = 0;
    virtual bool valid() const = 0;
    virtual bool must() const = 0;

    virtual const std::string &name() const = 0;
    virtual char short_name() const = 0;
    virtual const std::string &description() const = 0;
    virtual std::string short_description() const = 0;
  };

  //无值选项类
  class option_without_value : public option_base {
   public:
    option_without_value(const std::string &name, char short_name,
                         const std::string &desc)
        : nam(name), snam(short_name), desc(desc), has(false) {}
    ~option_without_value() {}

    //无值选项类,返回false
    bool has_value() const { return false; }

    //令has为真,返回true
    bool set() {
      has = true;
      return true;
    }

    //返回false
    bool set(const std::string &) { return false; }

    //返回has
    bool has_set() const { return has; }

    //返回true
    bool valid() const { return true; }

    //返回false
    bool must() const { return false; }

    //返回nam(string)
    const std::string &name() const { return nam; }

    //返回snam
    char short_name() const { return snam; }

    //返回desc
    const std::string &description() const { return desc; }

    //返回--nam
    std::string short_description() const { return "--" + nam; }

   private:
    std::string nam;
    char snam;
    std::string desc;
    bool has;
  };

  //有值选项类
  template <class T>
  class option_with_value : public option_base {
   public:
    option_with_value(const std::string &name, char short_name, bool need,
                      const T &def, const std::string &desc)
        : nam(name),
          snam(short_name),
          need(need),
          has(false),
          def(def),
          actual(def) {
      this->desc = full_description(desc);
    }
    ~option_with_value() {}

    //返回真实值
    const T &get() const { return actual; }

    //返回true
    bool has_value() const { return true; }

    //返回false
    bool set() { return false; }

    bool set(const std::string &value) {
      try {
        actual = read(value);
        has = true;
      } catch (const std::exception &e) {
        return false;
      }
      return true;
    }

    //返回has
    bool has_set() const { return has; }

    bool valid() const {
      if (need && !has) return false;
      return true;
    }

    //返回need
    bool must() const { return need; }

    //返回nam
    const std::string &name() const { return nam; }

    //返回snam
    char short_name() const { return snam; }

    //返回desc
    const std::string &description() const { return desc; }

    //返回简短描述
    std::string short_description() const {
      return "--" + nam + "=" + detail::readable_typename<T>();
    }

   protected:
     //完整描述
    std::string full_description(const std::string &desc) {
      return desc + " (" + detail::readable_typename<T>() +
             (need ? "" : " [=" + detail::default_value<T>(def) + "]") + ")";
    }

    virtual T read(const std::string &s) = 0;

    std::string nam;
    char snam;
    bool need;
    std::string desc;

    bool has;

    //默认值
    T def;
    //真实值
    T actual;
  };

 
  template <class T, class F>
  class option_with_value_with_reader : public option_with_value<T> {
   public:
    option_with_value_with_reader(const std::string &name, char short_name,
                                  bool need, const T def,
                                  const std::string &desc, F reader)
        : option_with_value<T>(name, short_name, need, def, desc),
          reader(reader) {}

   private:

     //将传入字符串赋予reader并返回
    T read(const std::string &s) { return reader(s); }

    F reader;
  };

  //选项
  std::map<std::string, option_base *> options;
  std::vector<option_base *> ordered;
  std::string ftr;

  //程序名称
  std::string prog_name;
  std::vector<std::string> others;

  //错误容器(string)
  std::vector<std::string> errors;
};  //解析器

}  // namespace cmdline

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: stvp_cmdline.exe是STVisual Programmer的命令行工具。通过该工具可以实现对ST微控制器的烧录功能。 -boardname=st-link参数指定了烧录时使用的调试器名称为st-link,表示使用ST-Link调试器。ST-Link是ST公司提供的一种调试和烧录工具,通常用于与STM32系列微控制器进行通信。 -progmode=swim参数指定了烧录模式为swim模式。SWIM(Single Wire Interface Module)是ST公司专为STM8系列微控制器设计的一种调试和烧录接口模式。通过SWIM接口,可以实现对STM8微控制器的烧录和调试。 -port=usb参数指定了与调试器连接的端口为USB端口。表示调试器通过USB接口与计算机进行通信。 综上所述,stvp_cmdline.exe -boardname=st-link -progmode=swim -port=usb命令的意思是使用ST-Link调试器,采用swim模式进行烧录,通过USB端口与计算机进行通信。这条命令可以通过命令行工具来实现对ST微控制器的烧录功能。 ### 回答2: stvp_cmdline.exe -boardname=st-link -progmode=swim -port=usb 是一个命令行工具,用于与ST-LINK调试器进行通信,并进行编程操作。具体含义如下: -boardname=st-link:指定使用的调试器板名称为ST-LINK,表示与ST-LINK调试器进行通信。 -progmode=swim:指定编程模式为SWIM模式,表示使用单线模式进行通信和编程。SWIM(Single Wire Interface Module)是STMicroelectronics提供的编程接口,通过单一的引脚实现通信和编程操作。 -port=usb:指定通信端口为USB端口,表示通过USB接口连接ST-LINK调试器和目标设备进行通信。 通过执行以上命令,可以启动stvp_cmdline.exe,并使用ST-LINK调试器连接目标设备,以便进行编程操作。 ### 回答3: stvp_cmdline.exe -boardname=st-link -progmode=swim -port=usb 是一个命令行工具,用于与ST-LINK调试器进行通信并下载程序。 -boardname=st-link 是指定调试器板名称为ST-LINK,这表示我们要和ST-LINK调试器进行交互。 -progmode=swim 是指定编程模式为SWIM(Single Wire Interface Module)。SWIM是ST-LINK调试器和STM8微控制器之间的一种通信接口,用于编程和调试。 -port=usb 是指定通信端口为USB。这意味着我们将通过USB端口与ST-LINK调试器进行通信。 该命令的目的是使用stvp_cmdline.exe来控制ST-LINK调试器,通过SWIM接口以USB通信方式下载程序或进行其他编程和调试操作。 这个命令可以用于在开发过程中将程序下载到目标设备上。通过ST-LINK调试器,我们可以将编译好的程序文件通过SWIM接口传输到目标设备上,实现程序的烧录和调试。使用USB端口进行通信,方便快捷。 总结起来,stvp_cmdline.exe -boardname=st-link -progmode=swim -port=usb 是一个用于控制ST-LINK调试器,通过SWIM接口和USB通信方式进行程序下载和调试的命令行工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值