// This file is part of the uutils diffutils package. // // For the full copyright and license information, please view the LICENSE-* // files that was distributed with this source code. use std::{ env::ArgsOs, ffi::{OsStr, OsString}, iter::Peekable, path::{Path, PathBuf}, process::ExitCode, }; mod cmp; mod context_diff; mod diff; mod ed_diff; mod macros; mod normal_diff; mod params; mod side_diff; mod unified_diff; mod utils; /// # Panics /// Panics if the binary path cannot be determined fn binary_path(args: &mut Peekable) -> PathBuf { match args.peek() { Some(ref s) if !s.is_empty() => PathBuf::from(s), _ => std::env::current_exe().unwrap(), } } /// #Panics /// Panics if path has no UTF-8 valid name fn name(binary_path: &Path) -> &OsStr { binary_path.file_stem().unwrap() } const VERSION: &str = env!("CARGO_PKG_VERSION"); fn usage(name: &str) { println!("{name} {VERSION} (multi-call binary)\n"); println!("Usage: {name} [function [arguments...]]\n"); println!("Currently defined functions:\n"); println!(" cmp, diff\n"); } fn second_arg_error(name: &OsStr) -> ! { eprintln!("Expected utility name as second argument, got nothing."); usage(&name.to_string_lossy()); std::process::exit(0); } fn main() -> ExitCode { let mut args = std::env::args_os().peekable(); let exe_path = binary_path(&mut args); let exe_name = name(&exe_path); let util_name = if exe_name.as_encoded_bytes().ends_with(b"diffutils") { // Discard the item we peeked. let _ = args.next(); args.peek() .cloned() .unwrap_or_else(|| second_arg_error(exe_name)) } else { OsString::from(exe_name) }; match util_name.as_encoded_bytes() { name if name.ends_with(b"diff") => diff::main(args), name if name.ends_with(b"cmp") => cmp::main(args), name => { use std::io::{stderr, Write as _}; let _ = writeln!( stderr(), "{}: utility not supported", String::from_utf8_lossy(name) ); ExitCode::from(2) } } }