From c54054338cf1967ac7e71a816b60e386a96af58a Mon Sep 17 00:00:00 2001 From: dalance Date: Fri, 25 Sep 2020 17:39:30 +0900 Subject: Add environment variables support --- src/lib.rs | 21 +++++++++++++++++++-- src/utils.rs | 24 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 80e2677..8c4c814 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,7 +77,10 @@ //! reflect the fact that no Pager is active. #![doc(html_root_url = "https://docs.rs/pager/0.15.0")] -#![cfg_attr(all(feature = "cargo-clippy", feature = "pedantic"), warn(clippy_pedantic))] +#![cfg_attr( + all(feature = "cargo-clippy", feature = "pedantic"), + warn(clippy_pedantic) +)] extern crate errno; extern crate libc; @@ -101,6 +104,7 @@ const DEFAULT_PAGER: &str = "more"; pub struct Pager { default_pager: Option, pager: Option, + envs: Vec, on: bool, skip_on_notty: bool, } @@ -110,6 +114,7 @@ impl Default for Pager { Self { default_pager: None, pager: env::var_os(DEFAULT_PAGER_ENV), + envs: Vec::new(), on: true, skip_on_notty: true, } @@ -155,6 +160,14 @@ impl Pager { } } + /// Launch pager with the specified environment variables + pub fn set_pager_envs(self, envs: &[&str]) -> Self { + Self { + envs: envs.into_iter().map(|x| x.into()).collect(), + ..self + } + } + /// Instructs `Pager` to bypass invoking pager if output is not a `tty` #[deprecated(since = "0.14.0", note = "'skip_on_notty' is default now")] pub fn skip_on_notty(self) -> Self { @@ -208,7 +221,11 @@ impl Pager { // I am parent utils::dup2(pager_stdin, libc::STDIN_FILENO); utils::close(main_stdout); - utils::execvp(pager); + if self.envs.is_empty() { + utils::execvp(pager); + } else { + utils::execvpe(pager, &self.envs); + } } } } else { diff --git a/src/utils.rs b/src/utils.rs index a826e45..65bd8f8 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -32,6 +32,30 @@ pub fn execvp(cmd: &OsString) { unsafe { libc::execvp(args[0], args.as_ptr()) }; } +pub fn execvpe(cmd: &OsString, envs: &[OsString]) { + let cstrings = split_string(cmd) + .into_iter() + .map(osstring2cstring) + .collect::>(); + let mut args = cstrings.iter().map(|c| c.as_ptr()).collect::>(); + args.push(ptr::null()); + + let mut cstrings_envs = envs + .into_iter() + .map(|s| osstring2cstring(s.clone())) + .collect::>(); + for (mut k, v) in std::env::vars_os() { + k.push("="); + k.push(v); + cstrings_envs.push(osstring2cstring(k)); + } + let mut envs = cstrings_envs.iter().map(|c| c.as_ptr()).collect::>(); + envs.push(ptr::null()); + + errno::set_errno(errno::Errno(0)); + unsafe { libc::execvpe(args[0], args.as_ptr(), envs.as_ptr()) }; +} + pub fn dup2(fd1: i32, fd2: i32) { assert!(unsafe { libc::dup2(fd1, fd2) } > -1); } -- cgit v1.2.3