Skip to content

Commit 5d2ac30

Browse files
authored
Merge pull request #9841 from sylvestre/env-dedup
env/printenv: dedup the code
2 parents c6271b6 + 50085d7 commit 5d2ac30

File tree

4 files changed

+39
-28
lines changed

4 files changed

+39
-28
lines changed

src/uu/env/src/env.rs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ use nix::sys::signal::{SigHandler::SigIgn, Signal, signal};
2424
use std::borrow::Cow;
2525
use std::env;
2626
use std::ffi::{OsStr, OsString};
27-
use std::io::{self, Write};
27+
use std::io;
2828
#[cfg(unix)]
2929
use std::os::unix::ffi::OsStrExt;
3030
#[cfg(unix)]
3131
use std::os::unix::process::CommandExt;
3232

33-
use uucore::display::{OsWrite, Quotable};
33+
use uucore::display::{Quotable, print_all_env_vars};
3434
use uucore::error::{ExitCode, UError, UResult, USimpleError, UUsageError};
3535
use uucore::line_ending::LineEnding;
3636
#[cfg(unix)]
@@ -99,19 +99,6 @@ struct Options<'a> {
9999
ignore_signal: Vec<usize>,
100100
}
101101

102-
/// print `name=value` env pairs on screen
103-
fn print_env(line_ending: LineEnding) -> io::Result<()> {
104-
let stdout_raw = io::stdout();
105-
let mut stdout = stdout_raw.lock();
106-
for (n, v) in env::vars_os() {
107-
stdout.write_all_os(&n)?;
108-
stdout.write_all(b"=")?;
109-
stdout.write_all_os(&v)?;
110-
write!(stdout, "{line_ending}")?;
111-
}
112-
Ok(())
113-
}
114-
115102
fn parse_name_value_opt<'a>(opts: &mut Options<'a>, opt: &'a OsStr) -> UResult<bool> {
116103
// is it a NAME=VALUE like opt ?
117104
let wrap = NativeStr::<'a>::new(opt);
@@ -552,7 +539,7 @@ impl EnvAppData {
552539

553540
if opts.program.is_empty() {
554541
// no program provided, so just dump all env vars to stdout
555-
print_env(opts.line_ending)?;
542+
print_all_env_vars(opts.line_ending)?;
556543
} else {
557544
return self.run_program(&opts, self.do_debug_printing);
558545
}

src/uu/printenv/src/printenv.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ use std::io::Write;
88

99
use clap::{Arg, ArgAction, Command};
1010

11+
use uucore::display::{OsWrite, print_all_env_vars};
1112
use uucore::error::UResult;
1213
use uucore::line_ending::LineEnding;
13-
use uucore::{format_usage, os_str_as_bytes, translate};
14+
use uucore::{format_usage, translate};
1415

1516
static OPT_NULL: &str = "null";
1617

@@ -28,14 +29,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
2829
let separator = LineEnding::from_zero_flag(matches.get_flag(OPT_NULL));
2930

3031
if variables.is_empty() {
31-
for (env_var, value) in env::vars_os() {
32-
let env_bytes = os_str_as_bytes(&env_var)?;
33-
let val_bytes = os_str_as_bytes(&value)?;
34-
std::io::stdout().lock().write_all(env_bytes)?;
35-
print!("=");
36-
std::io::stdout().lock().write_all(val_bytes)?;
37-
print!("{separator}");
38-
}
32+
print_all_env_vars(separator)?;
3933
return Ok(());
4034
}
4135

@@ -47,9 +41,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
4741
continue;
4842
}
4943
if let Some(var) = env::var_os(env_var) {
50-
let val_bytes = os_str_as_bytes(&var)?;
51-
std::io::stdout().lock().write_all(val_bytes)?;
52-
print!("{separator}");
44+
let mut stdout = std::io::stdout().lock();
45+
stdout.write_all_os(&var)?;
46+
write!(stdout, "{separator}")?;
5347
} else {
5448
error_found = true;
5549
}

src/uucore/src/lib/mods/display.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
//! # Ok::<(), std::io::Error>(())
2525
//! ```
2626
27+
use std::env;
2728
use std::ffi::OsStr;
29+
use std::fmt;
2830
use std::fs::File;
2931
use std::io::{self, BufWriter, Stdout, StdoutLock, Write as IoWrite};
3032

@@ -117,3 +119,18 @@ impl OsWrite for Box<dyn OsWrite> {
117119
this.write_all_os(buf)
118120
}
119121
}
122+
123+
/// Print all environment variables in the format `name=value` with the specified line ending.
124+
///
125+
/// This function handles non-UTF-8 environment variable names and values correctly by using
126+
/// raw bytes on Unix systems.
127+
pub fn print_all_env_vars<T: fmt::Display>(line_ending: T) -> io::Result<()> {
128+
let mut stdout = io::stdout().lock();
129+
for (name, value) in env::vars_os() {
130+
stdout.write_all_os(&name)?;
131+
stdout.write_all(b"=")?;
132+
stdout.write_all_os(&value)?;
133+
write!(stdout, "{line_ending}")?;
134+
}
135+
Ok(())
136+
}

tests/by-util/test_printenv.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,16 @@ fn test_non_utf8_value() {
117117
);
118118
result.stdout_is_bytes(b"/tmp/lib.so\xff\n");
119119
}
120+
121+
#[test]
122+
#[cfg(unix)]
123+
fn test_non_utf8_env_vars() {
124+
use std::ffi::OsString;
125+
use std::os::unix::ffi::OsStringExt;
126+
127+
let non_utf8_value = OsString::from_vec(b"hello\x80world".to_vec());
128+
new_ucmd!()
129+
.env("NON_UTF8_VAR", &non_utf8_value)
130+
.succeeds()
131+
.stdout_contains_bytes(b"NON_UTF8_VAR=hello\x80world");
132+
}

0 commit comments

Comments
 (0)