Skip to content

Commit 041b1b2

Browse files
committed
add pe args parsing
1 parent f704b10 commit 041b1b2

3 files changed

Lines changed: 1449 additions & 17 deletions

File tree

libwild/src/args.rs

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use std::path::PathBuf;
3232

3333
pub mod elf;
3434
pub mod macho;
35+
pub mod pe;
3536

3637
use crate::error::Warning;
3738
use crate::platform;
@@ -117,6 +118,7 @@ impl Args {
117118
match PlatformKind::host() {
118119
PlatformKind::Elf => Ok(Args::Elf(elf::ElfArgs::new()?)),
119120
PlatformKind::MachO => Ok(Args::MachO(macho::MachOArgs::new()?)),
121+
PlatformKind::Pe => Ok(Args::Pe(pe::PeArgs::new()?)),
120122
}
121123
}
122124

@@ -137,6 +139,7 @@ impl Args {
137139
match self {
138140
Args::Elf(args) => args.parse(input),
139141
Args::MachO(args) => args.parse(input),
142+
Args::Pe(args) => args.parse(input),
140143
}
141144
}
142145

@@ -156,28 +159,33 @@ impl Args {
156159

157160
pub(crate) fn common(&self) -> &CommonArgs {
158161
match self {
159-
Args::Elf(elf_args) => &elf_args.common,
160-
Args::MachO(macho_args) => &macho_args.common,
162+
Args::Elf(args) => &args.common,
163+
Args::MachO(args) => &args.common,
164+
Args::Pe(args) => &args.common,
161165
}
162166
}
163167

164168
pub(crate) fn common_mut(&mut self) -> &mut CommonArgs {
165169
match self {
166-
Args::Elf(elf_args) => &mut elf_args.common,
167-
Args::MachO(macho_args) => &mut macho_args.common,
170+
Args::Elf(args) => &mut args.common,
171+
Args::MachO(args) => &mut args.common,
172+
Args::Pe(args) => &mut args.common,
168173
}
169174
}
170175
}
171176

172177
enum PlatformKind {
173178
Elf,
174179
MachO,
180+
Pe,
175181
}
176182

