Skip to content

Commit b642d13

Browse files
committed
Support interpreting OEM code page output on windows.
1 parent dbec74f commit b642d13

File tree

1 file changed

+88
-10
lines changed
  • src/librustc_codegen_ssa/back

1 file changed

+88
-10
lines changed

src/librustc_codegen_ssa/back/link.rs

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use tempfile::{Builder as TempFileBuilder, TempDir};
2525

2626
use std::ascii;
2727
use std::char;
28+
use std::borrow::Cow;
2829
use std::fmt;
2930
use std::fs;
3031
use std::io;
@@ -417,6 +418,93 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
417418
}
418419
}
419420

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+
420508
// Create a dynamic library or executable
421509
//
422510
// 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,
586674

587675
match prog {
588676
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-
}
599677
if !prog.status.success() {
600678
let mut output = prog.stderr.clone();
601679
output.extend_from_slice(&prog.stdout);

0 commit comments

Comments
 (0)