Implement RFC 1014
Closes #25977 The various `stdfoo_raw` methods in std::io now return `io::Result`s, since they may not exist on Windows. They will always return `Ok` on Unix-like platforms. [breaking-change]
This commit is contained in:
parent
2228ce10c6
commit
a7bbd7da4e
7 changed files with 161 additions and 33 deletions
|
@ -19,6 +19,7 @@ use io::{self, BufReader, LineWriter};
|
||||||
use sync::{Arc, Mutex, MutexGuard};
|
use sync::{Arc, Mutex, MutexGuard};
|
||||||
use sys::stdio;
|
use sys::stdio;
|
||||||
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
||||||
|
use libc;
|
||||||
|
|
||||||
/// Stdout used by print! and println! macros
|
/// Stdout used by print! and println! macros
|
||||||
thread_local! {
|
thread_local! {
|
||||||
|
@ -52,7 +53,7 @@ struct StderrRaw(stdio::Stderr);
|
||||||
/// handles is **not** available to raw handles returned from this function.
|
/// handles is **not** available to raw handles returned from this function.
|
||||||
///
|
///
|
||||||
/// The returned handle has no external synchronization or buffering.
|
/// The returned handle has no external synchronization or buffering.
|
||||||
fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) }
|
fn stdin_raw() -> io::Result<StdinRaw> { stdio::Stdin::new().map(StdinRaw) }
|
||||||
|
|
||||||
/// Constructs a new raw handle to the standard input stream of this process.
|
/// Constructs a new raw handle to the standard input stream of this process.
|
||||||
///
|
///
|
||||||
|
@ -63,7 +64,7 @@ fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) }
|
||||||
///
|
///
|
||||||
/// The returned handle has no external synchronization or buffering layered on
|
/// The returned handle has no external synchronization or buffering layered on
|
||||||
/// top.
|
/// top.
|
||||||
fn stdout_raw() -> StdoutRaw { StdoutRaw(stdio::Stdout::new()) }
|
fn stdout_raw() -> io::Result<StdoutRaw> { stdio::Stdout::new().map(StdoutRaw) }
|
||||||
|
|
||||||
/// Constructs a new raw handle to the standard input stream of this process.
|
/// Constructs a new raw handle to the standard input stream of this process.
|
||||||
///
|
///
|
||||||
|
@ -72,7 +73,7 @@ fn stdout_raw() -> StdoutRaw { StdoutRaw(stdio::Stdout::new()) }
|
||||||
///
|
///
|
||||||
/// The returned handle has no external synchronization or buffering layered on
|
/// The returned handle has no external synchronization or buffering layered on
|
||||||
/// top.
|
/// top.
|
||||||
fn stderr_raw() -> StderrRaw { StderrRaw(stdio::Stderr::new()) }
|
fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) }
|
||||||
|
|
||||||
impl Read for StdinRaw {
|
impl Read for StdinRaw {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
|
||||||
|
@ -86,6 +87,48 @@ impl Write for StderrRaw {
|
||||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Maybe<T> {
|
||||||
|
Real(T),
|
||||||
|
Fake,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: io::Write> io::Write for Maybe<W> {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
match *self {
|
||||||
|
Maybe::Real(ref mut w) => handle_ebadf(w.write(buf), buf.len()),
|
||||||
|
Maybe::Fake => Ok(buf.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
match *self {
|
||||||
|
Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()),
|
||||||
|
Maybe::Fake => Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: io::Read> io::Read for Maybe<R> {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
match *self {
|
||||||
|
Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), buf.len()),
|
||||||
|
Maybe::Fake => Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
|
||||||
|
#[cfg(windows)]
|
||||||
|
const ERR: libc::c_int = libc::ERROR_INVALID_HANDLE;
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
const ERR: libc::c_int = libc::EBADF;
|
||||||
|
|
||||||
|
match r {
|
||||||
|
Err(ref e) if e.raw_os_error() == Some(ERR) => Ok(default),
|
||||||
|
r => r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A handle to the standard input stream of a process.
|
/// A handle to the standard input stream of a process.
|
||||||
///
|
///
|
||||||
/// Each handle is a shared reference to a global buffer of input data to this
|
/// Each handle is a shared reference to a global buffer of input data to this
|
||||||
|
@ -99,7 +142,7 @@ impl Write for StderrRaw {
|
||||||
/// Created by the function `io::stdin()`.
|
/// Created by the function `io::stdin()`.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Stdin {
|
pub struct Stdin {
|
||||||
inner: Arc<Mutex<BufReader<StdinRaw>>>,
|
inner: Arc<Mutex<BufReader<Maybe<StdinRaw>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A locked reference to the a `Stdin` handle.
|
/// A locked reference to the a `Stdin` handle.
|
||||||
|
@ -108,7 +151,7 @@ pub struct Stdin {
|
||||||
/// constructed via the `lock` method on `Stdin`.
|
/// constructed via the `lock` method on `Stdin`.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct StdinLock<'a> {
|
pub struct StdinLock<'a> {
|
||||||
inner: MutexGuard<'a, BufReader<StdinRaw>>,
|
inner: MutexGuard<'a, BufReader<Maybe<StdinRaw>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new handle to the global standard input stream of this process.
|
/// Creates a new handle to the global standard input stream of this process.
|
||||||
|
@ -122,20 +165,25 @@ pub struct StdinLock<'a> {
|
||||||
/// locked version, `StdinLock`, implements both `Read` and `BufRead`, however.
|
/// locked version, `StdinLock`, implements both `Read` and `BufRead`, however.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn stdin() -> Stdin {
|
pub fn stdin() -> Stdin {
|
||||||
static INSTANCE: Lazy<Mutex<BufReader<StdinRaw>>> = Lazy::new(stdin_init);
|
static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new(stdin_init);
|
||||||
return Stdin {
|
return Stdin {
|
||||||
inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
|
inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
|
||||||
};
|
};
|
||||||
|
|
||||||
fn stdin_init() -> Arc<Mutex<BufReader<StdinRaw>>> {
|
fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
|
||||||
|
let stdin = match stdin_raw() {
|
||||||
|
Ok(stdin) => Maybe::Real(stdin),
|
||||||
|
_ => Maybe::Fake
|
||||||
|
};
|
||||||
|
|
||||||
// The default buffer capacity is 64k, but apparently windows
|
// The default buffer capacity is 64k, but apparently windows
|
||||||
// doesn't like 64k reads on stdin. See #13304 for details, but the
|
// doesn't like 64k reads on stdin. See #13304 for details, but the
|
||||||
// idea is that on windows we use a slightly smaller buffer that's
|
// idea is that on windows we use a slightly smaller buffer that's
|
||||||
// been seen to be acceptable.
|
// been seen to be acceptable.
|
||||||
Arc::new(Mutex::new(if cfg!(windows) {
|
Arc::new(Mutex::new(if cfg!(windows) {
|
||||||
BufReader::with_capacity(8 * 1024, stdin_raw())
|
BufReader::with_capacity(8 * 1024, stdin)
|
||||||
} else {
|
} else {
|
||||||
BufReader::new(stdin_raw())
|
BufReader::new(stdin)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,6 +229,7 @@ impl<'a> Read for StdinLock<'a> {
|
||||||
self.inner.read(buf)
|
self.inner.read(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<'a> BufRead for StdinLock<'a> {
|
impl<'a> BufRead for StdinLock<'a> {
|
||||||
fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() }
|
fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() }
|
||||||
|
@ -215,7 +264,7 @@ pub struct Stdout {
|
||||||
// FIXME: this should be LineWriter or BufWriter depending on the state of
|
// FIXME: this should be LineWriter or BufWriter depending on the state of
|
||||||
// stdout (tty or not). Note that if this is not line buffered it
|
// stdout (tty or not). Note that if this is not line buffered it
|
||||||
// should also flush-on-panic or some form of flush-on-abort.
|
// should also flush-on-panic or some form of flush-on-abort.
|
||||||
inner: Arc<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
|
inner: Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A locked reference to the a `Stdout` handle.
|
/// A locked reference to the a `Stdout` handle.
|
||||||
|
@ -224,7 +273,7 @@ pub struct Stdout {
|
||||||
/// method on `Stdout`.
|
/// method on `Stdout`.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct StdoutLock<'a> {
|
pub struct StdoutLock<'a> {
|
||||||
inner: ReentrantMutexGuard<'a, RefCell<LineWriter<StdoutRaw>>>,
|
inner: ReentrantMutexGuard<'a, RefCell<LineWriter<Maybe<StdoutRaw>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new reference to the standard output of the current process.
|
/// Constructs a new reference to the standard output of the current process.
|
||||||
|
@ -236,13 +285,18 @@ pub struct StdoutLock<'a> {
|
||||||
/// The returned handle implements the `Write` trait.
|
/// The returned handle implements the `Write` trait.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn stdout() -> Stdout {
|
pub fn stdout() -> Stdout {
|
||||||
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = Lazy::new(stdout_init);
|
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
|
||||||
|
= Lazy::new(stdout_init);
|
||||||
return Stdout {
|
return Stdout {
|
||||||
inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
|
inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
|
||||||
};
|
};
|
||||||
|
|
||||||
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> {
|
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
|
||||||
Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))))
|
let stdout = match stdout_raw() {
|
||||||
|
Ok(stdout) => Maybe::Real(stdout),
|
||||||
|
_ => Maybe::Fake,
|
||||||
|
};
|
||||||
|
Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +342,7 @@ impl<'a> Write for StdoutLock<'a> {
|
||||||
/// For more information, see `stderr`
|
/// For more information, see `stderr`
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct Stderr {
|
pub struct Stderr {
|
||||||
inner: Arc<ReentrantMutex<RefCell<StderrRaw>>>,
|
inner: Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A locked reference to the a `Stderr` handle.
|
/// A locked reference to the a `Stderr` handle.
|
||||||
|
@ -297,7 +351,7 @@ pub struct Stderr {
|
||||||
/// method on `Stderr`.
|
/// method on `Stderr`.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub struct StderrLock<'a> {
|
pub struct StderrLock<'a> {
|
||||||
inner: ReentrantMutexGuard<'a, RefCell<StderrRaw>>,
|
inner: ReentrantMutexGuard<'a, RefCell<Maybe<StderrRaw>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new reference to the standard error stream of a process.
|
/// Constructs a new reference to the standard error stream of a process.
|
||||||
|
@ -308,13 +362,17 @@ pub struct StderrLock<'a> {
|
||||||
/// The returned handle implements the `Write` trait.
|
/// The returned handle implements the `Write` trait.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn stderr() -> Stderr {
|
pub fn stderr() -> Stderr {
|
||||||
static INSTANCE: Lazy<ReentrantMutex<RefCell<StderrRaw>>> = Lazy::new(stderr_init);
|
static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init);
|
||||||
return Stderr {
|
return Stderr {
|
||||||
inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
|
inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
|
||||||
};
|
};
|
||||||
|
|
||||||
fn stderr_init() -> Arc<ReentrantMutex<RefCell<StderrRaw>>> {
|
fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
|
||||||
Arc::new(ReentrantMutex::new(RefCell::new(stderr_raw())))
|
let stderr = match stderr_raw() {
|
||||||
|
Ok(stderr) => Maybe::Real(stderr),
|
||||||
|
_ => Maybe::Fake,
|
||||||
|
};
|
||||||
|
Arc::new(ReentrantMutex::new(RefCell::new(stderr)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,10 @@ pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
|
||||||
None => "Box<Any>",
|
None => "Box<Any>",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut err = Stderr::new();
|
let mut err = match Stderr::new() {
|
||||||
|
Ok(err) => err,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
let thread = thread_info::current_thread();
|
let thread = thread_info::current_thread();
|
||||||
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
|
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
|
||||||
let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
|
let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
|
||||||
|
|
|
@ -63,7 +63,7 @@ pub const ENFORCE_SANITY: bool = true || !cfg!(rtopt) || cfg!(rtdebug) ||
|
||||||
cfg!(rtassert);
|
cfg!(rtassert);
|
||||||
|
|
||||||
pub fn dumb_print(args: fmt::Arguments) {
|
pub fn dumb_print(args: fmt::Arguments) {
|
||||||
let _ = Stderr::new().write_fmt(args);
|
let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn abort(args: fmt::Arguments) -> ! {
|
pub fn abort(args: fmt::Arguments) -> ! {
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub struct Stdout(());
|
||||||
pub struct Stderr(());
|
pub struct Stderr(());
|
||||||
|
|
||||||
impl Stdin {
|
impl Stdin {
|
||||||
pub fn new() -> Stdin { Stdin(()) }
|
pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
|
||||||
|
|
||||||
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
|
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
|
||||||
let fd = FileDesc::new(libc::STDIN_FILENO);
|
let fd = FileDesc::new(libc::STDIN_FILENO);
|
||||||
|
@ -30,7 +30,7 @@ impl Stdin {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stdout {
|
impl Stdout {
|
||||||
pub fn new() -> Stdout { Stdout(()) }
|
pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
|
||||||
|
|
||||||
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
||||||
let fd = FileDesc::new(libc::STDOUT_FILENO);
|
let fd = FileDesc::new(libc::STDOUT_FILENO);
|
||||||
|
@ -41,7 +41,7 @@ impl Stdout {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stderr {
|
impl Stderr {
|
||||||
pub fn new() -> Stderr { Stderr(()) }
|
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
|
||||||
|
|
||||||
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
||||||
let fd = FileDesc::new(libc::STDERR_FILENO);
|
let fd = FileDesc::new(libc::STDERR_FILENO);
|
||||||
|
|
|
@ -77,11 +77,13 @@ fn write(out: &Output, data: &[u8]) -> io::Result<usize> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stdin {
|
impl Stdin {
|
||||||
pub fn new() -> Stdin {
|
pub fn new() -> io::Result<Stdin> {
|
||||||
Stdin {
|
get(c::STD_INPUT_HANDLE).map(|handle| {
|
||||||
handle: get(c::STD_INPUT_HANDLE).unwrap(),
|
Stdin {
|
||||||
utf8: Mutex::new(Cursor::new(Vec::new())),
|
handle: handle,
|
||||||
}
|
utf8: Mutex::new(Cursor::new(Vec::new())),
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
@ -116,8 +118,8 @@ impl Stdin {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stdout {
|
impl Stdout {
|
||||||
pub fn new() -> Stdout {
|
pub fn new() -> io::Result<Stdout> {
|
||||||
Stdout(get(c::STD_OUTPUT_HANDLE).unwrap())
|
get(c::STD_OUTPUT_HANDLE).map(Stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
||||||
|
@ -126,8 +128,8 @@ impl Stdout {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stderr {
|
impl Stderr {
|
||||||
pub fn new() -> Stderr {
|
pub fn new() -> io::Result<Stderr> {
|
||||||
Stderr(get(c::STD_ERROR_HANDLE).unwrap())
|
get(c::STD_ERROR_HANDLE).map(Stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
||||||
|
|
32
src/test/run-pass/rfc-1014-2.rs
Normal file
32
src/test/run-pass/rfc-1014-2.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
#![feature(libc)]
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
extern "system" {
|
||||||
|
fn SetStdHandle(nStdHandle: libc::DWORD, nHandle: libc::HANDLE) -> libc::BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn close_stdout() {
|
||||||
|
const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD;
|
||||||
|
unsafe { SetStdHandle(STD_OUTPUT_HANDLE, 0 as libc::HANDLE); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn main() {
|
||||||
|
close_stdout();
|
||||||
|
println!("hello world");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
fn main() {}
|
33
src/test/run-pass/rfc-1014.rs
Normal file
33
src/test/run-pass/rfc-1014.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
#![feature(libc)]
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
extern "system" {
|
||||||
|
pub fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn close_stdout() {
|
||||||
|
const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD;
|
||||||
|
unsafe { libc::CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
fn close_stdout() {
|
||||||
|
unsafe { libc::close(libc::STDOUT_FILENO); }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
close_stdout();
|
||||||
|
println!("hello world");
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue