1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! Inspection and manipulation of the process's environment.
//!
//! This module contains functions to inspect various aspects such as
//! process arguments, the current directory, and various
//! other important directories.

use alloc::vec::IntoIter;

use cstr_core::CStr;

use crate::io;
use crate::io::ErrorKind;
use crate::libc;
use crate::path::Path;
use crate::path::PathBuf;
use crate::prelude::*;

pub type Args = IntoIter<String>;

/// Returns the arguments which this program was started with.
///
/// The first element is traditionally the path of the executable, but it can be
/// set to arbitrary text, and may not even exist. This means this property should
/// not be relied upon for security purposes.
///
/// On Unix systems shell usually expands unquoted arguments with glob patterns
/// (such as `*` and `?`).
///
/// # Panics
///
/// The returned iterator will panic during iteration if any argument to the
/// process is not valid unicode.
///
/// # Examples
///
/// ```
/// use ndless::env;
///
/// // Prints each argument on a separate line
/// for argument in env::args() {
///     println!("{}", argument);
/// }
/// ```
pub fn args() -> Args {
	unsafe { &crate::ARGUMENTS }
		.map(|args| {
			args.iter()
				.map(|arg| {
					unsafe { CStr::from_ptr(*arg) }
						.to_str()
						.unwrap()
						.to_string()
				})
				.collect::<Vec<_>>()
		})
		.unwrap_or_default()
		.into_iter()
}

/// Returns the current working directory as a [`PathBuf`].
///
/// # Errors
///
/// Returns an [`Err`] if the current working directory value is invalid.
/// Possible cases:
///
/// * Current directory does not exist.
/// * There are insufficient permissions to access the current directory.
///
/// [`PathBuf`]: ../../std/path/struct.PathBuf.html
/// [`Err`]: ../../std/result/enum.Result.html#method.err
///
/// # Examples
///
/// ```
/// use ndless::env;
///
/// fn main() -> std::io::Result<()> {
///     let path = env::current_dir()?;
///     println!("The current directory is {}", path.display());
///     Ok(())
/// }
/// ```
pub fn current_dir() -> io::Result<PathBuf> {
	crate::file_io::sys::os::getcwd()
}

/// Changes the current working directory to the specified path.
///
/// Returns an [`Err`] if the operation fails.
///
/// [`Err`]: ../../std/result/enum.Result.html#method.err
///
/// # Examples
///
/// ```
/// use ndless::env;
/// use ndless::path::Path;
///
/// let root = Path::new("/");
/// assert!(env::set_current_dir(&root).is_ok());
/// println!("Successfully changed working directory to {}!", root.display());
/// ```
pub fn set_current_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
	crate::file_io::sys::os::chdir(path.as_ref())
}

pub fn get_documents_dir() -> io::Result<PathBuf> {
	unsafe {
		let ptr = libc::get_documents_dir();
		if ptr.is_null() {
			Err(ErrorKind::NotFound.into())
		} else {
			Ok(CStr::from_ptr(ptr).to_string_lossy().as_ref().into())
		}
	}
}