Advertisement
Guest User

Untitled

a guest
Jan 19th, 2020
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.37 KB | None | 0 0
  1. #![feature(with_options)]
  2. #![feature(seek_convenience)]
  3.  
  4. use std::io::{stdin, stdout, Write};
  5. use std::env;
  6. use std::process::Command;
  7. use std::path::Path;
  8. use std::os::unix::io::FromRawFd;
  9. use std::sync::Mutex;
  10. use std::io::{BufRead, BufReader, Seek, SeekFrom};
  11.  
  12.  
  13. #[macro_use]
  14. extern crate lazy_static;
  15.  
  16. lazy_static!{
  17. static ref HISTORY_FILE: Mutex<std::fs::File> = Mutex::new(std::fs::File::with_options().read(true)
  18. .write(true)
  19. .append(true)
  20. .create(true)
  21. .open("history.txt")
  22. .unwrap());
  23. }
  24.  
  25. macro_rules! history {
  26. () => {
  27. *HISTORY_FILE.lock().unwrap()
  28. };
  29. }
  30.  
  31. macro_rules! skip_fail {
  32. ($res:expr, Option<_>) => {
  33. match $res {
  34. Some(val) => val,
  35. None => {
  36.  
  37. continue;
  38. }
  39. }
  40. };
  41. ($res:expr, Result<_>) => {
  42. match $res {
  43. Ok(val) => val,
  44. Err(_) => {
  45. continue;
  46. }
  47. }
  48. };
  49. }
  50. #[derive(Debug, Clone)]
  51. enum Token{
  52. Command(String),
  53. CommandOptionSingle(String),
  54. CommandOptionCombined(String),
  55. CommandArguments(String),
  56. RedirectStream(u8, String),
  57. Pipe,
  58. End,
  59. }
  60.  
  61. enum ReturnCode{
  62. Stop,
  63. Continue
  64. }
  65.  
  66. fn main(){
  67. while {//for each line of input
  68. print!("{} >", env::current_dir()//print out new line with current location
  69. .unwrap_or("dir".into())
  70. .to_string_lossy()
  71. );
  72. stdout().flush().expect("Error flushing to output!");
  73.  
  74. //read line of input
  75. let mut input = String::new();
  76. stdin().read_line(&mut input).unwrap();
  77. //turn line into token-stream and parse contents
  78. let result = parse(tokenify(input));
  79. match result {
  80. Ok(code) => match code {
  81. ReturnCode::Continue => true,
  82. ReturnCode::Stop => false,
  83. },
  84. Err(code) => {eprintln!("Error: {}", code); true},
  85. }
  86. }{}
  87. }
  88.  
  89. fn tokenify(input: String) -> Vec<Token>{
  90. //split expressions from each-other
  91. let expression: Vec<&str> = input.split(';')
  92. .map(|s| s.trim())
  93. .filter(|slice| !slice.is_empty())
  94. .collect();
  95. expression.iter().for_each(|s| {let _ = writeln!(history!(), "{}",s);});
  96. history!().flush().ok();//history
  97.  
  98. //sides of pipe
  99. let pipe_sequences: Vec<Vec<&str>> = expression.into_iter()
  100. .map(|iter| {iter.split("|").collect()})
  101. .collect();
  102.  
  103. pipe_sequences.iter()//iter on vec of vec of str
  104. .map(|slice|{
  105. let mut ret:Vec<Token> = slice.iter()//iter on vec of str
  106. .enumerate()
  107. .map(|(index, iter)|
  108. string_to_token(iter, index == slice.len()-1)
  109. )
  110. .flatten().collect();
  111. ret.push(Token::End);
  112. return ret;
  113. }
  114. )
  115. .flatten()
  116. .collect()
  117. }
  118.  
  119. fn string_to_token(string: &str, last: bool) -> Vec<Token>{
  120. let mut words = string.split_whitespace().filter(|iter| !iter.is_empty());
  121. let mut tokens = vec![];
  122. if let Some(word) = words.next(){
  123. tokens.push(Token::Command(word.to_owned()));
  124. //command [args, [args..]] [options, [options..]]
  125. //first in sequence is command
  126. while let Some(word) = words.next(){
  127. let mut iter = word.chars().peekable();
  128.  
  129. let token = {
  130. if iter.peek().unwrap() == &'-' {//flags
  131. iter.next();
  132. if let Some(next_char) = iter.peek(){ //--
  133. if next_char== &'-' {
  134. iter.next();
  135. if iter.peek().is_none() {//empty --
  136. continue
  137. }
  138. else{
  139. Token::CommandOptionSingle(iter.collect())
  140. }
  141. }
  142. else {
  143. Token::CommandOptionCombined(iter.collect())//-
  144. }
  145. }
  146. else {
  147. continue;//empty -
  148. }
  149. }
  150. else {
  151. let taken_first: String = match iter.next(){
  152. Some(c) => c.to_owned().to_string(),
  153. None => String::new(),
  154. };
  155.  
  156. let taken_second: String = match iter.next(){
  157. Some(c) => c.to_owned().to_string(),
  158. None => String::new(),
  159. };
  160.  
  161. if taken_first == "<"{
  162. if iter.peek().is_none(){
  163. iter = match words.next(){
  164. Some(item) => item.chars().peekable(),
  165. None => continue //end of stream
  166. };
  167.  
  168. }
  169. Token::RedirectStream(0, taken_second.chars()
  170. .chain(iter)
  171. .collect())
  172. }
  173. else if taken_first == ">" {
  174. if iter.peek().is_none(){
  175. iter = match words.next(){
  176. Some(item) => item.chars().peekable(),
  177. None => continue //end of stream
  178. };
  179. }
  180.  
  181. Token::RedirectStream(1, taken_second.chars()
  182. .chain(iter)
  183. .collect())
  184. }
  185. else if taken_second == ">" {
  186. if iter.peek().is_none(){
  187. iter = match words.next(){
  188. Some(item) => item.chars().peekable(),
  189. None => continue //end of stream
  190. };
  191.  
  192. }
  193. if let Some(d) = taken_first.chars().next().unwrap().to_digit(10){
  194. Token::RedirectStream(d as u8, iter.collect())
  195. }
  196. else {
  197. continue
  198. }
  199. }
  200. else{
  201. Token::CommandArguments(taken_first.chars()
  202. .chain(taken_second.chars())
  203. .chain(iter)
  204. .collect())//args
  205. }
  206. }
  207. };
  208. tokens.push(token);
  209.  
  210. }
  211. }
  212. if !last{
  213. tokens.push(Token::Pipe);
  214. }
  215.  
  216. tokens
  217. }
  218.  
  219. fn parse(input: Vec<Token>)-> Result<ReturnCode, Box<dyn std::error::Error>> {
  220. let mut input = input.iter().enumerate().peekable();
  221. let mut previous_command_output: Option<std::process::Child> = None;
  222. let mut custom_command_output = Vec::<u8>::new();
  223. let mut command_builder: Option<Command> = None;
  224.  
  225. while let Some((_index, item)) = input.next() {
  226. match item {
  227. Token::Command(command) => match command.as_str(){
  228. "cd" => {
  229. let dir = match input.peek(){
  230. Some((_, Token::CommandArguments(string))) => {
  231. input.next();//skip next as we captured it in string
  232. &string[..]
  233. },
  234. _ =>"/",
  235. };
  236. if let Err(e) = env::set_current_dir(&Path::new(&dir)){
  237. return Err(Box::from(e))
  238. }
  239. else {
  240. continue
  241. }
  242. },
  243. "exit" | "q" => return Ok(ReturnCode::Stop),
  244. "help" => print_help(),
  245. "history" => {
  246. let mut n: usize = 1;
  247. if let Some(token) = input.peek().as_mut(){
  248. match token{
  249. (_, Token::CommandArguments(nr)) => n = skip_fail!(nr.chars().next(), Option<_>).to_digit(10)
  250. .unwrap_or(1) as usize,
  251. _ => (),
  252. }
  253. }
  254. print_history(n, &mut custom_command_output);
  255. }
  256. command => command_builder = Some(Command::new(command)),
  257. },
  258. Token::CommandArguments(arg) => if let Some(command) = command_builder.as_mut(){ command.arg(arg); },
  259. Token::CommandOptionCombined(arg) => if let Some(command) = command_builder.as_mut(){ command.arg("-".to_owned() + arg);},
  260. Token::CommandOptionSingle(arg) => if let Some(command) = command_builder.as_mut(){ command.arg("--".to_owned() + arg);},
  261. Token::Pipe => {
  262. if let Some(mut command) = command_builder.as_mut() {
  263. previous_command_output = Some((get_stdio(&mut command, &mut previous_command_output,
  264. & mut custom_command_output, false))
  265. .stdout(std::process::Stdio::piped())
  266. .spawn()?);
  267. if let Some(command) = previous_command_output.as_mut(){
  268. command.wait()?;
  269. }
  270. }
  271. },
  272. Token::RedirectStream(handle, file_handle_or_name) => {
  273. let mut file_stream = match file_handle_or_name {
  274. handle if handle.starts_with("&")
  275. => unsafe {std::fs::File::from_raw_fd(skip_fail!(handle.chars()
  276. .next()
  277. .unwrap()
  278. .to_digit(10),
  279. Option<_>
  280. )as i32
  281. )},
  282. file_name => skip_fail!(std::fs::File::with_options().read(true)
  283. .write(true)
  284. .create(true)
  285. .truncate(false)
  286. .open(file_name),
  287. Result<_>
  288. ),
  289. };
  290. file_stream.flush()?;
  291. match handle {
  292. 0 => if let Some(command) = command_builder.as_mut() {
  293. command.stdin(file_stream);
  294. },
  295. 1 => if let Some(command) = command_builder.as_mut() {
  296. command.stdout(file_stream);
  297. },
  298. 2 => if let Some(command) = command_builder.as_mut() {
  299. command.stderr(file_stream);
  300. },
  301. _ => continue,
  302.  
  303. }
  304. } ,
  305. Token::End => {if let Some(mut command) = command_builder.as_mut() {
  306. get_stdio(&mut command, &mut previous_command_output, &mut custom_command_output, true)
  307. .spawn()?.wait()?;
  308. };
  309. },
  310. }
  311. }
  312. Ok(ReturnCode::Continue)
  313. }
  314.  
  315. fn print_help(){
  316. unimplemented!();
  317. }
  318. fn print_history(nr_lines: usize, mut custom_command_output: &mut Vec<u8>){
  319.  
  320. let pos = history!().stream_position().unwrap();
  321. let _ =history!().seek(SeekFrom::Start(0));
  322.  
  323.  
  324. for line in BufReader::new(&history!()).lines().take(nr_lines as usize){
  325. eprintln!("buf {:?}",writeln!(&mut custom_command_output, "{}", line.unwrap_or("".to_owned())));
  326. }
  327. eprintln!("{:?}", custom_command_output);
  328. let _ = history!().seek(SeekFrom::Start(pos));
  329. }
  330.  
  331. fn get_stdio<'a>(command_builder: &'a mut std::process::Command, previous_command_output: &mut Option<std::process::Child>,
  332. custom_command_output: &mut Vec<u8>, force_flush: bool)
  333. -> &'a mut std::process::Command {
  334. eprintln!("stdio");
  335. if force_flush{
  336. std::io::stdout().lock().write_all(custom_command_output.as_slice());
  337. } if !custom_command_output.is_empty() && previous_command_output.is_some() {
  338. eprintln!("here");
  339. eprintln!("custom command output: {:?}", custom_command_output);
  340.  
  341. let temp_file = std::fs::File::create("temp.txt");
  342. if let Ok(mut temp_file) = temp_file {
  343. eprintln!("result {:?}", temp_file.write_all(custom_command_output.as_slice()));
  344. command_builder.stdin(std::process::Stdio::from(temp_file));
  345. custom_command_output.clear();
  346. eprintln!("end");
  347. }
  348. }
  349.  
  350. else if let Some(command) = previous_command_output.take() {
  351. eprintln!("1");
  352. command_builder.stdin(std::process::Stdio::from(command.stdout.unwrap()));
  353. eprintln!("2");
  354.  
  355. }
  356.  
  357. command_builder
  358. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement