use std::env;
use std::process;
mod machine;
use machine::OutputSelector;
mod errfmt;
mod filestream;
mod situation;
mod syntaxerror;
fn help() {
println!(
"Shellharden: The corrective bash syntax highlighter.\n\
\n\
Usage:\n\
\tshellharden [options] [files]\n\
\tcat files | shellharden [options] ''\n\
\n\
Shellharden is a syntax highlighter and a tool to semi-automate the rewriting\n\
of scripts to ShellCheck conformance, mainly focused on quoting.\n\
\n\
The default mode of operation is like `cat`, but with syntax highlighting in\n\
foreground colors and suggestive changes in background colors.\n\
\n\
Options:\n\
\t--suggest Output a colored diff suggesting changes.\n\
\t--syntax Output syntax highlighting with ANSI colors.\n\
\t--syntax-suggest Diff with syntax highlighting (default mode).\n\
\t--transform Output suggested changes.\n\
\t--check No output; exit with 2 if changes are suggested.\n\
\t--replace Replace file contents with suggested changes.\n\
\t-- Don't treat further arguments as options.\n\
\t-h|--help Show help text.\n\
\t--version Show version.\n\
\n\
The changes suggested by Shellharden inhibits word splitting and indirect\n\
pathname expansion. This will make your script ShellCheck compliant in terms of\n\
quoting. Whether your script will work afterwards is a different question:\n\
If your script was using those features on purpose, it obviously won't anymore!\n\
\n\
Every script is possible to write without using word splitting or indirect\n\
pathname expansion, but it may involve doing things differently.\n\
See the accompanying file how_to_do_things_safely_in_bash.md or online:\n\
https://github.com/anordal/shellharden/blob/master/how_to_do_things_safely_in_bash.md\n\
"
);
}
fn main() {
let mut args: std::env::ArgsOs = env::args_os();
args.next();
let mut sett = machine::Settings {
osel: OutputSelector::DIFF,
syntax: true,
replace: false,
};
let mut exit_code: i32 = 0;
let mut opt_trigger: &str = "-";
while let Some(arg) = args.next() {
if let Some(comparable) = arg.to_str() {
if comparable.starts_with(opt_trigger) {
match comparable {
"--suggest" => {
sett.osel=OutputSelector::DIFF;
sett.syntax=false;
sett.replace=false;
continue;
},
"--syntax" => {
sett.osel=OutputSelector::ORIGINAL;
sett.syntax=true;
sett.replace=false;
continue;
},
"--syntax-suggest" => {
sett.osel=OutputSelector::DIFF;
sett.syntax=true;
sett.replace=false;
continue;
},
"--transform" => {
sett.osel=OutputSelector::TRANSFORM;
sett.syntax=false;
sett.replace=false;
continue;
},
"--check" => {
sett.osel=OutputSelector::CHECK;
sett.syntax=false;
sett.replace=false;
continue;
},
"--replace" => {
sett.osel=OutputSelector::TRANSFORM;
sett.syntax=false;
sett.replace=true;
continue;
},
"--help" | "-h" => {
help();
continue;
},
"--version" => {
println!(env!("CARGO_PKG_VERSION"));
continue;
},
"--" => {
opt_trigger = "\x00";
continue;
},
_ => {
errfmt::blame_path(&arg, "No such option.");
exit_code = 3;
break;
},
}
}
}
if let Err(e) = machine::treatfile(&arg, &sett) {
println!("\x1b[m");
exit_code = 1;
match &e {
&machine::Error::Stdio(ref fail) => {
errfmt::blame_path_io(&arg, &fail);
},
&machine::Error::Syntax(ref fail) => {
errfmt::blame_syntax(&arg, &fail);
},
&machine::Error::Check => {
exit_code = 2;
break;
},
};
}
}
process::exit(exit_code);
}
mod commonargcmd;
mod commonstrcmd;
mod microparsers;
mod sitcase;
mod sitcomment;
mod sitcmd;
mod sitrvalue;
mod sitvec;
mod sitvarident;
mod sitstrsqesc;
mod situntilbyte;
mod sitextent;
mod sitstrdq;
mod sitstrphantom;