nstd_env/
lib.rs

1use nstd_collections::vec::*;
2use std::{
3    env,
4    ffi::{CStr, CString},
5    os::raw::{c_char, c_int, c_void},
6    ptr,
7};
8#[cfg(feature = "deps")]
9pub mod deps {
10    pub use nstd_collections;
11}
12
13#[allow(non_camel_case_types)]
14type byte = u8;
15
16/// Generates `nstd_env_path_to_exe` and `nstd_env_current_dir` functions.
17macro_rules! nstd_path_fns {
18    ($fn_name: ident, $env_fn: ident) => {
19        #[cfg_attr(feature = "clib", no_mangle)]
20        pub unsafe extern "C" fn $fn_name(errc: *mut c_int) -> *mut c_char {
21            match env::$env_fn() {
22                Ok(path) => {
23                    *errc = 0;
24                    let mut path = path.to_string_lossy().to_string();
25                    path.push('\0');
26                    CString::from_vec_unchecked(path.into_bytes()).into_raw()
27                }
28                _ => {
29                    *errc = 1;
30                    ptr::null_mut()
31                }
32            }
33        }
34    };
35}
36nstd_path_fns!(nstd_env_path_to_exe, current_exe);
37nstd_path_fns!(nstd_env_current_dir, current_dir);
38
39/// Returns the path of a temporary directory.
40/// Use `nstd_env_free_path` to free memory allocated by this function.
41/// Returns: `char *path` - The path of the temp dir.
42#[inline]
43#[cfg_attr(feature = "clib", no_mangle)]
44pub unsafe extern "C" fn nstd_env_temp_dir() -> *mut c_char {
45    match env::temp_dir().into_os_string().into_string() {
46        Ok(path) => CString::from_vec_unchecked(path.into_bytes()).into_raw(),
47        _ => ptr::null_mut(),
48    }
49}
50
51/// Frees memory allocated by `nstd_env_path_to_exe`,  `nstd_env_current_dir` or
52/// `nstd_env_temp_dir`.
53/// Parameters:
54///     `char **path` - String from `nstd_env_path_to_exe` or `nstd_env_current_dir`.
55#[inline]
56#[cfg_attr(feature = "clib", no_mangle)]
57pub unsafe extern "C" fn nstd_env_free_path(path: *mut *mut c_char) {
58    static_nstd_free_cstring(path);
59}
60
61/// Sets the current working directory.
62/// Parameters:
63///     `const char *const path` - The new working directory.
64/// Returns: `int errc` - Nonzero on error.
65#[cfg_attr(feature = "clib", no_mangle)]
66pub unsafe extern "C" fn nstd_env_set_current_dir(path: *const c_char) -> c_int {
67    match CStr::from_ptr(path).to_str() {
68        Ok(path) => match env::set_current_dir(path) {
69            Ok(_) => 0,
70            _ => 1,
71        },
72        _ => 1,
73    }
74}
75
76/// Returns a vector of strings that contain the cmd args that the program was started with.
77/// Returns: `NSTDVec args` - The command line arguments.
78#[cfg_attr(feature = "clib", no_mangle)]
79pub unsafe extern "C" fn nstd_env_args() -> NSTDVec {
80    const ELEMENT_SIZE: usize = std::mem::size_of::<*mut c_char>();
81    let args_iter = env::args().collect::<Vec<String>>();
82    let mut args = nstd_collections_vec_new_with_capacity(ELEMENT_SIZE, args_iter.len());
83    if !args.data.is_null() {
84        for arg in args_iter {
85            let mut bytes = arg.into_bytes();
86            bytes.push(0);
87            let cstr = CString::from_vec_unchecked(bytes).into_raw();
88            let cstrptr = &cstr as *const *mut c_char as *const c_void;
89            nstd_collections_vec_push(&mut args, cstrptr);
90        }
91    }
92    args
93}
94
95/// Frees memory allocated by `nstd_env_args`.
96/// Parameters:
97///     `NSTDVec *const args` - Returned from `nstd_env_args`.
98/// Returns: `int errc` - Nonzero on error.
99#[inline]
100#[cfg_attr(feature = "clib", no_mangle)]
101pub unsafe extern "C" fn nstd_env_free_args(args: &mut NSTDVec) -> c_int {
102    for i in 0..args.size {
103        let cstrptr = nstd_collections_vec_get(args, i) as *const *mut c_char;
104        if !cstrptr.is_null() {
105            drop(CString::from_raw(*cstrptr));
106        }
107    }
108    nstd_collections_vec_free(args)
109}
110
111/// Sets an environment variable.
112/// Parameters:
113///     `const char *const k` - The var key.
114///     `const char *const v` - The var value.
115#[cfg_attr(feature = "clib", no_mangle)]
116pub unsafe extern "C" fn nstd_env_set_var(k: *const c_char, v: *const c_char) {
117    if let Ok(k) = CStr::from_ptr(k).to_str() {
118        if let Ok(v) = CStr::from_ptr(v).to_str() {
119            env::set_var(k, v);
120        }
121    }
122}
123
124/// Gets an environment variable.
125/// Parameters:
126///     `const char *const k` - The var key.
127/// Returns: `char *v` - The value of the variable.
128#[cfg_attr(feature = "clib", no_mangle)]
129pub unsafe extern "C" fn nstd_env_get_var(k: *const c_char) -> *mut c_char {
130    if let Ok(k) = CStr::from_ptr(k).to_str() {
131        if let Ok(v) = env::var(k) {
132            return CString::from_vec_unchecked(v.into_bytes()).into_raw();
133        }
134    }
135    ptr::null_mut()
136}
137
138/// Removes an environment variable.
139/// This will not free memory allocated by `nstd_env_get_var`.
140/// Parameters:
141///     `const char *const k` - The var key.
142#[inline]
143#[cfg_attr(feature = "clib", no_mangle)]
144pub unsafe extern "C" fn nstd_env_remove_var(k: *const c_char) {
145    if let Ok(k) = CStr::from_ptr(k).to_str() {
146        env::remove_var(k);
147    }
148}
149
150/// Frees memory allocated by `nstd_env_get_var`.
151/// Parameters:
152///     `char **v` - The value returned from `nstd_env_get_var`.
153#[inline]
154#[cfg_attr(feature = "clib", no_mangle)]
155pub unsafe extern "C" fn nstd_env_free_var(k: *mut *mut c_char) {
156    static_nstd_free_cstring(k);
157}
158
159/// Returns an array of strings that contain the environment variables.
160/// Parameters:
161///     `NSTDUSize *size` - Number of variables.
162/// Returns: `char *vars` - The environment variables keys.
163#[cfg_attr(feature = "clib", no_mangle)]
164pub unsafe extern "C" fn nstd_env_vars(size: *mut usize) -> *mut c_char {
165    let vars = env::vars().collect::<Vec<(String, String)>>();
166    let mut bytes = Vec::<byte>::new();
167    *size = vars.len();
168    for var in vars {
169        bytes.extend(var.0.into_bytes());
170        bytes.push(0);
171    }
172    Box::<[byte]>::into_raw(bytes.into_boxed_slice()) as *mut c_char
173}
174
175/// Frees memory allocated by `nstd_env_vars`.
176/// Parameters:
177///     `char **vars` - Returned from `nstd_env_vars`.
178#[inline]
179#[cfg_attr(feature = "clib", no_mangle)]
180pub unsafe extern "C" fn nstd_env_free_vars(vars: *mut *mut c_char) {
181    static_nstd_free_cstring(vars);
182}
183
184/// Frees a cstring.
185/// Parameters:
186///     `cstr: *mut *mut c_char` - The cstring.
187#[inline]
188unsafe fn static_nstd_free_cstring(cstr: *mut *mut c_char) {
189    Box::from_raw(*cstr as *mut byte);
190    *cstr = ptr::null_mut();
191}