@@ -98,11 +98,13 @@ struct DropGuard<'a> {
98
98
lock : & ' a Mutex ,
99
99
}
100
100
101
- enum Problem {
101
+ pub enum Problem {
102
102
SawNul ,
103
103
Oversized ,
104
104
}
105
105
106
+ pub struct RawArg < ' a > ( & ' a OsStr ) ;
107
+
106
108
impl Command {
107
109
pub fn new ( program : & OsStr ) -> Command {
108
110
Command {
@@ -136,7 +138,7 @@ impl Command {
136
138
137
139
self . args . push ( arg. to_os_string ( ) ) ;
138
140
self . cmdline . push ( ' ' as u16 ) ;
139
- let result = append_arg ( & mut self . cmdline , arg , false ) ;
141
+ let result = arg . append_to ( & mut self . cmdline , false ) ;
140
142
match result {
141
143
Err ( err) => {
142
144
self . cmdline . truncate ( self . cmdline . len ( ) - 1 ) ;
@@ -203,7 +205,7 @@ impl Command {
203
205
// Prepare and terminate the application name and the cmdline
204
206
// XXX: this won't work for 16-bit, might be preferable to do a extend_from_slice
205
207
let mut program_str: Vec < u16 > = Vec :: new ( ) ;
206
- append_arg ( & mut program_str, program , true ) ?;
208
+ program . as_os_str ( ) . append_to ( & mut program_str, true ) ?;
207
209
program_str. push ( 0 ) ;
208
210
self . cmdline . push ( 0 ) ;
209
211
@@ -385,6 +387,31 @@ impl From<Problem> for Error {
385
387
}
386
388
}
387
389
390
+ pub trait Arg {
391
+ fn append_to ( & self , cmd : & mut Vec < u16 > , force_quotes : bool ) -> Result < usize , Problem > ;
392
+ fn arg_len ( & self , force_quotes : bool ) -> Result < usize , Problem > ;
393
+ }
394
+
395
+ impl Arg for & OsStr {
396
+ fn append_to ( & self , cmd : & mut Vec < u16 > , force_quotes : bool ) -> Result < usize , Problem > {
397
+ append_arg ( & mut Some ( cmd) , & self , force_quotes)
398
+ }
399
+ fn arg_len ( & self , force_quotes : bool ) -> Result < usize , Problem > {
400
+ append_arg ( & mut None , & self , force_quotes)
401
+ }
402
+ }
403
+
404
+ #[ allow( dead_code) ]
405
+ impl Arg for RawArg < ' _ > {
406
+ fn append_to ( & self , cmd : & mut Vec < u16 > , _fq : bool ) -> Result < usize , Problem > {
407
+ cmd. extend ( self . 0 . encode_wide ( ) ) ;
408
+ self . arg_len ( _fq)
409
+ }
410
+ fn arg_len ( & self , _: bool ) -> Result < usize , Problem > {
411
+ Ok ( self . 0 . encode_wide ( ) . count ( ) )
412
+ }
413
+ }
414
+
388
415
////////////////////////////////////////////////////////////////////////////////
389
416
// Processes
390
417
////////////////////////////////////////////////////////////////////////////////
@@ -523,7 +550,23 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION {
523
550
}
524
551
}
525
552
526
- fn append_arg ( cmd : & mut Vec < u16 > , arg : & OsStr , force_quotes : bool ) -> Result < usize , Problem > {
553
+ macro_rules! if_some {
554
+ ( $e: expr, $id: ident, $b: block) => {
555
+ if let & mut Some ( ref mut $id) = $e
556
+ $b
557
+ } ;
558
+ ( $e: expr, $id: ident, $s: stmt) => {
559
+ if_some!( $e, $id, { $s } )
560
+ } ;
561
+ }
562
+
563
+ // This is effed up. Yeah, how the heck do I pass an optional, mutable reference around?
564
+ // @see https://users.rust-lang.org/t/idiomatic-way-for-passing-an-optional-mutable-reference-around/7947
565
+ fn append_arg (
566
+ maybe_cmd : & mut Option < & mut Vec < u16 > > ,
567
+ arg : & OsStr ,
568
+ force_quotes : bool ,
569
+ ) -> Result < usize , Problem > {
527
570
let mut addsize: usize = 0 ;
528
571
// If an argument has 0 characters then we need to quote it to ensure
529
572
// that it actually gets passed through on the command line or otherwise
@@ -533,7 +576,7 @@ fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, force_quotes: bool) -> Result<usi
533
576
let quote =
534
577
force_quotes || arg_bytes. iter ( ) . any ( |c| * c == b' ' || * c == b'\t' ) || arg_bytes. is_empty ( ) ;
535
578
if quote {
536
- cmd. push ( '"' as u16 ) ;
579
+ if_some ! ( maybe_cmd , cmd, cmd . push( '"' as u16 ) ) ;
537
580
addsize += 1 ;
538
581
}
539
582
@@ -544,18 +587,20 @@ fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, force_quotes: bool) -> Result<usi
544
587
} else {
545
588
if x == '"' as u16 {
546
589
// Add n+1 backslashes to total 2n+1 before internal '"'.
547
- cmd. extend ( ( 0 ..=backslashes) . map ( |_| '\\' as u16 ) ) ;
590
+ if_some ! ( maybe_cmd , cmd, cmd . extend( ( 0 ..=backslashes) . map( |_| '\\' as u16 ) ) ) ;
548
591
addsize += backslashes + 1 ;
549
592
}
550
593
backslashes = 0 ;
551
594
}
552
- cmd. push ( x) ;
595
+ if_some ! ( maybe_cmd , cmd, cmd . push( x) ) ;
553
596
}
554
597
555
598
if quote {
556
599
// Add n backslashes to total 2n before ending '"'.
557
- cmd. extend ( ( 0 ..backslashes) . map ( |_| '\\' as u16 ) ) ;
558
- cmd. push ( '"' as u16 ) ;
600
+ if_some ! ( maybe_cmd, cmd, {
601
+ cmd. extend( ( 0 ..backslashes) . map( |_| '\\' as u16 ) ) ;
602
+ cmd. push( '"' as u16 ) ;
603
+ } ) ;
559
604
addsize += backslashes + 1 ;
560
605
}
561
606
Ok ( addsize)
@@ -570,10 +615,10 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
570
615
let mut cmd: Vec < u16 > = Vec :: new ( ) ;
571
616
// Always quote the program name so CreateProcess doesn't interpret args as
572
617
// part of the name if the binary wasn't found first time.
573
- append_arg ( & mut cmd, prog , true ) ?;
618
+ prog . append_to ( & mut cmd, true ) ?;
574
619
for arg in args {
575
620
cmd. push ( ' ' as u16 ) ;
576
- append_arg ( & mut cmd, arg , false ) ?;
621
+ arg . as_os_str ( ) . append_to ( & mut cmd, false ) ?;
577
622
}
578
623
return Ok ( cmd) ;
579
624
}
0 commit comments