#![allow(non_snake_case)]
#![allow(dead_code)]
use core::ffi::c_int;
use crate::ported::functionbar::Ncurses;
use crate::ported::incset::IncSet_new;
use crate::ported::infoscreen::{
InfoScreen, InfoScreenClass, InfoScreen_addLine, InfoScreen_done, InfoScreen_drawTitled,
InfoScreen_init,
};
use crate::ported::linux::platform::Platform_getProcessEnv;
use crate::ported::listitem::ListItem_new;
use crate::ported::object::{Object, ObjectClass};
use crate::ported::panel::{Panel_getSelectedIndex, Panel_new, Panel_prune, Panel_setSelected};
use crate::ported::process::{Process, Process_getCommand, Process_getPid};
use crate::ported::vector::{Vector_insertionSort, Vector_new};
const VECTOR_DEFAULT_SIZE: c_int = 10;
pub struct EnvScreen {
pub super_: InfoScreen,
}
impl InfoScreenClass for EnvScreen {
fn super_InfoScreen(&mut self) -> &mut InfoScreen {
&mut self.super_
}
fn draw(&mut self) {
EnvScreen_draw(&mut self.super_);
}
fn scan(&mut self) {
EnvScreen_scan(&mut self.super_);
}
fn has_scan(&self) -> bool {
true
}
}
pub fn EnvScreen_new(process: &Process) -> EnvScreen {
let list_item_class: &'static ObjectClass = ListItem_new("", 0).klass();
let mut this = EnvScreen {
super_: InfoScreen {
process: core::ptr::null(),
display: Panel_new(0, 0, 0, 0, None),
inc: IncSet_new(None),
lines: Vector_new(list_item_class, true, VECTOR_DEFAULT_SIZE),
},
};
InfoScreen_init(
&mut this.super_,
process as *const Process,
None,
Ncurses::lines() - 2,
" ",
);
this
}
pub fn EnvScreen_delete(this: EnvScreen) {
let EnvScreen { super_ } = this;
InfoScreen_done(super_);
}
pub fn EnvScreen_draw(this: &mut InfoScreen) {
let pid = Process_getPid(unsafe { &*this.process });
let cmd = match Process_getCommand(unsafe { &*this.process }) {
Some(b) => String::from_utf8_lossy(b).into_owned(),
None => String::new(),
};
let title = format!("Environment of process {} - {}", pid, cmd);
InfoScreen_drawTitled(this, &title);
}
pub fn EnvScreen_scan(this: &mut InfoScreen) {
let idx = Panel_getSelectedIndex(&this.display).max(0);
Panel_prune(&mut this.display);
let pid = unsafe { Process_getPid(&*this.process) };
match Platform_getProcessEnv(pid as libc::pid_t) {
Some(env) => {
for entry in env.split('\0') {
if entry.is_empty() {
break;
}
InfoScreen_addLine(this, entry);
}
}
None => {
InfoScreen_addLine(this, "Could not read process environment.");
}
}
Vector_insertionSort(&mut this.lines);
this.display
.items
.sort_by(|a, b| a.object().compare(b.object()).cmp(&0));
Panel_setSelected(&mut this.display, idx);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ported::incset::IncSet_filter;
use crate::ported::listitem::ListItem;
use crate::ported::panel::{Panel_get, Panel_headerHeight, Panel_size};
use crate::ported::process::Process_setPid;
use crate::ported::vector::Vector_size;
const INFO_FUNCTIONS: [&str; 4] = ["Search ", "Filter ", "Refresh", "Done "];
fn panel_value(p: &crate::ported::panel::Panel, i: i32) -> String {
let any: &dyn std::any::Any = Panel_get(p, i);
any.downcast_ref::<ListItem>().unwrap().value.clone()
}
#[test]
fn new_initializes_infoscreen_base() {
let p = Process::default();
let es = EnvScreen_new(&p);
assert_eq!(es.super_.process, &p as *const Process);
assert_eq!(Vector_size(&es.super_.lines), 0);
assert_eq!(Panel_size(&es.super_.display), 0);
assert!(IncSet_filter(&es.super_.inc).is_none());
}
#[test]
fn new_geometry_matches_c_panel_new_args() {
let p = Process::default();
let es = EnvScreen_new(&p);
assert_eq!(es.super_.display.x, 0);
assert_eq!(es.super_.display.y, 1);
assert_eq!(es.super_.display.w, Ncurses::cols());
assert_eq!(es.super_.display.h, Ncurses::lines() - 2);
assert_eq!(Panel_headerHeight(&es.super_.display), 1);
}
#[test]
fn new_builds_default_infoscreen_bar() {
let p = Process::default();
let es = EnvScreen_new(&p);
let bar = es
.super_
.display
.defaultBar
.as_ref()
.expect("default bar built");
assert_eq!(bar.functions, INFO_FUNCTIONS.to_vec());
let inc_bar = es.super_.inc.defaultBar.as_ref().expect("inc default bar");
assert_eq!(inc_bar.functions, INFO_FUNCTIONS.to_vec());
}
#[test]
fn scan_missing_pid_adds_error_line() {
let mut p = Process::default();
Process_setPid(&mut p, 2147483646);
let mut es = EnvScreen_new(&p);
EnvScreen_scan(&mut es.super_);
assert_eq!(Vector_size(&es.super_.lines), 1);
assert_eq!(Panel_size(&es.super_.display), 1);
assert_eq!(
panel_value(&es.super_.display, 0),
"Could not read process environment."
);
}
#[cfg(target_os = "linux")]
#[test]
fn scan_self_populates_sorted_env_lines() {
let mut p = Process::default();
Process_setPid(&mut p, std::process::id() as i32);
let mut es = EnvScreen_new(&p);
EnvScreen_scan(&mut es.super_);
let n = Vector_size(&es.super_.lines);
assert!(n > 0);
let mut prev = panel_value(&es.super_.display, 0);
for i in 1..Panel_size(&es.super_.display) {
let cur = panel_value(&es.super_.display, i);
assert!(prev <= cur, "panel items must be sorted");
prev = cur;
}
}
}