use clap::{ArgAction, Args, Parser, Subcommand};
use serde::{Deserialize, Serialize};
#[derive(Parser)]
#[command(name = "ghidra")]
#[command(version, about = "Rust CLI for Ghidra reverse engineering", long_about = None)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
#[arg(short, long, action = ArgAction::Count, global = true)]
pub verbose: u8,
#[arg(short, long, global = true)]
pub quiet: bool,
#[arg(long, global = true)]
pub json: bool,
#[arg(long, global = true)]
pub pretty: bool,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum Commands {
Query(QueryArgs),
Project(ProjectArgs),
#[command(subcommand, alias = "prog", alias = "programs")]
Program(ProgramCommands),
#[command(subcommand, alias = "fn", alias = "func", alias = "functions")]
Function(FunctionCommands),
#[command(subcommand, alias = "string", alias = "str")]
Strings(StringsCommands),
#[command(subcommand, alias = "sym", alias = "symbols")]
Symbol(SymbolCommands),
#[command(subcommand, alias = "mem")]
Memory(MemoryCommands),
#[command(
subcommand,
alias = "xrefs",
alias = "xref",
alias = "crossref",
alias = "crossrefs"
)]
XRef(XRefCommands),
#[command(subcommand, alias = "types")]
Type(TypeCommands),
#[command(subcommand, alias = "comments")]
Comment(CommentCommands),
#[command(subcommand, alias = "search")]
Find(FindCommands),
#[command(subcommand, alias = "callgraph", alias = "cg")]
Graph(GraphCommands),
#[command(alias = "decomp", alias = "dec")]
Decompile(DecompileArgs),
#[command(alias = "disassemble", alias = "dis")]
Disasm(DisasmArgs),
#[command(subcommand)]
Diff(DiffCommands),
#[command(subcommand, alias = "export")]
Dump(DumpCommands),
#[command(subcommand)]
Patch(PatchCommands),
#[command(subcommand, alias = "scripts")]
Script(ScriptCommands),
Batch(BatchArgs),
#[command(subcommand)]
Config(ConfigCommands),
SetDefault(SetDefaultArgs),
#[command(alias = "info")]
Summary(SummaryArgs),
Stats(StatsArgs),
Version,
Doctor,
Init,
Import(ImportArgs),
#[command(alias = "analysis")]
Analyze(AnalyzeArgs),
Start {
#[arg(long)]
project: Option<String>,
#[arg(long)]
program: Option<String>,
},
Stop {
#[arg(long)]
project: Option<String>,
},
Restart {
#[arg(long)]
project: Option<String>,
#[arg(long)]
program: Option<String>,
},
Status {
#[arg(long)]
project: Option<String>,
},
Ping {
#[arg(long)]
project: Option<String>,
},
Setup(SetupArgs),
#[command(alias = "mv")]
Rename(RenameArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct QueryArgs {
pub data_type: String,
#[arg(long, env = "GHIDRA_DEFAULT_PROGRAM")]
pub program: Option<String>,
#[arg(long, env = "GHIDRA_DEFAULT_PROJECT")]
pub project: Option<String>,
#[arg(short, long)]
pub filter: Option<String>,
#[arg(long)]
pub fields: Option<String>,
#[arg(long, short = 'o')]
pub format: Option<String>,
#[arg(long)]
pub limit: Option<usize>,
#[arg(long)]
pub offset: Option<usize>,
#[arg(long, allow_hyphen_values = true)]
pub sort: Option<String>,
#[arg(long)]
pub count: bool,
#[arg(long)]
pub json: bool,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct ProjectArgs {
#[command(subcommand)]
pub command: ProjectCommands,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum ProjectCommands {
Create { name: String },
List,
Delete { name: String },
Info { name: Option<String> },
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum ProgramCommands {
#[command(alias = "ls")]
List(ProgramTargetArgs),
Open(ProgramTargetArgs),
Close(ProgramTargetArgs),
Delete(ProgramTargetArgs),
Info(ProgramTargetArgs),
Export(ExportArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct ProgramTargetArgs {
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct ExportArgs {
pub format: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
#[arg(short, long)]
pub output: Option<String>,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum FunctionCommands {
#[command(alias = "ls")]
List(QueryOptions),
#[command(alias = "show", alias = "detail")]
Get(FunctionGetArgs),
#[command(alias = "decomp")]
Decompile(FunctionDecompileArgs),
#[command(alias = "disassemble", alias = "dis")]
Disasm(FunctionGetArgs),
Calls(FunctionGetArgs),
#[command(alias = "xrefs", alias = "crossrefs", alias = "references")]
XRefs(FunctionGetArgs),
Rename(RenameArgs),
Create(CreateFunctionArgs),
Delete(FunctionGetArgs),
SetSignature(SetSignatureArgs),
SetReturnType(SetReturnTypeArgs),
SetCallingConvention(SetCallingConventionArgs),
#[command(alias = "set-var-type")]
SetVarType(SetVarTypeArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct FunctionGetArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[command(flatten)]
pub options: QueryOptions,
}
impl FunctionGetArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct RenameArgs {
pub old_name: String,
pub new_name: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct CreateFunctionArgs {
pub address: String,
pub name: Option<String>,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct FunctionDecompileArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[arg(long)]
pub with_vars: bool,
#[arg(long)]
pub with_params: bool,
#[command(flatten)]
pub options: QueryOptions,
}
impl FunctionDecompileArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct SetSignatureArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[arg(long)]
pub signature: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
impl SetSignatureArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct SetReturnTypeArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[arg(long = "type")]
pub return_type: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
impl SetReturnTypeArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct SetCallingConventionArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[arg(long)]
pub convention: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
impl SetCallingConventionArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct SetVarTypeArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[arg(long = "var")]
pub var_name: String,
#[arg(long = "type")]
pub type_name: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
impl SetVarTypeArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum StringsCommands {
#[command(alias = "ls")]
List(QueryOptions),
#[command(alias = "references", alias = "xrefs")]
Refs(StringRefsArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct StringRefsArgs {
pub string: String,
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum SymbolCommands {
#[command(alias = "ls")]
List(QueryOptions),
Get(SymbolGetArgs),
Create(CreateSymbolArgs),
Delete(SymbolGetArgs),
Rename(RenameArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct SymbolGetArgs {
pub name: String,
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct CreateSymbolArgs {
pub address: String,
pub name: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum MemoryCommands {
Map(QueryOptions),
Read(MemReadArgs),
Write(MemWriteArgs),
Search(MemSearchArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct MemReadArgs {
pub address: String,
pub size: usize,
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct MemWriteArgs {
pub address: String,
pub bytes: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct MemSearchArgs {
pub pattern: String,
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum XRefCommands {
To(XRefArgs),
From(XRefArgs),
List(XRefArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct XRefArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[command(flatten)]
pub options: QueryOptions,
}
impl XRefArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum TypeCommands {
#[command(alias = "ls")]
List(QueryOptions),
Get(TypeGetArgs),
Create(CreateTypeArgs),
Apply(ApplyTypeArgs),
#[command(alias = "rm")]
Delete(TypeDeleteArgs),
#[command(alias = "mv")]
Rename(TypeRenameArgs),
CreateEnum(CreateEnumArgs),
Typedef(TypedefArgs),
AddField(TypeAddFieldArgs),
DelField(TypeDelFieldArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct TypeGetArgs {
pub name: String,
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct CreateTypeArgs {
pub definition: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct ApplyTypeArgs {
pub address: String,
pub type_name: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct TypeDeleteArgs {
pub name: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct TypeRenameArgs {
pub old_name: String,
pub new_name: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct CreateEnumArgs {
pub name: String,
#[arg(long)]
pub values: String,
#[arg(long, default_value = "4")]
pub size: i32,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct TypedefArgs {
pub name: String,
pub base_type: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct TypeAddFieldArgs {
pub type_name: String,
#[arg(long)]
pub name: String,
#[arg(long = "type")]
pub field_type: String,
#[arg(long)]
pub offset: Option<i32>,
#[arg(long)]
pub size: Option<i32>,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct TypeDelFieldArgs {
pub type_name: String,
#[arg(long)]
pub name: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum CommentCommands {
#[command(alias = "ls")]
List(QueryOptions),
Get(CommentGetArgs),
Set(CommentSetArgs),
Delete(CommentGetArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct CommentGetArgs {
pub address: String,
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct CommentSetArgs {
pub address: String,
pub text: String,
#[arg(long)]
pub comment_type: Option<String>,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum FindCommands {
#[command(alias = "str", alias = "strings")]
String(FindStringArgs),
Bytes(FindBytesArgs),
#[command(alias = "func", alias = "fn", alias = "functions")]
Function(FindFunctionArgs),
Calls(FindCallsArgs),
#[command(alias = "encryption")]
Crypto(QueryOptions),
#[command(alias = "suspicious", alias = "notable")]
Interesting(QueryOptions),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct FindStringArgs {
pub pattern: String,
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct FindBytesArgs {
pub hex: String,
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct FindFunctionArgs {
pub pattern: String,
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct FindCallsArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[command(flatten)]
pub options: QueryOptions,
}
impl FindCallsArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum GraphCommands {
Calls(QueryOptions),
#[command(alias = "called-by", alias = "incoming")]
Callers(GraphFunctionArgs),
#[command(alias = "calls-to", alias = "outgoing")]
Callees(GraphFunctionArgs),
Export(GraphExportArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct GraphFunctionArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[arg(long)]
pub depth: Option<usize>,
#[command(flatten)]
pub options: QueryOptions,
}
impl GraphFunctionArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct GraphExportArgs {
#[arg(id = "export_format")]
pub format: String,
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct DecompileArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[arg(long)]
pub with_vars: bool,
#[arg(long)]
pub with_params: bool,
#[command(flatten)]
pub options: QueryOptions,
}
impl DecompileArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct DisasmArgs {
#[arg(value_name = "TARGET", required_unless_present = "target")]
pub positional_target: Option<String>,
#[arg(long = "target", value_name = "TARGET")]
pub target: Option<String>,
#[arg(long = "instructions", short = 'n')]
pub num_instructions: Option<usize>,
#[command(flatten)]
pub options: QueryOptions,
}
impl DisasmArgs {
pub fn resolved_target(&self) -> &str {
self.target
.as_deref()
.or(self.positional_target.as_deref())
.expect("clap should ensure target is provided")
}
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum DiffCommands {
Programs(DiffProgramsArgs),
Functions(DiffFunctionsArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct DiffProgramsArgs {
pub program1: String,
pub program2: String,
#[arg(long)]
pub format: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct DiffFunctionsArgs {
pub func1: String,
pub func2: String,
#[arg(long)]
pub format: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum DumpCommands {
Imports(QueryOptions),
Exports(QueryOptions),
Functions(QueryOptions),
Strings(QueryOptions),
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum PatchCommands {
Bytes(PatchBytesArgs),
Nop(PatchNopArgs),
Export(PatchExportArgs),
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct PatchBytesArgs {
pub address: String,
pub hex: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct PatchNopArgs {
pub address: String,
#[arg(long)]
pub count: Option<usize>,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct PatchExportArgs {
#[arg(short, long)]
pub output: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum ScriptCommands {
Run(ScriptRunArgs),
Python(ScriptInlineArgs),
Java(ScriptInlineArgs),
List,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct ScriptRunArgs {
pub script_path: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
#[arg(last = true)]
pub args: Vec<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct ScriptInlineArgs {
pub code: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct BatchArgs {
pub script_file: String,
#[arg(long)]
pub project: Option<String>,
#[arg(long)]
pub program: Option<String>,
}
#[derive(Subcommand, Clone, Serialize, Deserialize, Debug)]
pub enum ConfigCommands {
List,
Get { key: String },
Set { key: String, value: String },
Reset,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct SetDefaultArgs {
pub kind: String,
pub value: String,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct SummaryArgs {
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct StatsArgs {
#[command(flatten)]
pub options: QueryOptions,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct ImportArgs {
pub binary: String,
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
#[arg(long, default_value = "false")]
pub detach: bool,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct AnalyzeArgs {
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
#[arg(long, default_value = "false")]
pub detach: bool,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct QueryOptions {
#[arg(long)]
pub program: Option<String>,
#[arg(long)]
pub project: Option<String>,
#[arg(short, long)]
pub filter: Option<String>,
#[arg(long)]
pub fields: Option<String>,
#[arg(long, short = 'o')]
pub format: Option<String>,
#[arg(long)]
pub limit: Option<usize>,
#[arg(long)]
pub offset: Option<usize>,
#[arg(long, allow_hyphen_values = true)]
pub sort: Option<String>,
#[arg(long)]
pub count: bool,
#[arg(long)]
pub json: bool,
}
#[derive(Args, Clone, Serialize, Deserialize, Debug)]
pub struct SetupArgs {
#[arg(long)]
pub version: Option<String>,
#[arg(long, short = 'd')]
pub dir: Option<String>,
#[arg(long)]
pub force: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_decompile_target_flag() {
let cli = Cli::try_parse_from(["ghidra", "decompile", "--target", "FUN_00401000"])
.expect("decompile --target should parse");
match cli.command {
Commands::Decompile(args) => assert_eq!(args.resolved_target(), "FUN_00401000"),
_ => panic!("expected decompile command"),
}
}
#[test]
fn parses_function_get_positional_target() {
let cli = Cli::try_parse_from(["ghidra", "function", "get", "main"])
.expect("function get positional target should parse");
match cli.command {
Commands::Function(FunctionCommands::Get(args)) => {
assert_eq!(args.resolved_target(), "main");
}
_ => panic!("expected function get command"),
}
}
}