use input_iterator::{InputIterator, InputIteratorErr};
use tokenizer::Token;
use arguments;
use execute::command;
use numtoa::NumToA;
use std::io::{self, StdoutLock, Read, Write};
pub fn dry_run<IO: Read>(flags: u16, inputs: InputIterator<IO>, arguments: &[Token]) {
let stdout = io::stdout();
let stdout = &mut stdout.lock();
let stderr = io::stderr();
let stderr = &mut stderr.lock();
let mut command_buffer = String::new();
let slot = "{SLOT_ID}";
let pipe = flags & arguments::PIPE_IS_ENABLED != 0;
let mut id_buffer = [0u8; 20];
let mut total_buffer = [0u8; 20];
let start_indice = inputs.total_arguments.numtoa(10, &mut total_buffer);
let job_total = &total_buffer[start_indice..];
let pipe_action: Box<Fn(&mut StdoutLock, &str)> = if flags & arguments::SHELL_QUOTE != 0 {
Box::new(|stdout: &mut StdoutLock, input: &str| {
if let Some(new_arg) = shell_quote(input) {
let _ = stdout.write(new_arg.as_bytes());
} else {
let _ = stdout.write(input.as_bytes());
}
})
} else {
Box::new(|stdout: &mut StdoutLock, input: &str| {
let _ = stdout.write(input.as_bytes());
})
};
for (job_id, input) in inputs.enumerate() {
match input {
Ok(input) => {
let start_indice = job_id.numtoa(10, &mut id_buffer);
let command = command::ParallelCommand {
slot_no: slot,
job_no: &id_buffer[start_indice..],
job_total: job_total,
input: &input,
command_template: arguments,
flags: flags,
};
command.build_arguments(&mut command_buffer);
if !pipe {
command::append_argument(&mut command_buffer, command.command_template, command.input);
}
pipe_action(stdout, &command_buffer);
let _ = stdout.write(b"\n");
command_buffer.clear();
},
Err(why) => {
match why {
InputIteratorErr::FileRead(path, why) => {
let _ = write!(stderr, "parallel: input file read error: {:?}: {}\n", path, why);
},
}
}
}
}
}
fn shell_quote(command: &str) -> Option<String> {
let mut needs_escaping = false;
for character in command.chars() {
match character {
'$' | ' ' | '\\' | '>' | '<' | '^' | '&' | '#' | '!' | '*' |
'\'' | '\"' | '`' | '~' | '{' | '}' | '[' | ']' | '(' | ')' |
';' | '|' | '?' => needs_escaping = true,
_ => ()
}
}
if needs_escaping {
let mut output = String::with_capacity(command.len() * 2);
for character in command.chars() {
match character {
'$' | ' ' | '\\' | '>' | '<' | '^' | '&' | '#' | '!' | '*' |
'\'' | '\"' | '`' | '~' | '{' | '}' | '[' | ']' | '(' | ')' |
';' | '|' | '?' => output.push('\\'),
_ => ()
}
output.push(character);
}
Some(output)
} else {
None
}
}