@@ -25,6 +25,7 @@ use tempfile::{Builder as TempFileBuilder, TempDir};
25
25
26
26
use std:: ascii;
27
27
use std:: char;
28
+ use std:: borrow:: Cow ;
28
29
use std:: fmt;
29
30
use std:: fs;
30
31
use std:: io;
@@ -417,6 +418,93 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
417
418
}
418
419
}
419
420
421
+ #[ cfg( not( windows) ) ]
422
+ fn escape_win_oemcp_str ( s : & [ u8 ] ) -> Result < String , & [ u8 ] > {
423
+ Err ( s)
424
+ }
425
+
426
+ #[ cfg( windows) ]
427
+ fn escape_win_oemcp_str ( s : & [ u8 ] ) -> Result < String , & [ u8 ] > {
428
+ use std:: ffi:: OsString ;
429
+ use std:: os:: raw:: { c_char, c_int, c_uint, c_ulong} ;
430
+ use std:: os:: windows:: ffi:: OsStringExt ;
431
+ use std:: ptr:: null_mut;
432
+ type UINT = c_uint ;
433
+ type DWORD = c_ulong ;
434
+ type LPCSTR = * const c_char ;
435
+ type LPWSTR = * mut u16 ;
436
+ const CP_OEMCP : DWORD = 1 ;
437
+ const MB_ERR_INVALID_CHARS : DWORD = 0x00000008 ;
438
+ extern "system" {
439
+ fn MultiByteToWideChar (
440
+ CodePage : UINT ,
441
+ dwFlags : DWORD ,
442
+ lpMultiByteStr : LPCSTR ,
443
+ cbMultiByte : c_int ,
444
+ lpWideCharStr : LPWSTR ,
445
+ cchWideChar : c_int ,
446
+ ) -> c_int ;
447
+ }
448
+ if s. is_empty ( ) {
449
+ return Ok ( String :: new ( ) ) ;
450
+ }
451
+ if s. len ( ) > libc:: INT_MAX as _ {
452
+ return Err ( s) ;
453
+ }
454
+ let len = unsafe {
455
+ let l = MultiByteToWideChar (
456
+ CP_OEMCP ,
457
+ MB_ERR_INVALID_CHARS ,
458
+ s. as_ptr ( ) as _ ,
459
+ s. len ( ) as c_int ,
460
+ null_mut ( ) ,
461
+ 0 ,
462
+ ) ;
463
+ match l {
464
+ 0 => return Err ( s) ,
465
+ x => x,
466
+ }
467
+ } ;
468
+ assert ! ( len > 0 ) ;
469
+ let mut widestr = vec ! [ 0u16 ; len as usize ] ;
470
+ unsafe {
471
+ let l = MultiByteToWideChar (
472
+ CP_OEMCP ,
473
+ MB_ERR_INVALID_CHARS ,
474
+ s. as_ptr ( ) as _ ,
475
+ s. len ( ) as c_int ,
476
+ widestr. as_mut_ptr ( ) ,
477
+ len,
478
+ ) ;
479
+ assert_eq ! ( l, len) ;
480
+ }
481
+ let os_string = OsString :: from_wide ( & widestr[ ..] ) ;
482
+ let x = match os_string. into_string ( ) {
483
+ Err ( _) => return Err ( s) ,
484
+ Ok ( x) => x,
485
+ } ;
486
+ Ok ( x)
487
+ }
488
+
489
+ fn escape_string ( s : & [ u8 ] ) -> Cow < ' _ , str > {
490
+ // UTF-8
491
+ if let Ok ( x) = str:: from_utf8 ( s) {
492
+ return Cow :: Borrowed ( x) ;
493
+ }
494
+
495
+ // Windows OEMCP
496
+ if let Ok ( os) = escape_win_oemcp_str ( s) {
497
+ let mut x = "OEM codepage output: " . to_string ( ) ;
498
+ x += & os;
499
+ return Cow :: Owned ( x) ;
500
+ }
501
+
502
+ // Fallback: Non-UTF-8
503
+ let mut x = "Non-UTF-8 output: " . to_string ( ) ;
504
+ x. extend ( s. iter ( ) . flat_map ( |& b| ascii:: escape_default ( b) ) . map ( char:: from) ) ;
505
+ Cow :: Owned ( x)
506
+ }
507
+
420
508
// Create a dynamic library or executable
421
509
//
422
510
// This will invoke the system linker/cc to create the resulting file. This
@@ -586,16 +674,6 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
586
674
587
675
match prog {
588
676
Ok ( prog) => {
589
- fn escape_string ( s : & [ u8 ] ) -> String {
590
- str:: from_utf8 ( s) . map ( |s| s. to_owned ( ) )
591
- . unwrap_or_else ( |_| {
592
- let mut x = "Non-UTF-8 output: " . to_string ( ) ;
593
- x. extend ( s. iter ( )
594
- . flat_map ( |& b| ascii:: escape_default ( b) )
595
- . map ( char:: from) ) ;
596
- x
597
- } )
598
- }
599
677
if !prog. status . success ( ) {
600
678
let mut output = prog. stderr . clone ( ) ;
601
679
output. extend_from_slice ( & prog. stdout ) ;
0 commit comments