use crate::auth::{AuthState, AuthType};
use crate::error::RadError;
use crate::logger::WarningType;
use crate::models::RadResult;
use crate::Processor;
use lazy_static::lazy_static;
use regex::Regex;
use std::io::BufRead;
lazy_static! {
pub static ref TRIM: Regex = Regex::new(r"^[ \t\r\n]+|[ \t\r\n]+$").unwrap();
}
#[cfg(feature = "color")]
use colored::*;
pub(crate) struct Utils;
impl Utils {
pub(crate) fn local_name(level: usize, name: &str) -> String {
format!("{}.{}", level, name)
}
pub(crate) fn trim(args: &str) -> String {
let result = TRIM.replace_all(args, "");
result.to_string()
}
pub fn full_lines(mut input: impl BufRead) -> impl Iterator<Item = std::io::Result<String>> {
std::iter::from_fn(move || {
let mut vec = String::new();
match input.read_line(&mut vec) {
Ok(0) => None,
Ok(_) => Some(Ok(vec)),
Err(e) => Some(Err(e)),
}
})
}
pub(crate) fn is_blank_char(ch: char) -> bool {
ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
}
pub(crate) fn is_arg_true(arg: &str) -> RadResult<bool> {
let arg = Utils::trim(arg);
if let Ok(value) = arg.parse::<usize>() {
if value == 0 {
return Ok(false);
} else {
return Ok(true);
}
} else if arg.to_lowercase() == "true" {
return Ok(true);
} else if arg.to_lowercase() == "false" {
return Ok(false);
}
Err(RadError::InvalidArgument(
"Neither true nor false".to_owned(),
))
}
pub(crate) fn utf8_substring(source: &str, min: Option<usize>, max: Option<usize>) -> String {
let mut result = String::new();
if let Some(min) = min {
if let Some(max) = max {
for (idx, ch) in source.chars().enumerate() {
if idx >= min && idx <= max {
result.push(ch);
}
}
} else {
for (idx, ch) in source.chars().enumerate() {
if idx >= min {
result.push(ch);
}
}
}
} else {
if let Some(max) = max {
for (idx, ch) in source.chars().enumerate() {
if idx <= max {
result.push(ch);
}
}
} else {
return source.to_owned();
}
}
result
}
pub fn green(string: &str) -> Box<dyn std::fmt::Display> {
if cfg!(feature = "color") {
#[cfg(feature = "color")]
return Box::new(string.green());
}
Box::new(string.to_owned())
}
pub fn red(string: &str) -> Box<dyn std::fmt::Display> {
if cfg!(feature = "color") {
#[cfg(feature = "color")]
return Box::new(string.red());
}
Box::new(string.to_owned())
}
pub fn yellow(string: &str) -> Box<dyn std::fmt::Display> {
if cfg!(feature = "color") {
#[cfg(feature = "color")]
return Box::new(string.yellow());
}
Box::new(string.to_owned())
}
#[allow(dead_code)]
pub(crate) fn count_sentences(s: &str) -> usize {
s.as_bytes().iter().filter(|&&c| c == b'\n').count() + 1
}
#[cfg(feature = "debug")]
pub fn clear_terminal() -> RadResult<()> {
use crossterm::{terminal::ClearType, ExecutableCommand};
std::io::stdout()
.execute(crossterm::terminal::Clear(ClearType::All))?
.execute(crossterm::cursor::MoveTo(0, 0))?;
Ok(())
}
pub fn is_real_path(path: &std::path::Path) -> RadResult<()> {
if !path.exists() {
return Err(RadError::InvalidFile(path.display().to_string()));
}
Ok(())
}
pub fn pop_newline(s: &mut String) {
if s.ends_with('\n') {
s.pop();
if s.ends_with('\r') {
s.pop();
}
}
}
pub(crate) fn is_granted(
name: &str,
auth_type: AuthType,
processor: &mut Processor,
) -> RadResult<bool> {
match processor.get_auth_state(&auth_type) {
AuthState::Restricted => Err(RadError::PermissionDenied(name.to_owned(), auth_type)),
AuthState::Warn => {
processor.log_warning(
&format!(
"\"{}\" was called with \"{:?}\" permission",
name, auth_type
),
WarningType::Security,
)?;
Ok(true)
}
AuthState::Open => Ok(true),
}
}
#[cfg(feature = "clap")]
pub(crate) fn subprocess(args: &[&str]) -> RadResult<()> {
use std::io::Write;
use std::process::Stdio;
#[cfg(target_os = "windows")]
let process = std::process::Command::new("cmd")
.arg("/C")
.args(&args[0..])
.stdin(Stdio::piped())
.spawn()
.map_err(|_| {
RadError::InvalidArgument(format!("Failed to execute command : \"{:?}\"", &args[0]))
})?;
#[cfg(not(target_os = "windows"))]
let process = std::process::Command::new("sh")
.arg("-c")
.arg(&args[0..].join(" ")) .stdin(Stdio::piped())
.spawn()
.map_err(|_| {
RadError::InvalidArgument(format!("Failed to execute command : \"{:?}\"", &args[0]))
})?;
let output = process.wait_with_output()?;
let out_content = String::from_utf8_lossy(&output.stdout);
let err_content = String::from_utf8_lossy(&output.stderr);
if out_content.len() != 0 {
write!(std::io::stdout(), "{}", &out_content)?;
}
if err_content.len() != 0 {
write!(std::io::stderr(), "{}", &err_content)?;
}
Ok(())
}
}