libcopp 2.3.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cmd_option.h
Go to the documentation of this file.
1#ifndef UTIL_CLI_CMDOPTION_H
2#define UTIL_CLI_CMDOPTION_H
3
4#pragma once
5
22#include <assert.h>
23#include <cstdio>
24#include <exception>
25#include <set>
26
27#include <map>
28#include <memory>
29#include <ostream>
30#include <sstream>
31#include <vector>
32
33#include "std/ref.h"
34
35// 载入绑定器
36#include "cli/cmd_option_bind.h"
39#include "cmd_option_list.h"
40
41#include "shell_font.h"
42
43namespace util {
44namespace cli {
45// 标准指令处理函数(无返回值,参数为选项的映射表)
46// void function_name (cmd_option_list&, [参数]); // 函数参数可选
47// void function_name (callback_param, [参数]); // 函数参数可选
48
49// 值类型
50typedef std::shared_ptr<cli::cmd_option_value> value_type;
51
65template <typename TCmdStr>
67 public:
68 typedef unsigned char uc_t;
72 typedef std::shared_ptr<binder::cmd_option_bind_base> func_ptr_t;
73 typedef std::map<TCmdStr, func_ptr_t> funmap_type;
74
75 protected:
76 static short map_value_[256]; // 记录不同字符的映射关系
77 static char trans_value_[256]; // 记录特殊转义字符
78
79 funmap_type callback_funcs_; // 记录命令的映射函数
80 funmap_type callback_children_; // 子命令组额外索引
83
89 void run_cmd(const TCmdStr &cmd_content, callback_param params) const {
90 typename funmap_type::const_iterator iter = callback_funcs_.find(cmd_content);
91
92 // 如果是顶层调用则添加根指令调用栈
93 if (params.get_cmd_array().empty()) {
94 params.append_cmd(ROOT_NODE_CMD, std::const_pointer_cast<binder::cmd_option_bind_base>(shared_from_this()));
95 }
96
97 if (iter == callback_funcs_.end()) {
98 // 内定命令不报“找不到指令”错
99 if (cmd_content == "@OnDefault") return;
100
101 iter = callback_funcs_.find("@OnError"); // 查找错误处理函数
102 if (iter != callback_funcs_.end()) {
103 // 错误附加内容(错误内容)
104 params.add("@ErrorMsg=Command Invalid");
105 params.append_cmd(cmd_content.c_str(), iter->second); // 添加当前指令调用栈
106
107 (*iter->second)(params);
108 }
109 return;
110 }
111
112 // 添加当前指令调用栈
113 params.append_cmd(cmd_content.c_str(), iter->second);
114 (*iter->second)(params);
115 }
116
121 std::cout << "Help:" << std::endl;
122 std::cout << (*this);
123 }
124
125 public:
126 void list_help_msg(help_list_t &msg, const std::string &prefix) const {
127 for (typename funmap_type::const_iterator iter = callback_funcs_.begin(); iter != callback_funcs_.end(); ++iter) {
128 if (iter->first.empty() || '@' == iter->first[0]) {
129 continue;
130 }
131
132 help_list_t::iterator iter_m;
133 help_msg_t *obj;
134 for (iter_m = msg.begin(), obj = nullptr; iter_m != msg.end(); ++iter_m) {
135 if ((*iter_m).binded_obj == iter->second) {
136 obj = &(*iter_m);
137 break;
138 }
139 }
140
141 // all children do not make a help_msg_t
142 if (callback_children_.find(iter->first) != callback_children_.end()) {
143#if defined(LIBCOPP_MACRO_ENABLE_RTTI) && LIBCOPP_MACRO_ENABLE_RTTI
144 self_type *child = dynamic_cast<self_type *>(iter->second.get());
145#else
146 self_type *child = static_cast<self_type *>(iter->second.get());
147#endif
148 assert(child);
149 child->list_help_msg(msg, (prefix + " ") + iter->first.c_str());
150 continue;
151 }
152
153 if (nullptr == obj) {
154 msg.push_back(help_msg_t());
155 obj = &msg.back();
156 assert(obj);
157 obj->binded_obj = iter->second;
158 obj->description = iter->second->get_help_msg();
159 }
160
161 // any string to std::string
162 std::string full_cmd;
163 full_cmd.reserve(prefix.capacity() + iter->first.capacity());
164 if (!prefix.empty()) {
165 full_cmd = prefix;
166 full_cmd += " ";
167 }
168 full_cmd += iter->first.c_str();
169 obj->cmd_paths.push_back(full_cmd);
170 }
171 }
172
173 static std::ostream &dump(std::ostream &os, const self_type &self, const std::string &prefix) {
174 help_list_t msgs;
175 self.list_help_msg(msgs, "");
176
177 size_t cmd_padding = 4;
178 // sort all commands of the same callback
179 for (help_list_t::iterator iter = msgs.begin(); iter != msgs.end(); ++iter) {
180 std::sort((*iter).cmd_paths.begin(), (*iter).cmd_paths.end());
181 std::stringstream ss;
182 bool not_first = false;
183 for (std::vector<std::string>::iterator cmd_it = (*iter).cmd_paths.begin(); cmd_it != (*iter).cmd_paths.end();
184 ++cmd_it) {
185 if (not_first) {
186 ss << ", ";
187 }
188 ss << *cmd_it;
189 not_first = true;
190 }
191
192 (*iter).all_cmds = ss.str();
193 if ((*iter).all_cmds.size() >= cmd_padding) {
194 cmd_padding = (((*iter).all_cmds.size() >> 2) + 1) << 2;
195 }
196 }
197
198 std::sort(msgs.begin(), msgs.end(), binder::cmd_option_bind_base::sort_by_all_cmds);
199
200 for (help_list_t::iterator iter = msgs.begin(); iter != msgs.end(); ++iter) {
201 shell_stream ss(os);
202
203 ss().open(self.help_cmd_style_) << prefix << (*iter).all_cmds;
204 if ((*iter).all_cmds.size() < cmd_padding) {
205 std::string padding_space;
206 padding_space.resize(cmd_padding - (*iter).all_cmds.size(), ' ');
207 ss() << padding_space;
208 }
209 ss().open(self.help_description_style_) << (*iter).description << std::endl;
210 }
211
212 return os;
213 }
214
215 friend std::ostream &operator<<(std::ostream &os, const self_type &self) { return dump(os, self, std::string()); }
216
217 std::ostream &dump(std::ostream &os, const std::string &prefix) { return dump(os, *this, prefix); }
218
225 static const char *get_segment(const char *begin_str, std::string &val) {
226 val.clear();
227 char flag; // 字符串开闭字符
228
229 // 去除分隔符前缀
230 while (*begin_str && (map_value_[(uc_t)*begin_str] & SPLITCHAR)) ++begin_str;
231
232 while (*begin_str && !(map_value_[(uc_t)*begin_str] & SPLITCHAR)) {
233 if (!(map_value_[(uc_t)*begin_str] & STRINGSYM)) {
234 val += *begin_str;
235 ++begin_str;
236 } else {
237 flag = *begin_str;
238 ++begin_str;
239
240 while (*begin_str && *begin_str != flag) {
241 char cur_byte = *begin_str;
242 if (map_value_[(uc_t)*begin_str] & TRANSLATE) {
243 if (*(begin_str + 1)) {
244 ++begin_str;
245 cur_byte = trans_value_[(uc_t)*begin_str];
246 }
247 }
248
249 val += cur_byte;
250 ++begin_str;
251 }
252
253 ++begin_str;
254 break; // 字符串结束后参数结束
255 }
256 }
257
258 // 去除分隔符后缀
259 while (*begin_str && (map_value_[(uc_t)*begin_str] & SPLITCHAR)) ++begin_str;
260 return begin_str;
261 }
262
268 static std::vector<std::string> split_cmd(const char *begin_str) {
269 std::vector<std::string> ret;
270 for (const char *begin_ptr = begin_str; (*begin_ptr);) {
271 std::string cmd_content;
272 // 去除命令分隔符前缀
273 while ((*begin_ptr) && (map_value_[(uc_t)*begin_ptr] & CMDSPLIT)) ++begin_ptr;
274
275 // 分离命令
276 while ((*begin_ptr) && !(map_value_[(uc_t)*begin_ptr] & CMDSPLIT)) {
277 cmd_content.push_back(*begin_ptr);
278 ++begin_ptr;
279 }
280
281 if (cmd_content.size() > 0) ret.push_back(cmd_content);
282 }
283
284 return ret;
285 }
286
287 private:
292 : help_cmd_style_(shell_font_style::SHELL_FONT_COLOR_YELLOW |
293 static_cast<int>(shell_font_style::SHELL_FONT_SPEC_BOLD)),
295 // 如果已初始化则跳过
296 if (map_value_[(uc_t)' '] & SPLITCHAR) return;
297
298 // 分隔符
299 map_value_[(uc_t)' '] = map_value_[(uc_t)'\t'] = map_value_[(uc_t)'\r'] = map_value_[(uc_t)'\n'] = SPLITCHAR;
300 // 字符串开闭符
301 map_value_[(uc_t)'\''] = map_value_[(uc_t)'\"'] = STRINGSYM;
302 // 转义标记符
303 map_value_[(uc_t)'\\'] = TRANSLATE;
304 // 指令分隔符
305 map_value_[(uc_t)' '] |= CMDSPLIT;
306 map_value_[(uc_t)','] = map_value_[(uc_t)';'] = CMDSPLIT;
307
308 // 转义字符设置
309 for (int i = 0; i < 256; ++i) trans_value_[i] = static_cast<char>(i);
310
311 trans_value_[(uc_t)'0'] = '\0';
312 trans_value_[(uc_t)'a'] = '\a';
313 trans_value_[(uc_t)'b'] = '\b';
314 trans_value_[(uc_t)'f'] = '\f';
315 trans_value_[(uc_t)'r'] = '\r';
316 trans_value_[(uc_t)'n'] = '\n';
317 trans_value_[(uc_t)'t'] = '\t';
318 trans_value_[(uc_t)'v'] = '\v';
319 trans_value_[(uc_t)'\\'] = '\\';
320 trans_value_[(uc_t)'\''] = '\'';
321 trans_value_[(uc_t)'\"'] = '\"';
322 }
323
324 public:
325 typedef std::shared_ptr<cmd_option_bind> ptr_type;
326 static ptr_type create() { return ptr_type(new cmd_option_bind()); }
327
332 std::shared_ptr<std::vector<const char *> > get_cmd_names() const {
333 typename funmap_type::const_iterator iter = callback_funcs_.begin();
334 std::shared_ptr<std::vector<const char *> > ret_ptr =
335 std::shared_ptr<std::vector<const char *> >(new std::vector<const char *>());
336 while (iter != callback_funcs_.end()) {
337 ret_ptr->push_back(iter->first.c_str());
338 ++iter;
339 }
340 return ret_ptr;
341 }
342
348 std::shared_ptr<binder::cmd_option_bind_base> get_binded_cmd(const char *cmd_name) const {
349 typename funmap_type::const_iterator iter = callback_funcs_.find(cmd_name);
350 if (iter == callback_funcs_.end()) return std::shared_ptr<binder::cmd_option_bind_base>();
351 return iter->second;
352 }
353
354 size_t size() const { return callback_funcs_.size(); }
355 size_t empty() const { return callback_funcs_.empty(); }
356 const funmap_type &get_all() const { return callback_funcs_; }
357
358 size_t children_size() const { return callback_children_.size(); }
359 size_t children_empty() const { return callback_children_.empty(); }
361
362 int get_help_cmd_style() const { return help_cmd_style_; }
363 void set_help_cmd_style(int style) { help_cmd_style_ = style; }
366
381 void start(callback_param args, bool is_single_cmd = false) const {
382 int argv = static_cast<int>(args.get_params_number());
383 cmd_option_list cmd_args;
384 TCmdStr cmd_content = is_single_cmd ? "@OnError" : "@OnDefault";
385 for (int i = -1; i < argv;) {
386 ++i;
387 cmd_args.clear();
388 cmd_args.load_cmd_array(args.get_cmd_array());
389 cmd_args.set_ext_param(args.get_ext_param());
390
391 for (; i < argv; ++i) {
392 // 把所有的非指令字符串设为指令参数
393 if (callback_funcs_.find(args[static_cast<size_t>(i)]->to_string()) == callback_funcs_.end()) {
394 cmd_args.add(args[static_cast<size_t>(i)]->to_string());
395 } else {
396 // 如果是单指令且有未知参数则分发@OnError错误处理
397 if (is_single_cmd && cmd_args.get_params_number() > 0) {
398 run_cmd(cmd_content, cmd_args);
399 cmd_args.clear();
400 cmd_args.load_cmd_array(args.get_cmd_array());
401 cmd_args.set_ext_param(args.get_ext_param());
402 }
403
404 // 追加所有参数,执行单指令
405 if (is_single_cmd) {
406 cmd_content = TCmdStr(args[static_cast<size_t>(i)]->to_cpp_string().c_str(),
407 args[static_cast<size_t>(i)]->to_cpp_string().size());
408 for (++i; i < argv; ++i) cmd_args.add(args[static_cast<size_t>(i)]->to_string());
409 }
410 break;
411 }
412 }
413
414 run_cmd(cmd_content, cmd_args);
415 if (i >= argv) break;
416 cmd_content = TCmdStr(args[static_cast<size_t>(i)]->to_cpp_string().c_str(),
417 args[static_cast<size_t>(i)]->to_cpp_string().size());
418 }
419 }
420
428 inline void start(int argv, const char *argc[], bool is_single_cmd = false, void *ext_param = nullptr) const {
429 cmd_option_list copt_list(argv, argc);
430 copt_list.set_ext_param(ext_param);
431
432 start(copt_list, is_single_cmd);
433 }
434
442 inline void start(int argv, char *argc[], bool is_single_cmd = false, void *ext_param = nullptr) const {
443 typedef const char *conv_char_t;
444
445 start(argv, const_cast<conv_char_t *>(argc), is_single_cmd, ext_param);
446 }
447
454 inline void start(const std::vector<std::string> &cmds, bool is_single_cmd = false, void *ext_param = nullptr) const {
455 cmd_option_list copt_list(cmds);
456 copt_list.set_ext_param(ext_param);
457
458 start(copt_list, is_single_cmd);
459 }
460
466 void start(const char *cmd_content, bool is_single_cmd = false, void *ext_param = nullptr) const {
467 cmd_option_list cmds;
468 std::string seg;
469
470 // 分离指令
471 while (*cmd_content) {
472 cmd_content = get_segment(cmd_content, seg);
473 cmds.add(seg.c_str());
474 }
475
476 cmds.set_ext_param(ext_param);
477
478 start(cmds, is_single_cmd);
479 }
480
486 inline void start(const std::string &cmd_content, bool is_single_cmd = false, void *ext_param = nullptr) const {
487 start(cmd_content.c_str(), is_single_cmd, ext_param);
488 }
489
494 inline void unbind_cmd(const std::string &cmd_content) {
495 TCmdStr cmd_obj = TCmdStr(cmd_content.c_str(), cmd_content.size());
496 callback_funcs_.erase(cmd_obj);
497 callback_children_.erase(cmd_content);
498 }
499
503 inline void unbind_all_cmd() {
504 callback_funcs_.clear();
505 callback_children_.clear();
506 }
507
512 inline std::shared_ptr<binder::cmd_option_bindt<
514 binder::cmd_option_bind_param_list<cmd_option_bind<TCmdStr> *> > >
515 bind_help_cmd(const char *help_cmd_content) {
516 return bind_cmd(help_cmd_content, &cmd_option_bind<TCmdStr>::on_help, this);
517 }
518
522 void operator()(callback_param arg) override {
523 // 响应@OnCallFunc事件
524 typename funmap_type::const_iterator iter = callback_funcs_.find("@OnCallFunc");
525 if (iter != callback_funcs_.end()) (*iter->second)(arg);
526
527 // 重新执行指令集, 进入子结构的一定是单指令
528 start(arg, true);
529 }
530
535 std::string get_help_msg(const char *prefix_data = "") const override {
536 std::set<typename funmap_type::mapped_type> set_obj;
537 std::string help_msg_content;
538
539 for (typename funmap_type::const_iterator iter = callback_funcs_.begin(); iter != callback_funcs_.end(); ++iter) {
540 // 删除重复的引用对象
541 if (set_obj.find(iter->second) != set_obj.end()) continue;
542
543 // 跳过内置命令
544 if ('@' == *iter->first.c_str()) continue;
545
546 set_obj.insert(iter->second);
547 std::string cmd_help = iter->second->get_help_msg((prefix_data + help_msg_).c_str());
548
549 if (cmd_help.size() > 0) {
550 if (help_msg_content.size() > 0 && '\n' != *help_msg_content.rbegin()) help_msg_content += "\r\n";
551 help_msg_content += cmd_help;
552 }
553 }
554 return help_msg_content;
555 }
556
574 template <typename _F,
575 typename... _Args> // 绑定函数(_Arg:参数[注意值的复制发生在本函数执行时], _R: 绑定函数返回值类型)
576 std::shared_ptr<binder::cmd_option_bindt<typename binder::maybe_wrap_member_pointer<_F>::caller_type,
578 bind_cmd(const std::string &cmd_content, _F raw_fn, _Args... args) {
579 typedef binder::cmd_option_bind_param_list<_Args...> list_type;
580 typedef typename binder::maybe_wrap_member_pointer<_F>::caller_type caller_type;
581 typedef std::shared_ptr<binder::cmd_option_bindt<caller_type, list_type> > obj_type;
582
583 obj_type fn =
584 obj_type(new binder::cmd_option_bindt<caller_type, list_type>(caller_type(raw_fn), list_type(args...)));
585
586 std::vector<std::string> cmds = split_cmd(cmd_content.c_str());
587 for (std::vector<std::string>::size_type index = 0; index < cmds.size(); ++index) {
588 TCmdStr cmd_obj = TCmdStr(cmds[index].c_str(), cmds[index].size());
589 callback_funcs_[cmd_obj] = fn;
590 }
591
592 return fn;
593 }
594
603 std::shared_ptr<binder::cmd_option_bind_base> bind_child_cmd(
604 const std::string cmd_content, std::shared_ptr<binder::cmd_option_bind_base> base_node) {
605 std::vector<std::string> cmds = split_cmd(cmd_content.c_str());
606 for (std::vector<std::string>::size_type index = 0; index < cmds.size(); ++index) {
607 TCmdStr cmd_obj = TCmdStr(cmds[index].c_str(), cmds[index].size());
608 callback_funcs_[cmd_obj] = base_node;
609 callback_children_[cmd_obj] = base_node;
610 }
611
612 return base_node;
613 }
614
615 std::shared_ptr<binder::cmd_option_bind_base> bind_child_cmd(const std::string cmd_content, ptr_type cmd_opt) {
616#if defined(LIBATFRAME_UTILS_ENABLE_RTTI) && LIBATFRAME_UTILS_ENABLE_RTTI
617 std::shared_ptr<binder::cmd_option_bind_base> base_node =
618 std::dynamic_pointer_cast<binder::cmd_option_bind_base>(cmd_opt);
619#else
620 std::shared_ptr<binder::cmd_option_bind_base> base_node =
621 std::static_pointer_cast<binder::cmd_option_bind_base>(cmd_opt);
622#endif
623 std::vector<std::string> cmds = split_cmd(cmd_content.c_str());
624 for (std::vector<std::string>::size_type index = 0; index < cmds.size(); ++index) {
625 TCmdStr cmd_obj = TCmdStr(cmds[index].c_str(), cmds[index].size());
626 callback_funcs_[cmd_obj] = base_node;
627 callback_children_[cmd_obj] = base_node;
628 }
629
630 return base_node;
631 }
632};
633
634template <typename Ty>
635short cmd_option_bind<Ty>::map_value_[256] = {0};
636
637template <typename Ty>
639
640// 类型重定义
643} // namespace cli
644} // namespace util
645#endif /* CMDOPTION_H_ */
std::vector< help_msg_t > help_list_t
static bool sort_by_all_cmds(const help_msg_t &l, const help_msg_t &r)
size_t children_size() const
Definition cmd_option.h:358
cmd_option_bind< TCmdStr > self_type
Definition cmd_option.h:69
void start(const std::vector< std::string > &cmds, bool is_single_cmd=false, void *ext_param=nullptr) const
Definition cmd_option.h:454
void set_help_cmd_style(int style)
Definition cmd_option.h:363
std::shared_ptr< std::vector< const char * > > get_cmd_names() const
Definition cmd_option.h:332
std::shared_ptr< cmd_option_bind > ptr_type
Definition cmd_option.h:325
std::shared_ptr< binder::cmd_option_bindt< typename binder::maybe_wrap_member_pointer< _F >::caller_type, binder::cmd_option_bind_param_list< _Args... > > > bind_cmd(const std::string &cmd_content, _F raw_fn, _Args... args)
Definition cmd_option.h:578
void operator()(callback_param arg) override
Definition cmd_option.h:522
void on_help(callback_param)
Definition cmd_option.h:120
void run_cmd(const TCmdStr &cmd_content, callback_param params) const
Definition cmd_option.h:89
void start(const char *cmd_content, bool is_single_cmd=false, void *ext_param=nullptr) const
Definition cmd_option.h:466
const funmap_type & get_all() const
Definition cmd_option.h:356
void list_help_msg(help_list_t &msg, const std::string &prefix) const
Definition cmd_option.h:126
size_t children_empty() const
Definition cmd_option.h:359
std::shared_ptr< binder::cmd_option_bind_base > get_binded_cmd(const char *cmd_name) const
Definition cmd_option.h:348
binder::cmd_option_bind_base::help_list_t help_list_t
Definition cmd_option.h:71
static const char * get_segment(const char *begin_str, std::string &val)
Definition cmd_option.h:225
binder::cmd_option_bind_base::help_msg_t help_msg_t
Definition cmd_option.h:70
static std::vector< std::string > split_cmd(const char *begin_str)
Definition cmd_option.h:268
static short map_value_[256]
Definition cmd_option.h:76
std::ostream & dump(std::ostream &os, const std::string &prefix)
Definition cmd_option.h:217
std::shared_ptr< binder::cmd_option_bindt< typename binder::maybe_wrap_member_pointer< void(cmd_option_bind< TCmdStr >::*)(callback_param)>::caller_type, binder::cmd_option_bind_param_list< cmd_option_bind< TCmdStr > * > > > bind_help_cmd(const char *help_cmd_content)
Definition cmd_option.h:515
friend std::ostream & operator<<(std::ostream &os, const self_type &self)
Definition cmd_option.h:215
std::shared_ptr< binder::cmd_option_bind_base > bind_child_cmd(const std::string cmd_content, ptr_type cmd_opt)
Definition cmd_option.h:615
void start(int argv, const char *argc[], bool is_single_cmd=false, void *ext_param=nullptr) const
Definition cmd_option.h:428
std::shared_ptr< binder::cmd_option_bind_base > func_ptr_t
Definition cmd_option.h:72
std::map< TCmdStr, func_ptr_t > funmap_type
Definition cmd_option.h:73
void start(const std::string &cmd_content, bool is_single_cmd=false, void *ext_param=nullptr) const
Definition cmd_option.h:486
std::string get_help_msg(const char *prefix_data="") const override
Definition cmd_option.h:535
std::shared_ptr< binder::cmd_option_bind_base > bind_child_cmd(const std::string cmd_content, std::shared_ptr< binder::cmd_option_bind_base > base_node)
Definition cmd_option.h:603
void start(callback_param args, bool is_single_cmd=false) const
Definition cmd_option.h:381
static char trans_value_[256]
Definition cmd_option.h:77
int get_help_description_style() const
Definition cmd_option.h:364
void unbind_cmd(const std::string &cmd_content)
Definition cmd_option.h:494
funmap_type callback_children_
Definition cmd_option.h:80
static ptr_type create()
Definition cmd_option.h:326
const funmap_type & get_all_children() const
Definition cmd_option.h:360
static std::ostream & dump(std::ostream &os, const self_type &self, const std::string &prefix)
Definition cmd_option.h:173
void set_help_description_style(int style)
Definition cmd_option.h:365
void start(int argv, char *argc[], bool is_single_cmd=false, void *ext_param=nullptr) const
Definition cmd_option.h:442
void append_cmd(const char *cmd_content, std::shared_ptr< binder::cmd_option_bind_base > base_node)
size_type get_params_number() const
void load_cmd_array(const cmd_array_type &cmds)
const cmd_array_type & get_cmd_array() const
void add(const char *param)
cmd_option_bind< std::string > cmd_option
Definition cmd_option.h:641
cmd_option_bind< cmd_option_ci_string > cmd_option_ci
Definition cmd_option.h:642
std::shared_ptr< cli::cmd_option_value > value_type
Definition cmd_option.h:50
导入高级库,hash、引用包装等 Licensed under the MIT licenses.
std::shared_ptr< cmd_option_bind_base > binded_obj