10 from cmd_descs_util
import (
24 CMDDESCS_C_TEMPLATE =
"""// SPDX-FileCopyrightText: 2021 RizinOrg <info@rizin.re>
25 // SPDX-License-Identifier: LGPL-3.0-only
27 // WARNING: This file was auto-generated by cmd_descs_generate.py script. Do not
28 // modify it manually. Look at cmd_descs.yaml if you want to update commands.
31 #include <cmd_descs.h>
36 RZ_IPI void rzshell_cmddescs_init(RzCore *core) {{
37 \tRzCmdDesc *root_cd = rz_cmd_get_root(core->rcmd);
38 \trz_cmd_batch_start(core->rcmd);
40 \trz_cmd_batch_end(core->rcmd);
44 CMDDESCS_H_TEMPLATE =
"""// SPDX-FileCopyrightText: 2021 RizinOrg <info@rizin.re>
45 // SPDX-License-Identifier: LGPL-3.0-only
47 // WARNING: This file was auto-generated by cmd_descs_generate.py script. Do not
48 // modify it manually. Look at cmd_descs.yaml if you want to update commands.
55 // Command handlers, manually defined somewhere else
56 {handlers_declarations}
58 // Main function that initialize the entire commands tree
59 RZ_IPI void rzshell_cmddescs_init(RzCore *core);
62 DESC_HELP_DETAIL_ENTRY_TEMPLATE = (
63 """\t{{ .text = {text}, .arg_str = {arg_str}, .comment = {comment} }}"""
65 DESC_HELP_DETAIL_ENTRIES_TEMPLATE =
"""static const RzCmdDescDetailEntry {cname}[] = {{
70 DESC_HELP_DETAIL_TEMPLATE =
"""\t{{ .name = {name}, .entries = {entries} }}"""
71 DESC_HELP_DETAILS_TEMPLATE =
"""static const RzCmdDescDetail {cname}[] = {{
75 DECL_DESC_HELP_DETAILS_TEMPLATE =
"static const RzCmdDescDetail {cname}[{size}];"
77 DESC_HELP_ARG_CHOICES =
"static const char *{cname}[] = {{ {choices} }};\n"
78 DESC_HELP_ARG_UNION_CHOICES =
"\t\t.choices = {choices},\n"
79 DESC_HELP_ARG_UNION_CHOICES_CB =
"\t\t.choices_cb = {choices_cb},\n"
80 DESC_HELP_ARG_TEMPLATE_FLAGS =
"\t\t.flags = {flags},\n"
81 DESC_HELP_ARG_TEMPLATE_OPTIONAL =
"\t\t.optional = {optional},\n"
82 DESC_HELP_ARG_TEMPLATE_NO_SPACE =
"\t\t.no_space = {no_space},\n"
83 DESC_HELP_ARG_TEMPLATE_DEFAULT_VALUE =
"\t\t.default_value = {default_value},\n"
84 DESC_HELP_ARG_TEMPLATE =
"""\t{{
87 {flags}{optional}{no_space}{default_value}{union}
89 DESC_HELP_ARGS_TEMPLATE =
"""static const RzCmdDescArg {cname}[] = {{
93 DECL_DESC_HELP_ARGS_TEMPLATE =
"static const RzCmdDescArg {cname}[{size}];"
95 DESC_HELP_TEMPLATE_DESCRIPTION =
"\t.description = {description},\n"
96 DESC_HELP_TEMPLATE_ARGS_STR =
"\t.args_str = {args_str},\n"
97 DESC_HELP_TEMPLATE_USAGE =
"\t.usage = {usage},\n"
98 DESC_HELP_TEMPLATE_SORT_SUBCOMMANDS =
"\t.sort_subcommands = {sort_subcommands},\n"
99 DESC_HELP_TEMPLATE_OPTIONS =
"\t.options = {options},\n"
100 DESC_HELP_TEMPLATE_DETAILS =
"\t.details = {details},\n"
101 DESC_HELP_TEMPLATE_DETAILS_CB =
"\t.details_cb = {details_cb},\n"
102 DESC_HELP_TEMPLATE_ARGS =
"\t.args = {args},\n"
103 DESC_HELP_TEMPLATE =
"""static const RzCmdDescHelp {cname} = {{
104 \t.summary = {summary},
105 {description}{args_str}{usage}{options}{details}{details_cb}{args}{sort_subcommands}}};
108 DEFINE_OLDINPUT_TEMPLATE =
"""
109 \tRzCmdDesc *{cname}_cd = rz_cmd_desc_oldinput_new(core->rcmd, {parent_cname}_cd, {name}, {handler_cname}, &{help_cname});
110 \trz_warn_if_fail({cname}_cd);"""
111 DEFINE_ARGV_TEMPLATE =
"""
112 \tRzCmdDesc *{cname}_cd = rz_cmd_desc_argv_new(core->rcmd, {parent_cname}_cd, {name}, {handler_cname}, &{help_cname});
113 \trz_warn_if_fail({cname}_cd);"""
114 DEFINE_ARGV_MODES_TEMPLATE =
"""
115 \tRzCmdDesc *{cname}_cd = rz_cmd_desc_argv_modes_new(core->rcmd, {parent_cname}_cd, {name}, {modes}, {handler_cname}, &{help_cname});
116 \trz_warn_if_fail({cname}_cd);"""
117 DEFINE_ARGV_STATE_TEMPLATE =
"""
118 \tRzCmdDesc *{cname}_cd = rz_cmd_desc_argv_state_new(core->rcmd, {parent_cname}_cd, {name}, {modes}, {handler_cname}, &{help_cname});
119 \trz_warn_if_fail({cname}_cd);"""
120 DEFINE_GROUP_TEMPLATE =
"""
121 \tRzCmdDesc *{cname}_cd = rz_cmd_desc_group_new(core->rcmd, {parent_cname}_cd, {name}, {handler_cname}, {help_cname_ref}, &{group_help_cname});
122 \trz_warn_if_fail({cname}_cd);"""
123 DEFINE_GROUP_MODES_TEMPLATE =
"""
124 \tRzCmdDesc *{cname}_cd = rz_cmd_desc_group_modes_new(core->rcmd, {parent_cname}_cd, {name}, {modes}, {handler_cname}, {help_cname_ref}, &{group_help_cname});
125 \trz_warn_if_fail({cname}_cd);"""
126 DEFINE_GROUP_STATE_TEMPLATE =
"""
127 \tRzCmdDesc *{cname}_cd = rz_cmd_desc_group_state_new(core->rcmd, {parent_cname}_cd, {name}, {modes}, {handler_cname}, {help_cname_ref}, &{group_help_cname});
128 \trz_warn_if_fail({cname}_cd);"""
129 DEFINE_INNER_TEMPLATE =
"""
130 \tRzCmdDesc *{cname}_cd = rz_cmd_desc_inner_new(core->rcmd, {parent_cname}_cd, {name}, &{help_cname});
131 \trz_warn_if_fail({cname}_cd);"""
132 DEFINE_FAKE_TEMPLATE =
"""
133 \tRzCmdDesc *{cname}_cd = rz_cmd_desc_fake_new(core->rcmd, {parent_cname}_cd, {name}, &{help_cname});
134 \trz_warn_if_fail({cname}_cd);"""
136 SET_DEFAULT_MODE_TEMPLATE =
"""
137 \trz_cmd_desc_set_default_mode({cname}_cd, {default_mode});"""
141 return s.replace(
"\\",
"\\\\").
replace(
'"',
'\\"')
145 return '"' +
_escape(s) +
'"' if s
is not None else "NULL"
149 return s.strip(
"\n")
if s
is not None else None
154 if "name" not in c
or "type" not in c:
155 print(
"Argument of %s should have `name`/`type` fields" % (cd.name,))
161 self.
flagsflags = c.pop(
"flags",
None)
166 str(c.pop(
"default_value"))
if "default_value" in c
else None
172 "Argument %s for command %s has unrecognized properties: %s."
173 % (self.
namename, self.
cdcd.name, c.keys())
179 "Argument %s for command %s has both optional and default_value."
180 % (self.
namename, self.
cdcd.name)
185 if self.
typetype ==
"RZ_CMD_ARG_TYPE_CHOICES":
188 raise Exception(
"_get_choices_cname should be called on ARG_TYPE_CHOICES only")
191 if self.
typetype ==
"RZ_CMD_ARG_TYPE_CHOICES":
193 return DESC_HELP_ARG_UNION_CHOICES.format(
196 return DESC_HELP_ARG_UNION_CHOICES_CB.format(choices_cb=self.
choices_cbchoices_cb)
202 DESC_HELP_ARG_TEMPLATE_FLAGS.format(flags=self.
flagsflags)
203 if self.
flagsflags
is not None and self.
flagsflags !=
""
207 DESC_HELP_ARG_TEMPLATE_OPTIONAL.format(
208 optional=
"true" if self.
optionaloptional
else "false"
210 if self.
optionaloptional
is not None
214 DESC_HELP_ARG_TEMPLATE_NO_SPACE.format(
215 no_space=
"true" if self.
no_spaceno_space
else "false"
217 if self.
no_spaceno_space
is not None
221 DESC_HELP_ARG_TEMPLATE_DEFAULT_VALUE.format(
227 return DESC_HELP_ARG_TEMPLATE.format(
233 default_value=default_value,
238 if self.
typetype ==
"RZ_CMD_ARG_TYPE_CHOICES" and self.
choices_cbchoices_cb
is None:
239 return DESC_HELP_ARG_CHOICES.format(
243 '"%s"' % (x,)
if x !=
"NULL" else x
244 for x
in self.
choiceschoices + [
"NULL"]
251 if self.
typetype ==
"RZ_CMD_ARG_TYPE_CHOICES" and self.
choices_cbchoices_cb
is not None:
252 return "RZ_IPI char **%s(RzCore *core);" % (self.
choices_cbchoices_cb,)
257 if "text" not in c
or "comment" not in c:
258 print(
"No `text`/`comment` fields for DetailEntry %s" % (c,))
261 text =
strip(c[
"text"])
262 comment =
strip(c[
"comment"])
263 arg_str =
strip(c.get(
"arg_str"))
265 return DESC_HELP_DETAIL_ENTRY_TEMPLATE.format(
274 if "name" not in c
or "entries" not in c:
275 print(
"No `name`/`entries` fields for Detail %s" % (c,))
284 "Detail %s for command %s has unrecognized properties: %s."
285 % (self.
namename, self.
cdcd.name, c.keys())
293 return DESC_HELP_DETAIL_TEMPLATE.format(
299 return DESC_HELP_DETAIL_ENTRIES_TEMPLATE.format(
301 entry=
",\n".join([
str(e)
for e
in self.
entriesentries] + [
"\t{ 0 },"]),
312 if "details" in c
and isinstance(c[
"details"], list):
314 elif "details" in c
and isinstance(c[
"details"], str):
316 if "details_cb" in c
and isinstance(c[
"details_cb"], str):
320 if "args" in c
and isinstance(c[
"args"], list):
321 self.
argsargs = [
Arg(self, x)
for x
in c.pop(
"args", [])]
324 and self.
argsargs[-1].type
in CD_ARG_LAST_TYPES
325 and self.
argsargs[-1].flags
is None
327 self.
argsargs[-1].flags =
"RZ_CMD_ARG_FLAG_LAST"
328 elif "args" in c
and isinstance(c[
"args"], str):
334 elif c.get(
"subcommands"):
335 self.
typetype = CD_TYPE_GROUP
336 elif self.
modesmodes:
337 self.
typetype = CD_TYPE_ARGV_MODES
339 self.
typetype = CD_TYPE_ARGV
342 if "subcommands" in c
and isinstance(c[
"subcommands"], list):
346 for i, x
in enumerate(c.pop(
"subcommands", []))
348 elif "subcommands" in c
and isinstance(c[
"subcommands"], str):
350 subcommands_name = c.pop(
"subcommands")
351 if subcommands_name
not in yamls:
353 "Command %s referenced another YAML file (%s) that is not passed as arg to cmd_descs_generate.py."
354 % (self.
namename, subcommands_name)
358 external_c = yamls[subcommands_name]
360 CmdDesc(yamls, x, self, i)
for i, x
in enumerate(external_c)
367 and self.
subcommandssubcommands[0].type
not in [CD_TYPE_INNER, CD_TYPE_FAKE]
379 self.
typetype = CD_TYPE_GROUP
382 if not c.get(
"name")
or not c.get(
"summary"):
383 print(
"No `name`/`summary` fields in", c)
387 self.
namename = c.pop(
"name")
393 self.
modesmodes = c.pop(
"modes",
None)
419 CmdDesc.c_cds[self.
cnamecname] = self
423 CmdDesc.c_args[CmdDesc.get_arg_cname(self)] = self
425 CmdDesc.c_details[CmdDesc.get_detail_cname(self)] = self
429 print(
"Command %s has unrecognized properties: %s." % (self.
namename, c.keys()))
432 if self.
typetype
not in CD_VALID_TYPES:
433 print(
"Command %s does not have a valid type." % (self.
namename,))
438 in [CD_TYPE_ARGV, CD_TYPE_ARGV_MODES, CD_TYPE_ARGV_STATE, CD_TYPE_OLDINPUT]
439 and not self.
cnamecname
441 print(
"Command %s does not have cname field" % (self.
namename,))
448 and self.
typetype
not in [CD_TYPE_INNER, CD_TYPE_FAKE]
451 "If a command has the same name as its parent, it can only be the first child. See parent of Command %s"
456 if self.
parentparent
and self.
parentparent.type
not in [
461 print(
"The parent of %s is of the wrong type" % (self.
cnamecname,))
464 if self.
cnamecname
in CmdDesc.c_cds:
465 print(
"Another command already has the same cname as %s" % (self.
cnamecname,))
469 self.
typetype
in [CD_TYPE_ARGV, CD_TYPE_ARGV_MODES, CD_TYPE_ARGV_STATE]
470 and self.
argsargs
is None
473 print(
"Specify arguments for command %s" % (self.
namename,))
477 if self.
typetype
not in [
488 return cd.cname +
"_args"
492 return cd.cname +
"_details"
495 return self.
cnamecname +
"_help"
502 if self.
detailsdetails
is not None:
503 out +=
"\n".join([d.get_cstructure()
for d
in self.
detailsdetails])
504 out += DESC_HELP_DETAILS_TEMPLATE.format(
505 cname=CmdDesc.get_detail_cname(self),
506 details=
",\n".join([
str(d)
for d
in self.
detailsdetails] + [
"\t{ 0 },"]),
508 details_cname = CmdDesc.get_detail_cname(self)
512 if self.
argsargs
is not None:
514 [a.get_cstructure()
for a
in self.
argsargs
if a.get_cstructure() !=
""]
516 out += DESC_HELP_ARGS_TEMPLATE.format(
517 cname=CmdDesc.get_arg_cname(self),
518 args=
",\n".join([
str(a)
for a
in self.
argsargs] + [
"\t{ 0 },"]),
520 args_cname = CmdDesc.get_arg_cname(self)
522 args_cname = self.
args_aliasargs_alias +
"_args"
525 DESC_HELP_TEMPLATE_DESCRIPTION.format(
533 if self.
args_strargs_str
is not None
538 if self.
usageusage
is not None
542 DESC_HELP_TEMPLATE_SORT_SUBCOMMANDS.format(
543 sort_subcommands=
"true" if self.
sort_subcommandssort_subcommands
else "false"
550 if self.
optionsoptions
is not None
554 DESC_HELP_TEMPLATE_DETAILS.format(details=details_cname)
555 if details_cname
is not None
559 DESC_HELP_TEMPLATE_DETAILS_CB.format(details_cb=self.
details_cbdetails_cb)
564 DESC_HELP_TEMPLATE_ARGS.format(args=args_cname)
565 if args_cname
is not None
568 out += DESC_HELP_TEMPLATE.format(
571 description=description,
576 details_cb=details_cb,
578 sort_subcommands=sort_subcommands,
582 out +=
"\n".join([
str(child)
for child
in self.
subcommandssubcommands])
588 out += spaces +
"Name: %s\n" % (self.
namename,)
589 out += spaces +
"CName: %s\n" % (self.
cnamecname,)
590 out += spaces +
"Summary: %s\n" % (self.
summarysummary,)
592 out += spaces +
"Description: %s\n" % (self.
descriptiondescription,)
594 out += spaces +
"Subcommands:\n"
596 out += c.str_tab(tab + 4)
606 if cd.exec_cd
and cd.exec_cd.type == CD_TYPE_ARGV_MODES:
607 formatted_string = DEFINE_GROUP_MODES_TEMPLATE.format(
609 parent_cname=cd.parent.cname,
611 modes=
" | ".join(cd.exec_cd.modes),
612 handler_cname=cd.exec_cd.get_handler_cname(),
613 help_cname_ref=
"&" + cd.exec_cd.get_help_cname(),
614 group_help_cname=cd.get_help_cname(),
616 if cd.exec_cd.default_mode
is not None:
617 formatted_string += SET_DEFAULT_MODE_TEMPLATE.format(
619 default_mode=cd.exec_cd.default_mode,
621 formatted_string +=
"\n".join(
622 [
createcd(child)
for child
in cd.subcommands[1:]
or []]
624 elif cd.exec_cd
and cd.exec_cd.type == CD_TYPE_ARGV_STATE:
625 formatted_string = DEFINE_GROUP_STATE_TEMPLATE.format(
627 parent_cname=cd.parent.cname,
629 modes=
" | ".join(cd.exec_cd.modes),
630 handler_cname=cd.exec_cd.get_handler_cname(),
631 help_cname_ref=
"&" + cd.exec_cd.get_help_cname(),
632 group_help_cname=cd.get_help_cname(),
634 if cd.exec_cd.default_mode
is not None:
635 formatted_string += SET_DEFAULT_MODE_TEMPLATE.format(
637 default_mode=cd.exec_cd.default_mode,
639 formatted_string +=
"\n".join(
640 [
createcd(child)
for child
in cd.subcommands[1:]
or []]
643 formatted_string = DEFINE_GROUP_TEMPLATE.format(
645 parent_cname=cd.parent.cname,
647 handler_cname=(cd.exec_cd
and cd.exec_cd.get_handler_cname())
or "NULL",
648 help_cname_ref=(cd.exec_cd
and "&" + cd.exec_cd.get_help_cname())
or "NULL",
649 group_help_cname=cd.get_help_cname(),
652 cd.exec_cd
and cd.subcommands
and cd.subcommands[1:]
654 formatted_string +=
"\n".join([
createcd(child)
for child
in subcommands
or []])
656 return formatted_string
660 formatted_string =
None
662 if cd.type == CD_TYPE_ARGV:
663 formatted_string = DEFINE_ARGV_TEMPLATE.format(
665 parent_cname=cd.parent.cname,
667 handler_cname=cd.get_handler_cname(),
668 help_cname=cd.get_help_cname(),
670 elif cd.type == CD_TYPE_ARGV_MODES:
671 formatted_string = DEFINE_ARGV_MODES_TEMPLATE.format(
673 parent_cname=cd.parent.cname,
675 modes=
" | ".join(cd.modes),
676 handler_cname=cd.get_handler_cname(),
677 help_cname=cd.get_help_cname(),
679 if cd.default_mode
is not None:
680 formatted_string += SET_DEFAULT_MODE_TEMPLATE.format(
682 default_mode=cd.default_mode,
684 elif cd.type == CD_TYPE_ARGV_STATE:
685 formatted_string = DEFINE_ARGV_STATE_TEMPLATE.format(
687 parent_cname=cd.parent.cname,
689 modes=
" | ".join(cd.modes),
690 handler_cname=cd.get_handler_cname(),
691 help_cname=cd.get_help_cname(),
693 if cd.default_mode
is not None:
694 formatted_string += SET_DEFAULT_MODE_TEMPLATE.format(
696 default_mode=cd.default_mode,
698 elif cd.type == CD_TYPE_FAKE:
699 formatted_string = DEFINE_FAKE_TEMPLATE.format(
701 parent_cname=cd.parent.cname,
703 help_cname=cd.get_help_cname(),
705 elif cd.type == CD_TYPE_INNER:
706 formatted_string = DEFINE_INNER_TEMPLATE.format(
708 parent_cname=cd.parent.cname,
710 help_cname=cd.get_help_cname(),
712 formatted_string +=
"\n".join(
713 [
createcd(child)
for child
in cd.subcommands
or []]
715 elif cd.type == CD_TYPE_OLDINPUT:
716 formatted_string = DEFINE_OLDINPUT_TEMPLATE.format(
718 parent_cname=cd.parent.cname,
720 handler_cname=cd.get_handler_cname(),
721 help_cname=cd.get_help_cname(),
723 formatted_string +=
"\n".join(
724 [
createcd(child)
for child
in cd.subcommands
or []]
726 elif cd.type == CD_TYPE_GROUP:
729 raise Exception(
"Not handled cd type")
731 return formatted_string
735 return DECL_DESC_HELP_ARGS_TEMPLATE.format(
736 cname=CmdDesc.get_arg_cname(cd), size=
len(cd.args) + 1
741 return DECL_DESC_HELP_DETAILS_TEMPLATE.format(
742 cname=CmdDesc.get_detail_cname(cd), size=
len(cd.details) + 1
748 if cd_type == CD_TYPE_ARGV:
750 "RZ_IPI RzCmdStatus %s(RzCore *core, int argc, const char **argv);"
753 if cd_type == CD_TYPE_ARGV_MODES:
755 "RZ_IPI RzCmdStatus %s(RzCore *core, int argc, const char **argv, RzOutputMode mode);"
758 if cd_type == CD_TYPE_ARGV_STATE:
760 "RZ_IPI RzCmdStatus %s(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);"
763 if cd_type == CD_TYPE_OLDINPUT:
764 out.append(
"RZ_IPI int %s(void *data, const char *input);" % (handler_name,))
766 if cd.details_cb
is not None:
768 "RZ_IPI RzCmdDescDetail *%s(RzCore *core, int argc, const char **argv);"
772 if isinstance(cd.args, list):
778 return "\n".join(out)
if out
else None
781 parser = argparse.ArgumentParser(
782 description=
"Generate .c/.h files from Command Descriptors YAML file."
785 "--src-output-dir", type=str, required=
False, help=
"Source output directory"
787 parser.add_argument(
"--output-dir", type=str, required=
True, help=
"Output directory")
790 type=argparse.FileType(
"r"),
792 help=
"Input YAML files containing commands descriptions. One should be named 'root'.",
795 args = parser.parse_args()
797 commands_yml_arr = [yaml.safe_load(f)
for f
in args.yaml_files]
798 commands_yml = {c[
"name"]: c[
"commands"]
for c
in commands_yml_arr}
801 root_cds = [
CmdDesc(commands_yml, c, root_cd)
for c
in commands_yml[
"root"]]
803 arg_decls = [
arg2decl(cd)
for cd
in CmdDesc.c_args.values()]
804 detail_decls = [
detail2decl(cd)
for cd
in CmdDesc.c_details.values()]
805 helps = [
str(cd)
for cd
in root_cds]
808 cf_text = CMDDESCS_C_TEMPLATE.format(
809 helps_declarations=
"\n".join(detail_decls + arg_decls),
810 helps=
"\n".join(helps),
811 init_code=
"\n".join(init_code),
813 with open(os.path.join(args.output_dir,
"cmd_descs.c"),
"w", encoding=
"utf8")
as f:
815 if args.src_output_dir:
817 os.path.join(args.src_output_dir,
"cmd_descs.c"),
"w", encoding=
"utf8"
822 lambda th: th[2]
is not None,
823 [(cd, cd.type, cd.get_handler_cname())
for cd
in CmdDesc.c_cds.values()],
826 hf_text = CMDDESCS_H_TEMPLATE.format(
827 handlers_declarations=
"\n".join(
831 with open(os.path.join(args.output_dir,
"cmd_descs.h"),
"w", encoding=
"utf8")
as f:
833 if args.src_output_dir:
835 os.path.join(args.src_output_dir,
"cmd_descs.h"),
"w", encoding=
"utf8"
def _get_choices_cname(self)
def __init__(self, cd, c)
def get_handler_cname(self)
def get_arg_cname(cls, cd)
def __init__(self, yamls, c, parent=None, pos=0)
def get_detail_cname(cls, cd)
def _process_details(self, c)
def _set_subcommands(self, c, yamls)
def _process_args(self, c)
def __init__(self, cd, c)
def get_detail_entries_cname(self)
def handler2decl(cd, cd_type, handler_name)
def createcd_typegroup(cd)
def format_detail_entry(c)
int replace(char *string, const char *token, const char *fmt,...)