CMD.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
  3. *
  4. * This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
  5. *
  6. * Use of this source code is governed by MIT license that can be found in the
  7. * LICENSE file in the root of the source tree. All contributing project authors
  8. * may be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #ifndef SRC_UTIL_CMD_H_
  11. #define SRC_UTIL_CMD_H_
  12. #include <map>
  13. #include <mutex>
  14. #include <string>
  15. #include <memory>
  16. #include <vector>
  17. #include <iostream>
  18. #include <functional>
  19. #include "mini.h"
  20. namespace toolkit{
  21. class Option {
  22. public:
  23. using OptionHandler = std::function<bool(const std::shared_ptr<std::ostream> &stream, const std::string &arg)>;
  24. enum ArgType {
  25. ArgNone = 0,//no_argument,
  26. ArgRequired = 1,//required_argument,
  27. ArgOptional = 2,//optional_argument
  28. };
  29. Option() = default;
  30. Option(char short_opt, const char *long_opt, enum ArgType type, const char *default_value, bool must_exist,
  31. const char *des, const OptionHandler &cb) {
  32. _short_opt = short_opt;
  33. _long_opt = long_opt;
  34. _type = type;
  35. if (type != ArgNone) {
  36. if (default_value) {
  37. _default_value = std::make_shared<std::string>(default_value);
  38. }
  39. if (!_default_value && must_exist) {
  40. _must_exist = true;
  41. }
  42. }
  43. _des = des;
  44. _cb = cb;
  45. }
  46. bool operator()(const std::shared_ptr<std::ostream> &stream, const std::string &arg) {
  47. return _cb ? _cb(stream, arg) : true;
  48. }
  49. private:
  50. friend class OptionParser;
  51. bool _must_exist = false;
  52. char _short_opt;
  53. enum ArgType _type;
  54. std::string _des;
  55. std::string _long_opt;
  56. OptionHandler _cb;
  57. std::shared_ptr<std::string> _default_value;
  58. };
  59. class OptionParser {
  60. public:
  61. using OptionCompleted = std::function<void(const std::shared_ptr<std::ostream> &, mINI &)>;
  62. OptionParser(const OptionCompleted &cb = nullptr, bool enable_empty_args = true) {
  63. _on_completed = cb;
  64. _enable_empty_args = enable_empty_args;
  65. _helper = Option('h', "help", Option::ArgNone, nullptr, false, "打印此信息",
  66. [this](const std::shared_ptr<std::ostream> &stream,const std::string &arg)->bool {
  67. static const char *argsType[] = {"无参", "有参", "选参"};
  68. static const char *mustExist[] = {"选填", "必填"};
  69. static std::string defaultPrefix = "默认:";
  70. static std::string defaultNull = "null";
  71. std::stringstream printer;
  72. size_t maxLen_longOpt = 0;
  73. auto maxLen_default = defaultNull.size();
  74. for (auto &pr : _map_options) {
  75. auto &opt = pr.second;
  76. if (opt._long_opt.size() > maxLen_longOpt) {
  77. maxLen_longOpt = opt._long_opt.size();
  78. }
  79. if (opt._default_value) {
  80. if (opt._default_value->size() > maxLen_default) {
  81. maxLen_default = opt._default_value->size();
  82. }
  83. }
  84. }
  85. for (auto &pr : _map_options) {
  86. auto &opt = pr.second;
  87. //打印短参和长参名
  88. if (opt._short_opt) {
  89. printer << " -" << opt._short_opt << " --" << opt._long_opt;
  90. } else {
  91. printer << " " << " " << " --" << opt._long_opt;
  92. }
  93. for (size_t i = 0; i < maxLen_longOpt - opt._long_opt.size(); ++i) {
  94. printer << " ";
  95. }
  96. //打印是否有参
  97. printer << " " << argsType[opt._type];
  98. //打印默认参数
  99. std::string defaultValue = defaultNull;
  100. if (opt._default_value) {
  101. defaultValue = *opt._default_value;
  102. }
  103. printer << " " << defaultPrefix << defaultValue;
  104. for (size_t i = 0; i < maxLen_default - defaultValue.size(); ++i) {
  105. printer << " ";
  106. }
  107. //打印是否必填参数
  108. printer << " " << mustExist[opt._must_exist];
  109. //打印描述
  110. printer << " " << opt._des << std::endl;
  111. }
  112. throw std::invalid_argument(printer.str());
  113. });
  114. (*this) << _helper;
  115. }
  116. OptionParser &operator<<(Option &&option) {
  117. int index = 0xFF + (int) _map_options.size();
  118. if (option._short_opt) {
  119. _map_char_index.emplace(option._short_opt, index);
  120. }
  121. _map_options.emplace(index, std::forward<Option>(option));
  122. return *this;
  123. }
  124. OptionParser &operator<<(const Option &option) {
  125. int index = 0xFF + (int) _map_options.size();
  126. if (option._short_opt) {
  127. _map_char_index.emplace(option._short_opt, index);
  128. }
  129. _map_options.emplace(index, option);
  130. return *this;
  131. }
  132. void delOption(const char *key) {
  133. for (auto &pr : _map_options) {
  134. if (pr.second._long_opt == key) {
  135. if (pr.second._short_opt) {
  136. _map_char_index.erase(pr.second._short_opt);
  137. }
  138. _map_options.erase(pr.first);
  139. break;
  140. }
  141. }
  142. }
  143. void operator ()(mINI &all_args, int argc, char *argv[], const std::shared_ptr<std::ostream> &stream);
  144. private:
  145. bool _enable_empty_args;
  146. Option _helper;
  147. std::map<char, int> _map_char_index;
  148. std::map<int, Option> _map_options;
  149. OptionCompleted _on_completed;
  150. };
  151. class CMD : public mINI {
  152. public:
  153. virtual ~CMD() = default;
  154. virtual const char *description() const {
  155. return "description";
  156. }
  157. void operator()(int argc, char *argv[], const std::shared_ptr<std::ostream> &stream = nullptr) {
  158. this->clear();
  159. std::shared_ptr<std::ostream> coutPtr(&std::cout, [](std::ostream *) {});
  160. (*_parser)(*this, argc, argv, stream ? stream : coutPtr);
  161. }
  162. bool hasKey(const char *key) {
  163. return this->find(key) != this->end();
  164. }
  165. std::vector<variant> splitedVal(const char *key, const char *delim = ":") {
  166. std::vector<variant> ret;
  167. auto &val = (*this)[key];
  168. split(val, delim, ret);
  169. return ret;
  170. }
  171. void delOption(const char *key) {
  172. if (_parser) {
  173. _parser->delOption(key);
  174. }
  175. }
  176. protected:
  177. std::shared_ptr<OptionParser> _parser;
  178. private:
  179. void split(const std::string &s, const char *delim, std::vector<variant> &ret) {
  180. size_t last = 0;
  181. auto index = s.find(delim, last);
  182. while (index != std::string::npos) {
  183. if (index - last > 0) {
  184. ret.push_back(s.substr(last, index - last));
  185. }
  186. last = index + strlen(delim);
  187. index = s.find(delim, last);
  188. }
  189. if (s.size() - last > 0) {
  190. ret.push_back(s.substr(last));
  191. }
  192. }
  193. };
  194. class CMDRegister {
  195. public:
  196. static CMDRegister &Instance();
  197. void clear() {
  198. std::lock_guard<std::recursive_mutex> lck(_mtx);
  199. _cmd_map.clear();
  200. }
  201. void registCMD(const char *name, const std::shared_ptr<CMD> &cmd) {
  202. std::lock_guard<std::recursive_mutex> lck(_mtx);
  203. _cmd_map.emplace(name, cmd);
  204. }
  205. void unregistCMD(const char *name) {
  206. std::lock_guard<std::recursive_mutex> lck(_mtx);
  207. _cmd_map.erase(name);
  208. }
  209. std::shared_ptr<CMD> operator[](const char *name) {
  210. std::lock_guard<std::recursive_mutex> lck(_mtx);
  211. auto it = _cmd_map.find(name);
  212. if (it == _cmd_map.end()) {
  213. throw std::invalid_argument(std::string("CMD not existed: ") + name);
  214. }
  215. return it->second;
  216. }
  217. void operator()(const char *name, int argc, char *argv[], const std::shared_ptr<std::ostream> &stream = nullptr) {
  218. auto cmd = (*this)[name];
  219. if (!cmd) {
  220. throw std::invalid_argument(std::string("CMD not existed: ") + name);
  221. }
  222. (*cmd)(argc, argv, stream);
  223. }
  224. void printHelp(const std::shared_ptr<std::ostream> &streamTmp = nullptr) {
  225. auto stream = streamTmp;
  226. if (!stream) {
  227. stream.reset(&std::cout, [](std::ostream *) {});
  228. }
  229. std::lock_guard<std::recursive_mutex> lck(_mtx);
  230. size_t maxLen = 0;
  231. for (auto &pr : _cmd_map) {
  232. if (pr.first.size() > maxLen) {
  233. maxLen = pr.first.size();
  234. }
  235. }
  236. for (auto &pr : _cmd_map) {
  237. (*stream) << " " << pr.first;
  238. for (size_t i = 0; i < maxLen - pr.first.size(); ++i) {
  239. (*stream) << " ";
  240. }
  241. (*stream) << " " << pr.second->description() << std::endl;
  242. }
  243. }
  244. void operator()(const std::string &line, const std::shared_ptr<std::ostream> &stream = nullptr) {
  245. if (line.empty()) {
  246. return;
  247. }
  248. std::vector<char *> argv;
  249. size_t argc = getArgs((char *) line.data(), argv);
  250. if (argc == 0) {
  251. return;
  252. }
  253. std::string cmd = argv[0];
  254. std::lock_guard<std::recursive_mutex> lck(_mtx);
  255. auto it = _cmd_map.find(cmd);
  256. if (it == _cmd_map.end()) {
  257. std::stringstream ss;
  258. ss << " 未识别的命令\"" << cmd << "\",输入 \"help\" 获取帮助.";
  259. throw std::invalid_argument(ss.str());
  260. }
  261. (*it->second)((int) argc, &argv[0], stream);
  262. }
  263. private:
  264. size_t getArgs(char *buf, std::vector<char *> &argv) {
  265. size_t argc = 0;
  266. bool start = false;
  267. auto len = strlen(buf);
  268. for (size_t i = 0; i < len; ++i) {
  269. if (buf[i] != ' ' && buf[i] != '\t' && buf[i] != '\r' && buf[i] != '\n') {
  270. if (!start) {
  271. start = true;
  272. if (argv.size() < argc + 1) {
  273. argv.resize(argc + 1);
  274. }
  275. argv[argc++] = buf + i;
  276. }
  277. } else {
  278. buf[i] = '\0';
  279. start = false;
  280. }
  281. }
  282. return argc;
  283. }
  284. private:
  285. std::recursive_mutex _mtx;
  286. std::map<std::string, std::shared_ptr<CMD> > _cmd_map;
  287. };
  288. //帮助命令(help),该命令默认已注册
  289. class CMD_help : public CMD {
  290. public:
  291. CMD_help() {
  292. _parser = std::make_shared<OptionParser>([](const std::shared_ptr<std::ostream> &stream, mINI &) {
  293. CMDRegister::Instance().printHelp(stream);
  294. });
  295. }
  296. const char *description() const override {
  297. return "打印帮助信息";
  298. }
  299. };
  300. class ExitException : public std::exception {};
  301. //退出程序命令(exit),该命令默认已注册
  302. class CMD_exit : public CMD {
  303. public:
  304. CMD_exit() {
  305. _parser = std::make_shared<OptionParser>([](const std::shared_ptr<std::ostream> &, mINI &) {
  306. throw ExitException();
  307. });
  308. }
  309. const char *description() const override {
  310. return "退出shell";
  311. }
  312. };
  313. //退出程序命令(quit),该命令默认已注册
  314. #define CMD_quit CMD_exit
  315. //清空屏幕信息命令(clear),该命令默认已注册
  316. class CMD_clear : public CMD {
  317. public:
  318. CMD_clear() {
  319. _parser = std::make_shared<OptionParser>([this](const std::shared_ptr<std::ostream> &stream, mINI &args) {
  320. clear(stream);
  321. });
  322. }
  323. const char *description() const {
  324. return "清空屏幕输出";
  325. }
  326. private:
  327. void clear(const std::shared_ptr<std::ostream> &stream) {
  328. (*stream) << "\x1b[2J\x1b[H";
  329. stream->flush();
  330. }
  331. };
  332. #define GET_CMD(name) (*(CMDRegister::Instance()[name]))
  333. #define CMD_DO(name,...) (*(CMDRegister::Instance()[name]))(__VA_ARGS__)
  334. #define REGIST_CMD(name) CMDRegister::Instance().registCMD(#name,std::make_shared<CMD_##name>());
  335. }//namespace toolkit
  336. #endif /* SRC_UTIL_CMD_H_ */