rizin/librz/include/rz_cmd.h
Rot127 1b50a5b954
librz/core: remove old shell completely (#5004)
* Fix UB access of NULL context.

During the tests the global RzCons is accessed. Because it was
never initialized all members were 0.
Leading to undefined behavior and breaking the test with ASAN enabled.

* Use correct yaml example for the command described.

* Remove old shell compatibility code.

* Remove dependency tree of rz_core_cmd_subst() and rz_core_cmd_subst_i().

* Remove rz_core_cmd_pipe_old()

* Remove unused rz_core_hack_help()

* Regenerate grammar after removal of legacy_quoted_stmt.
2025-03-17 22:26:22 +08:00

610 lines
23 KiB
C

#ifndef RZ_CMD_H
#define RZ_CMD_H
#include <rz_types.h>
#include <rz_util.h>
#include <rz_bind.h>
#ifdef __cplusplus
extern "C" {
#endif
// RZ_LIB_VERSION_HEADER (rz_cmd);
/**
* Value returned by a command handler.
*/
typedef enum rz_cmd_status_t {
RZ_CMD_STATUS_OK = 0, ///< command handler exited in the right way
RZ_CMD_STATUS_WRONG_ARGS, ///< command handler could not handle the arguments passed to it
RZ_CMD_STATUS_ERROR, ///< command handler had issues while running (e.g. allocation error, etc.)
RZ_CMD_STATUS_INVALID, ///< command could not be executed (e.g. shell level error, bad expression, etc.)
RZ_CMD_STATUS_NONEXISTINGCMD, ///< command does not exist
RZ_CMD_STATUS_EXIT, ///< command handler asks to exit the prompt loop
} RzCmdStatus;
/**
* Type of argument a command handler can have. This is used for visualization
* in help messages and for autocompletion as well.
*/
typedef enum rz_cmd_arg_type_t {
RZ_CMD_ARG_TYPE_FAKE, ///< This is not considered a real argument, just used to show something in the help. Name of arg is shown as-is and it is not counted.
RZ_CMD_ARG_TYPE_NUM, ///< Argument is a number
RZ_CMD_ARG_TYPE_RZNUM, ///< Argument that can be interpreted by RzNum (numbers, flags, operations, etc.)
RZ_CMD_ARG_TYPE_STRING, ///< Argument that can be an arbitrary string
RZ_CMD_ARG_TYPE_RAW, ///< Like RZ_CMD_ARG_TYPE_STRING, but unescaping and quote unwrapping is not done
RZ_CMD_ARG_TYPE_ENV, ///< Argument can be the name of an existing rizin variable
RZ_CMD_ARG_TYPE_CHOICES, ///< Argument can be one of the provided choices
RZ_CMD_ARG_TYPE_FCN, ///< Argument can be the name of an existing function
RZ_CMD_ARG_TYPE_FILE, ///< Argument is a filename
RZ_CMD_ARG_TYPE_OPTION, ///< Argument is an option, prefixed with `-`. It is present or not. No argument.
RZ_CMD_ARG_TYPE_CMD, ///< Argument is an rizin command
RZ_CMD_ARG_TYPE_MACRO, ///< Argument is the name of a pre-defined macro
RZ_CMD_ARG_TYPE_EVAL_KEY, ///< Argument is the name of a evaluable variable (e.g. `et` command)
RZ_CMD_ARG_TYPE_EVAL_FULL, ///< Argument is the name+(optional)value of a evaluable variable (e.g. `e` command)
RZ_CMD_ARG_TYPE_FCN_VAR, ///< Argument is the name of a function variable/argument
RZ_CMD_ARG_TYPE_FLAG, ///< Argument is a rizin flag
RZ_CMD_ARG_TYPE_ENUM_TYPE, ///< Argument is a C enum type name
RZ_CMD_ARG_TYPE_STRUCT_TYPE, ///< Argument is a C struct type name
RZ_CMD_ARG_TYPE_UNION_TYPE, ///< Argument is a C union type name
RZ_CMD_ARG_TYPE_ALIAS_TYPE, ///< Argument is a C typedef (alias) name
RZ_CMD_ARG_TYPE_CLASS_TYPE, ///< Argument is a C++/etc class name
RZ_CMD_ARG_TYPE_ANY_TYPE, ///< Argument is the any of the C or C++ type name
RZ_CMD_ARG_TYPE_GLOBAL_VAR, ///< Argument is a user defined global variable
RZ_CMD_ARG_TYPE_REG_FILTER, ///< Argument is a register name, size, type or "all"
RZ_CMD_ARG_TYPE_REG_TYPE, ///< Argument is a register type/arena like "gpr"
} RzCmdArgType;
/**
* Argument can contain spaces when it is the last of a command and it would
* be considered as a single argument by the command handler.
*/
#define RZ_CMD_ARG_FLAG_LAST (1 << 0)
/**
* Argument is an array of elements. It must be the last in the list of
* arguments of a command.
*/
#define RZ_CMD_ARG_FLAG_ARRAY (1 << 1)
/**
* Argument is an option, prefixed with `-`. It is present or not.
*/
#define RZ_CMD_ARG_FLAG_OPTION (1 << 2)
typedef enum rz_cmd_escape_t {
RZ_CMD_ESCAPE_ONE_ARG, ///< The string should be escaped so that it appears as one single argument
RZ_CMD_ESCAPE_MULTI_ARG, ///< The string should be escaped so that it appears as one or multiple arguments
RZ_CMD_ESCAPE_PF_ARG, ///< The string should be escaped so that it appears as one or multiple `pf` arguments
RZ_CMD_ESCAPE_DOUBLE_QUOTED_ARG, ///< The string should be escaped so that it can be wrapped in "...."
RZ_CMD_ESCAPE_SINGLE_QUOTED_ARG, ///< The string should be escaped so that it can be wrapped in '....'
} RzCmdEscape;
/**
* \brief Enum to describe the way data are printed
*/
typedef enum {
RZ_OUTPUT_MODE_STANDARD = 1 << 0,
RZ_OUTPUT_MODE_JSON = 1 << 1,
RZ_OUTPUT_MODE_RIZIN = 1 << 2,
RZ_OUTPUT_MODE_QUIET = 1 << 3,
RZ_OUTPUT_MODE_SDB = 1 << 4,
RZ_OUTPUT_MODE_LONG = 1 << 5,
RZ_OUTPUT_MODE_LONG_JSON = 1 << 6,
RZ_OUTPUT_MODE_TABLE = 1 << 7,
RZ_OUTPUT_MODE_QUIETEST = 1 << 8,
RZ_OUTPUT_MODE_GRAPH = 1 << 9,
} RzOutputMode;
/**
* \brief Represent the output state of a command handler.
*
* This structure is passed to commands of type \p RZ_CMD_DESC_TYPE_ARGV_STATE .
*/
typedef struct rz_cmd_state_output_t {
/**
* Output mode expected from the command handler
*/
RzOutputMode mode;
/**
* mode-specific data. Handlers are called with these data already
* initialized as necessary, based on the requested mode, and they do not
* need to be freed by the handler.
*/
union {
PJ *pj;
RzTable *t;
} d;
} RzCmdStateOutput;
typedef int (*RzCmdCb)(void *user, const char *input);
typedef RzCmdStatus (*RzCmdArgvCb)(RzCore *core, int argc, const char **argv);
typedef RzCmdStatus (*RzCmdArgvModesCb)(RzCore *core, int argc, const char **argv, RzOutputMode mode);
typedef RzCmdStatus (*RzCmdArgvStateCb)(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
typedef RzCmdStatus (*RzCmdMacroCb)(RzCore *core, int argc, const char **argv, int macro);
typedef int (*RzCmdNullCb)(void *user);
/**
* argc/argv data created from parsing the input command string.
*/
typedef struct rz_cmd_parsed_args_t {
int argc;
char **argv;
bool has_space_after_cmd;
char *extra; ///< Extra data that is neither a command name nor an argument (e.g. command modifiers/specifiers, table queries, etc.)
} RzCmdParsedArgs;
typedef struct rz_cmd_macro_t {
char *name;
char **args;
size_t nargs;
char *code;
} RzCmdMacro;
typedef struct rz_cmd_item_t {
char cmd[64];
RzCmdCb callback;
} RzCmdItem;
typedef struct rz_cmd_alias_t {
int count;
char **keys;
char **values;
int *remote;
} RzCmdAlias;
/**
* \brief A detailed entry that can be used to show additional info about a command entry.
*
* It can contain whatever relevant information (e.g. examples, specific uses of
* a command, variables, etc.).
*
* Displayed as:
* | <text><arg_str> # <comment>
*/
typedef struct rz_cmd_desc_detail_entry_t {
/**
* Main text of the detailed entry
*/
const char *text;
/**
* Short explanation of the entry, shown with the comment color
*/
const char *comment;
/**
* Text to show in a different color, after `text`, usually used to show
* arguments for examples.
*
* Optional.
*/
const char *arg_str;
} RzCmdDescDetailEntry;
/**
* A detail section used to better describe a command.
*/
typedef struct rz_cmd_desc_detail_t {
/**
* Name of the section, displayed at the beginning of the section.
*/
const char *name;
/**
* NULL-terminated array of entries, displayed one per line.
*/
const RzCmdDescDetailEntry *entries;
} RzCmdDescDetail;
/**
* Callback used to dynamically generate the details sections in the help of a command.
* NOTE: The array of RzCmdDescDetail returned will be freed, so all fields
* within need to be dynamically allocated even if they are marked as `const`.
*/
typedef RZ_OWN RzCmdDescDetail *(*RzCmdDescDetailCb)(RzCore *core, int argc, const char **argv);
/**
* Callback used to dynamically generate the choices of an argument with type \p RZ_CMD_ARG_TYPE_CHOICES
*/
typedef RZ_OWN char **(*RzCmdArgChoiceCb)(RzCore *core);
/**
* A description of an argument of a RzCmdDesc.
*/
typedef struct rz_cmd_desc_arg_t {
/**
* The name of the argument, shown also in its help.
*/
const char *name;
/**
* True if the argument is optional. If argument X is optional, then all
* arguments after X can only be specified if X was provided as well and
* they don't need to be set as optional.
*
* Example:
* CMDNAME <mandatory-arg0> [<optional-arg1> <optional-arg2> [<optional-arg3> [optional-arg4]]]
* <mandatory-arg0> has optional=false
* <optional-arg1> has optional=true
* <optional-arg2> has optional=false (it can be specified only if arg1
* was specified as well, so it doesn't need to be optional)
* <optional-arg3> has optional=true
* <optional-arg4> has optional=true
* Given the above:
* - `CMDNAME a0` is a valid command
* - `CMDNAME a0 a1 a2` is a valid command
* - `CMDNAME a0 a1` is not a valid command, because if a1 is specified, also a2 has to be
* - `CMDNAME a0 a1 a2 a3` is a valid command
* - `CMDNAME a0 a1 a2 a3 a4` is a valid command
*/
bool optional;
/**
* True if no space should be displayed before this argument in the help. By default it is
* false and a space is displayed before this argument.
*/
bool no_space;
/**
* Type of the argument.
*/
RzCmdArgType type;
/**
* Flag of the argument, used to modify the behaviour of this argument. See RZ_CMD_ARG_FLAG_ values.
*/
int flags;
/**
* Default value for the argument, if it is not specified. This field
* shall be used only when \p optional is true.
*/
const char *default_value;
/**
* Additional data which is type specific.
*/
union {
/**
* Data associated with an argument of \p type RZ_CMD_ARG_TYPE_CHOICES.
*/
struct {
/**
* Predefined list of possible values.
*/
const char **choices;
/**
* Callback used to generate a list of possible values.
* When this is specified, \p choices is ignored.
*/
RzCmdArgChoiceCb choices_cb;
} choices;
};
} RzCmdDescArg;
/**
* Define how the command looks like in the help.
*/
typedef struct rz_cmd_desc_help_t {
/**
* Short-sentence explaining what the command does.
* This is shown, for example, when the list of sub-commands is printed
* and each sub-command has a very short description on the right,
* explaining what it does.
*/
const char *summary;
/**
* Long description of what the command does. It can be as long as you
* want and it should explain well how the command behaves. This is
* shown, for example, when `??` is appended on a command. In that case,
* the short summary is extended with this longer description.
*
* Optional.
*/
const char *description;
/**
* String used to identify the arguments. This usually comes together
* with the summary.
* TODO: explain how to differentiate between required and optional arguments
*/
const char *args_str;
/**
* String that overrides the name+args_str usually used to describe the
* command.
*
* Optional.
*/
const char *usage;
/**
* String to use as sub-commands suggestions instead of the
* auto-generated one (e.g. [abcd] or [?] that you can see near command
* names when doing `w?`). If not provided, the options will be
* auto-generated.
*
* Optional.
*/
const char *options;
/**
* When true, the subcommands are automatically sorted alphabetically. By
* default subcommands are shown in the order provided by the developer.
*
* Optional.
*/
bool sort_subcommands;
/**
* NULL-terminated array of details sections used to better explain how
* to use the command. This is shown together with the long description.
*
* Optional.
*/
const RzCmdDescDetail *details;
/**
* Function that returns an array of details sections used to better explain
* how to use the command. This is shown together with the long description
* and can be used in addition or in alternative of \p details , when the
* output needs to be generated dynamically.
*
* Optional.
*/
RzCmdDescDetailCb details_cb;
/**
* Description of the arguments accepted by this command.
*/
const RzCmdDescArg *args;
} RzCmdDescHelp;
typedef enum rz_cmd_desc_type_t {
/**
* For handlers that accept argc/argv. It cannot have children. Use
* RZ_CMD_DESC_TYPE_GROUP if you need a command that can be both
* executed and has sub-commands.
*/
RZ_CMD_DESC_TYPE_ARGV = 0,
/**
* For cmd descriptors that are parent of other sub-commands, even if
* they may also have a sub-command with the same name. For example,
* `wc` is both the parent of `wci`, `wc*`, etc. but there is also `wc`
* as a sub-command.
*/
RZ_CMD_DESC_TYPE_GROUP,
/**
* For cmd descriptors that are just used to group together related
* sub-commands. Do not use this if the command can be used by itself or
* if it's necessary to show its help. Because this descriptor is not
* stored in the hashtable and cannot be retrieved except by listing the
* children of its parent. Most of the time you want RZ_CMD_DESC_TYPE_GROUP.
*/
RZ_CMD_DESC_TYPE_INNER,
/**
* For entries that shall be shown in the help tree but that are not
* commands on their own. `|?`, `@?`, `>?` are example of this. It is
* useful to provide help entries for them in the tree, but there are no
* command handlers for these. The RzCmdDescDetail in the help can be
* used to show fake children of this descriptor.
*/
RZ_CMD_DESC_TYPE_FAKE,
/**
* For handlers that accept argc/argv and that provides multiple output
* modes (e.g. rizin commands, quiet output, json, long). It cannot have
* children. Use RZ_CMD_DESC_TYPE_GROUP if you need a command that can
* be both executed and has sub-commands.
*/
RZ_CMD_DESC_TYPE_ARGV_MODES,
/**
* For handlers that accept argc/argv and that provides multiple output
* modes (e.g. rizin commands, quiet output, json, long). It cannot have
* children. Use RZ_CMD_DESC_TYPE_GROUP if you need a command that can
* be both executed and has sub-commands.
*
* Differently from \p RZ_CMD_DESC_TYPE_ARGV_MODES, these handlers receive
* an output structure with the mode and data already initialized (e.g. PJ,
* RzTable, etc.) and the handler just has to fill the data in those
* structure, while RzCmd will allocate, free and print the data within.
*/
RZ_CMD_DESC_TYPE_ARGV_STATE,
} RzCmdDescType;
/**
* Command Descriptor structure. It represents a command that can be executed
* by the user on the shell or a part of the command help (e.g. groups of
* commands). Anything that appears under `?` has an associated command
* descriptor.
*/
typedef struct rz_cmd_desc_t {
/**
* Type of the command descriptor. There are several types of commands:
* groups, fake and inner have no handlers; argv, mode and state can
* have handlers and get arguments via int argc, char **argv.
*/
RzCmdDescType type;
/**
* Base name of the command. This is used to retrieve the \p RzCmdDesc when
* a user executes a command. It can match multiple user-called commands.
* For example a command that accepts STANDARD and JSON \p modes is called
* for both `<name>` and `<name>j`.
*/
char *name;
/**
* Parent of this command descriptor.
*
* Commands are organized in a tree, with the root being shown when doing
* `?`. This relationship is used when showing commands helps.
*/
struct rz_cmd_desc_t *parent;
/**
* Number of children command descriptors of this node.
*/
int n_children;
/**
* Vector of childrens command descriptors.
*/
RzPVector /*<RzCmdDesc *>*/ children;
/**
* Reference to the help structure of this command descriptor.
*/
const RzCmdDescHelp *help;
/**
* Type-specific fields.
*/
union {
struct {
RzCmdArgvCb cb;
int min_argc;
int max_argc;
} argv_data;
struct {
struct rz_cmd_desc_t *exec_cd;
} group_data;
struct {
RzCmdArgvModesCb cb;
int modes; ///< A combination of RzOutputMode values
RzOutputMode default_mode; ///< Make one of the modes the default one, used even when the special suffix is not specified.
int min_argc;
int max_argc;
} argv_modes_data;
struct {
RzCmdArgvStateCb cb;
int modes; ///< A combination of RzOutputMode values
RzOutputMode default_mode; ///< Make one of the modes the default one, used even when the special suffix is not specified.
int min_argc;
int max_argc;
} argv_state_data;
} d;
} RzCmdDesc;
typedef struct rz_cmd_t {
RzCore *core;
RzCmdNullCb nullcallback;
RzCmdItem *cmds[UT8_MAX];
RzCmdAlias aliases;
HtSP *macros; ///< Map of macros (char *)name -> RzCmdMacro
void *language; // used to store TSLanguage *
HtUP *ts_symbols_ht;
RzCmdDesc *root_cmd_desc;
HtSP *ht_cmds;
/**
* True if a rz_cons_instance exists. When used from RzCore this is
* commonly true. However, it can be used in tests to avoid access to
* non-initialized RzCons.
*/
bool has_cons;
/**
* True when you want to add multiple commands in batch. This is an
* optimization mainly for groups that require sorted sub-commands, so
* instead of sorting on each addition we just sort one time at the end.
* False by default.
*/
bool batch;
} RzCmd;
// TODO: remove this once transitioned to RzCmdDesc
typedef struct rz_cmd_descriptor_t {
const char *cmd;
const char **help_msg;
const char **help_detail;
const char **help_detail2;
struct rz_cmd_descriptor_t *sub[127];
} RzCmdDescriptor;
typedef bool (*RzCmdForeachNameCb)(RzCmd *cmd, const RzCmdDesc *desc, void *user);
typedef bool (*RzCmdForeachMacroCb)(RzCmd *cmd, const RzCmdMacro *macro, void *user);
#ifdef RZ_API
RZ_API RzCmd *rz_cmd_new(RzCore *core, bool has_cons);
RZ_API RzCmd *rz_cmd_free(RzCmd *cmd);
RZ_API void rz_cmd_batch_start(RzCmd *cmd);
RZ_API void rz_cmd_batch_end(RzCmd *cmd);
RZ_API int rz_cmd_add(RzCmd *cmd, const char *command, RzCmdCb callback);
RZ_API int rz_cmd_call(RzCmd *cmd, const char *command);
RZ_API RzCmdStatus rz_cmd_call_parsed_args(RzCmd *cmd, RzCmdParsedArgs *args);
RZ_API RzCmdDesc *rz_cmd_get_root(RzCmd *cmd);
RZ_API RzCmdDesc *rz_cmd_get_desc(RzCmd *cmd, const char *cmd_identifier);
RZ_API RzCmdDesc *rz_cmd_get_desc_best(RzCmd *cmd, const char *cmd_identifier);
RZ_API char *rz_cmd_get_help(RzCmd *cmd, RzCmdParsedArgs *args, bool use_color);
RZ_API bool rz_cmd_get_help_json(RzCmd *cmd, const RzCmdDesc *cd, PJ *j);
RZ_API bool rz_cmd_get_help_strbuf(RzCmd *cmd, const RzCmdDesc *cd, bool use_color, RzStrBuf *sb);
static inline RzCmdStatus rz_cmd_int2status(int v) {
if (v == -2) {
return RZ_CMD_STATUS_EXIT;
} else if (v < 0) {
return RZ_CMD_STATUS_ERROR;
} else {
return RZ_CMD_STATUS_OK;
}
}
static inline int rz_cmd_status2int(RzCmdStatus s) {
switch (s) {
case RZ_CMD_STATUS_OK:
return 0;
case RZ_CMD_STATUS_ERROR:
case RZ_CMD_STATUS_WRONG_ARGS:
case RZ_CMD_STATUS_INVALID:
case RZ_CMD_STATUS_NONEXISTINGCMD:
return -1;
case RZ_CMD_STATUS_EXIT:
default:
return -2;
}
}
/* RzCmdDescriptor */
RZ_API RzCmdDesc *rz_cmd_desc_argv_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, RzCmdArgvCb cb, const RzCmdDescHelp *help);
RZ_API RzCmdDesc *rz_cmd_desc_argv_modes_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, int modes, RzCmdArgvModesCb cb, const RzCmdDescHelp *help);
RZ_API RzCmdDesc *rz_cmd_desc_argv_state_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, int modes, RzCmdArgvStateCb cb, const RzCmdDescHelp *help);
RZ_API RzCmdDesc *rz_cmd_desc_inner_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, const RzCmdDescHelp *help);
RZ_API RzCmdDesc *rz_cmd_desc_group_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, RzCmdArgvCb cb, const RzCmdDescHelp *help, const RzCmdDescHelp *group_help);
RZ_API RzCmdDesc *rz_cmd_desc_group_modes_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, int modes, RzCmdArgvModesCb cb, const RzCmdDescHelp *help, const RzCmdDescHelp *group_help);
RZ_API RzCmdDesc *rz_cmd_desc_group_state_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, int modes, RzCmdArgvStateCb cb, const RzCmdDescHelp *help, const RzCmdDescHelp *group_help);
RZ_API RzCmdDesc *rz_cmd_desc_fake_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, const RzCmdDescHelp *help);
RZ_API RzCmdDesc *rz_cmd_desc_parent(RzCmdDesc *cd);
RZ_API RzCmdDesc *rz_cmd_desc_get_exec(RzCmdDesc *cd);
RZ_API bool rz_cmd_desc_set_default_mode(RzCmdDesc *cd, RzOutputMode mode);
RZ_API bool rz_cmd_desc_has_handler(const RzCmdDesc *cd);
RZ_API bool rz_cmd_desc_remove(RzCmd *cmd, RzCmdDesc *cd);
RZ_API void rz_cmd_foreach_cmdname(RzCmd *cmd, RzCmdDesc *begin, RzCmdForeachNameCb cb, void *user);
RZ_API const RzCmdDescArg *rz_cmd_desc_get_arg(const RzCmdDesc *cd, size_t i);
#define rz_cmd_desc_children_foreach(root, it_cd) rz_pvector_foreach (&root->children, it_cd)
RZ_API void rz_cmd_desc_details_free(RzCmdDescDetail *details);
/* RzCmdParsedArgs */
RZ_API RzCmdParsedArgs *rz_cmd_parsed_args_new(const char *cmd, int n_args, char **args);
RZ_API RzCmdParsedArgs *rz_cmd_parsed_args_newcmd(const char *cmd);
RZ_API RzCmdParsedArgs *rz_cmd_parsed_args_newargs(int n_args, char **args);
RZ_API void rz_cmd_parsed_args_free(RzCmdParsedArgs *args);
RZ_API bool rz_cmd_parsed_args_setargs(RzCmdParsedArgs *arg, int n_args, char **args);
RZ_API bool rz_cmd_parsed_args_addarg(RzCmdParsedArgs *a, const char *arg);
RZ_API bool rz_cmd_parsed_args_setcmd(RzCmdParsedArgs *arg, const char *cmd);
RZ_API char *rz_cmd_parsed_args_argstr(RzCmdParsedArgs *arg);
RZ_API char *rz_cmd_parsed_args_execstr(RzCmdParsedArgs *arg);
RZ_API const char *rz_cmd_parsed_args_cmd(RzCmdParsedArgs *arg);
RZ_API char *rz_cmd_escape_arg(const char *arg, RzCmdEscape escape);
RZ_API char *rz_cmd_unescape_arg(const char *arg, RzCmdEscape escape);
RZ_API void rz_cmd_state_output_array_start(RzCmdStateOutput *state);
RZ_API void rz_cmd_state_output_array_end(RzCmdStateOutput *state);
RZ_API void rz_cmd_state_output_set_columnsf(RzCmdStateOutput *state, const char *fmt, ...);
RZ_API bool rz_cmd_state_output_init(RZ_NONNULL RzCmdStateOutput *state, RzOutputMode mode);
RZ_API void rz_cmd_state_output_fini(RZ_NONNULL RzCmdStateOutput *state);
RZ_API void rz_cmd_state_output_free(RZ_NONNULL RzCmdStateOutput *state);
RZ_API void rz_cmd_state_output_print(RZ_NONNULL RzCmdStateOutput *state);
#define rz_cmd_parsed_args_foreach_arg(args, i, arg) for ((i) = 1; (i) < (args->argc) && ((arg) = (args)->argv[i]); (i)++)
/* rz_cmd_macro */
RZ_API bool rz_cmd_macro_add(RZ_NONNULL RzCmd *cmd, RZ_NONNULL const char *name, const char **args, RZ_NONNULL const char *code);
RZ_API bool rz_cmd_macro_update(RZ_NONNULL RzCmd *cmd, RZ_NONNULL const char *name, const char **args, RZ_NONNULL const char *code);
RZ_API bool rz_cmd_macro_rm(RZ_NONNULL RzCmd *cmd, RZ_NONNULL const char *name);
RZ_API const RzCmdMacro *rz_cmd_macro_get(RZ_NONNULL RzCmd *cmd, RZ_NONNULL const char *name);
RZ_API RZ_OWN RzList /*<RzCmdMacro *>*/ *rz_cmd_macro_list(RZ_NONNULL RzCmd *cmd);
RZ_API RzCmdStatus rz_cmd_macro_call(RZ_NONNULL RzCmd *cmd, RZ_NONNULL const char *name, RZ_NONNULL const char **argv);
RZ_API RzCmdStatus rz_cmd_macro_call_multiple(RZ_NONNULL RzCmd *cmd, RZ_NONNULL const char *name, RZ_NONNULL const char **argv);
RZ_API void rz_cmd_macro_foreach(RZ_NONNULL RzCmd *cmd, RzCmdForeachMacroCb cb, void *user);
RZ_API bool rz_cmd_alias_del(RzCmd *cmd, const char *k);
RZ_API char **rz_cmd_alias_keys(RzCmd *cmd, int *sz);
RZ_API int rz_cmd_alias_set(RzCmd *cmd, const char *k, const char *v, int remote);
RZ_API char *rz_cmd_alias_get(RzCmd *cmd, const char *k, int remote);
RZ_API void rz_cmd_alias_free(RzCmd *cmd);
#ifdef __cplusplus
}
#endif
#endif
#endif