177183
impl PlatformKind {
178184
fn host() -> Self {
179185
if cfg!(target_os = "macos") {
180186
PlatformKind::MachO
187+
} else if cfg!(target_os = "windows") {
188+
PlatformKind::Pe
181189
} else {
182190
PlatformKind::Elf
183191
}
@@ -426,13 +434,15 @@ pub struct ThreadPool {
426434
pub enum Args {
427435
Elf(elf::ElfArgs),
428436
MachO(macho::MachOArgs),
437+
Pe(pe::PeArgs),
429438
}
430439

431440
impl std::fmt::Debug for Args {
432441
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
433442
match self {
434443
Args::Elf(args) => args.fmt(f),
435444
Args::MachO(args) => args.fmt(f),
445+
Args::Pe(args) => args.fmt(f),
436446
}
437447
}
438448
}
@@ -550,10 +560,46 @@ pub(crate) enum UnresolvedSymbols {
550560
IgnoreAll,
551561
}
552562

563+
#[derive(Clone, Copy)]
564+
enum OptionStyle {
565+
/// `--flag=value`, `-flag`, case-sensitive
566+
Unix,
567+
/// `/FLAG:value`, case-insensitive
568+
Windows,
569+
}
570+
571+
impl OptionStyle {
572+
fn strip_option(self, arg: &str) -> Option<&str> {
573+
match self {
574+
Self::Unix => arg.strip_prefix("--").or(arg.strip_prefix('-')),
575+
Self::Windows => arg.strip_prefix('/').or(arg.strip_prefix('-')),
576+
}
577+
}
578+
579+
fn has_option_prefix(self, arg: &str) -> bool {
580+
match self {
581+
Self::Unix => arg.starts_with('-'),
582+
Self::Windows => arg.starts_with('/') || arg.starts_with('-'),
583+
}
584+
}
585+
586+
fn find_separator(self, stripped: &str) -> Option<usize> {
587+
match self {
588+
Self::Unix => stripped.find('='),
589+
Self::Windows => stripped.find(':'),
590+
}
591+
}
592+
593+
fn is_case_insensitive(self) -> bool {
594+
matches!(self, Self::Windows)
595+
}
596+
}
597+
553598
struct ArgumentParser<T> {
554599
options: HashMap<&'static str, OptionHandler<T>>, // Long option lookup
555600
short_options: HashMap<&'static str, OptionHandler<T>>, // Short option lookup
556601
prefix_options: HashMap<&'static str, PrefixOptionHandler<T>>, // For options like -L, -l, etc.
602+
style: OptionStyle,
557603
}
558604

559605
impl<T: platform::Args> Default for ArgumentParser<T> {
@@ -569,6 +615,17 @@ impl<T: platform::Args> ArgumentParser<T> {
569615
options: HashMap::new(),
570616
short_options: HashMap::new(),
571617
prefix_options: HashMap::new(),
618+
style: OptionStyle::Unix,
619+
}
620+
}
621+
622+
#[must_use]
623+
fn new_windows() -> Self {
624+
Self {
625+
options: HashMap::new(),
626+
short_options: HashMap::new(),
627+
prefix_options: HashMap::new(),
628+
style: OptionStyle::Windows,
572629
}
573630
}
574631

@@ -608,6 +665,22 @@ impl<T: platform::Args> ArgumentParser<T> {
608665
}
609666
}
610667

668+
fn get_option_handler(&self, option_name: &str) -> Option<&OptionHandler<T>> {
669+
if self.style.is_case_insensitive() {
670+
if let Some(handler) = self.options.get(option_name) {
671+
return Some(handler);
672+
}
673+
for (key, handler) in &self.options {
674+
if key.eq_ignore_ascii_case(option_name) {
675+
return Some(handler);
676+
}
677+
}
678+
None
679+
} else {
680+
self.options.get(option_name)
681+
}
682+
}
683+
611684
fn handle_argument<S: AsRef<str>, I: Iterator<Item = S>>(
612685
&self,
613686
args: &mut T,
@@ -628,13 +701,12 @@ impl<T: platform::Args> ArgumentParser<T> {
628701
return Ok(());
629702
}
630703

631-
if let Some(stripped) = strip_option(arg) {
632-
// Check for option with '=' syntax
633-
if let Some(eq_pos) = stripped.find('=') {
704+
if let Some(stripped) = self.style.strip_option(arg) {
705+
if let Some(eq_pos) = self.style.find_separator(stripped) {
634706
let option_name = &stripped[..eq_pos];
635707
let value = &stripped[eq_pos + 1..];
636708

637-
if let Some(handler) = self.options.get(option_name) {
709+
if let Some(handler) = self.get_option_handler(option_name) {
638710
match &handler.handler {
639711
OptionHandlerFn::WithParam(f) => f(args, modifier_stack, value)?,
640712
OptionHandlerFn::OptionalParam(f) => f(args, modifier_stack, Some(value))?,
@@ -644,14 +716,14 @@ impl<T: platform::Args> ArgumentParser<T> {
644716
}
645717
} else {
646718
if stripped == "build-id"
647-
&& let Some(handler) = self.options.get(stripped)
719+
&& let Some(handler) = self.get_option_handler(stripped)
648720
&& let OptionHandlerFn::WithParam(f) = &handler.handler
649721
{
650722
f(args, modifier_stack, "fast")?;
651723
return Ok(());
652724
}
653725

654-
if let Some(handler) = self.options.get(stripped) {
726+
if let Some(handler) = self.get_option_handler(stripped) {
655727
match &handler.handler {
656728
OptionHandlerFn::NoParam(f) => f(args, modifier_stack)?,
657729
OptionHandlerFn::WithParam(f) => {
@@ -709,7 +781,6 @@ impl<T: platform::Args> ArgumentParser<T> {
709781
SubOptionHandler::WithValue(f) => f(args, modifier_stack, param_value)?,
710782
}
711783
} else {
712-
// Fall back to the main handler
713784
(handler.handler)(args, modifier_stack, &value)?;
714785
}
715786
} else {
@@ -730,8 +801,8 @@ impl<T: platform::Args> ArgumentParser<T> {
730801
}
731802
}
732803

733-
if arg.starts_with('-') {
734-
if let Some(stripped) = strip_option(arg)
804+
if self.style.has_option_prefix(arg) {
805+
if let Some(stripped) = self.style.strip_option(arg)
735806
&& IGNORED_FLAGS.contains(&stripped)
736807
{
737808
args.warn_unsupported(arg)?;
@@ -1092,10 +1163,6 @@ impl<'a, T> OptionDeclaration<'a, T, WithOptionalParam> {
10921163
}
10931164
}
10941165

1095-
fn strip_option(arg: &str) -> Option<&str> {
1096-
arg.strip_prefix("--").or(arg.strip_prefix('-'))
1097-
}
1098-
10991166
pub(crate) fn read_args_from_file(path: &Path) -> Result<Vec<String>> {
11001167
let contents = std::fs::read_to_string(path)
11011168
.with_context(|| format!("Failed to read arguments from file `{}`", path.display()))?;

0 commit comments

Comments
 (0)