Skip to content

Commit d22b164

Browse files
committed
Use str::from_utf8_lossy() for os::env() and friends
Parse the environment by default with from_utf8_lossy. Also provide byte-vector equivalents (e.g. os::env_as_bytes()). Unfortunately, setenv() can't have a byte-vector equivalent because of Windows support, unless we want to define a setenv_bytes() that fails under Windows for non-UTF8 (or non-UTF16).
1 parent c73d5ce commit d22b164

File tree

1 file changed

+60
-11
lines changed

1 file changed

+60
-11
lines changed

src/libstd/os.rs

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,23 @@ fn with_env_lock<T>(f: || -> T) -> T {
160160

161161
/// Returns a vector of (variable, value) pairs for all the environment
162162
/// variables of the current process.
163+
///
164+
/// Invalid UTF-8 bytes are replaced with \uFFFD. See `str::from_utf8_lossy()`
165+
/// for details.
163166
pub fn env() -> ~[(~str,~str)] {
167+
env_as_bytes().move_iter().map(|(k,v)| {
168+
let k = str::from_utf8_lossy(k).into_owned();
169+
let v = str::from_utf8_lossy(v).into_owned();
170+
(k,v)
171+
}).collect()
172+
}
173+
174+
/// Returns a vector of (variable, value) byte-vector pairs for all the
175+
/// environment variables of the current process.
176+
pub fn env_as_bytes() -> ~[(~[u8],~[u8])] {
164177
unsafe {
165178
#[cfg(windows)]
166-
unsafe fn get_env_pairs() -> ~[~str] {
179+
unsafe fn get_env_pairs() -> ~[~[u8]] {
167180
use c_str;
168181
use str::StrSlice;
169182

@@ -178,13 +191,15 @@ pub fn env() -> ~[(~str,~str)] {
178191
}
179192
let mut result = ~[];
180193
c_str::from_c_multistring(ch as *c_char, None, |cstr| {
181-
result.push(cstr.as_str().unwrap().to_owned());
194+
result.push(cstr.as_bytes_no_nul().to_owned());
182195
});
183196
FreeEnvironmentStringsA(ch);
184197
result
185198
}
186199
#[cfg(unix)]
187-
unsafe fn get_env_pairs() -> ~[~str] {
200+
unsafe fn get_env_pairs() -> ~[~[u8]] {
201+
use c_str::CString;
202+
188203
extern {
189204
fn rust_env_pairs() -> **c_char;
190205
}
@@ -195,20 +210,19 @@ pub fn env() -> ~[(~str,~str)] {
195210
}
196211
let mut result = ~[];
197212
ptr::array_each(environ, |e| {
198-
let env_pair = str::raw::from_c_str(e);
199-
debug!("get_env_pairs: {}", env_pair);
213+
let env_pair = CString::new(e, false).as_bytes_no_nul().to_owned();
200214
result.push(env_pair);
201215
});
202216
result
203217
}
204218

205-
fn env_convert(input: ~[~str]) -> ~[(~str, ~str)] {
219+
fn env_convert(input: ~[~[u8]]) -> ~[(~[u8], ~[u8])] {
206220
let mut pairs = ~[];
207221
for p in input.iter() {
208-
let vs: ~[&str] = p.splitn('=', 1).collect();
209-
debug!("splitting: len: {}", vs.len());
210-
assert_eq!(vs.len(), 2);
211-
pairs.push((vs[0].to_owned(), vs[1].to_owned()));
222+
let vs: ~[&[u8]] = p.splitn(1, |b| *b == '=' as u8).collect();
223+
let key = vs[0].to_owned();
224+
let val = (if vs.len() < 2 { ~[] } else { vs[1].to_owned() });
225+
pairs.push((key, val));
212226
}
213227
pairs
214228
}
@@ -222,14 +236,34 @@ pub fn env() -> ~[(~str,~str)] {
222236
#[cfg(unix)]
223237
/// Fetches the environment variable `n` from the current process, returning
224238
/// None if the variable isn't set.
239+
///
240+
/// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
241+
/// `str::from_utf8_lossy()` for details.
242+
///
243+
/// # Failure
244+
///
245+
/// Fails if `n` has any interior NULs.
225246
pub fn getenv(n: &str) -> Option<~str> {
247+
getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v).into_owned())
248+
}
249+
250+
#[cfg(unix)]
251+
/// Fetches the environment variable `n` byte vector from the current process,
252+
/// returning None if the variable isn't set.
253+
///
254+
/// # Failure
255+
///
256+
/// Fails if `n` has any interior NULs.
257+
pub fn getenv_as_bytes(n: &str) -> Option<~[u8]> {
258+
use c_str::CString;
259+
226260
unsafe {
227261
with_env_lock(|| {
228262
let s = n.with_c_str(|buf| libc::getenv(buf));
229263
if s.is_null() {
230264
None
231265
} else {
232-
Some(str::raw::from_c_str(s))
266+
Some(CString::new(s, false).as_bytes_no_nul().to_owned())
233267
}
234268
})
235269
}
@@ -251,10 +285,21 @@ pub fn getenv(n: &str) -> Option<~str> {
251285
}
252286
}
253287

288+
#[cfg(windows)]
289+
/// Fetches the environment variable `n` byte vector from the current process,
290+
/// returning None if the variable isn't set.
291+
pub fn getenv_as_bytes(n: &str) -> Option<~[u8]> {
292+
getenv(n).map(|s| s.into_bytes())
293+
}
294+
254295

255296
#[cfg(unix)]
256297
/// Sets the environment variable `n` to the value `v` for the currently running
257298
/// process
299+
///
300+
/// # Failure
301+
///
302+
/// Fails if `n` or `v` have any interior NULs.
258303
pub fn setenv(n: &str, v: &str) {
259304
unsafe {
260305
with_env_lock(|| {
@@ -285,6 +330,10 @@ pub fn setenv(n: &str, v: &str) {
285330
}
286331

287332
/// Remove a variable from the environment entirely
333+
///
334+
/// # Failure
335+
///
336+
/// Fails (on unix) if `n` has any interior NULs.
288337
pub fn unsetenv(n: &str) {
289338
#[cfg(unix)]
290339
fn _unsetenv(n: &str) {

0 commit comments

Comments
 (0)