Merge branch 'optimizations'
This commit is contained in:
		
						commit
						138044e52f
					
				
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @ -95,7 +95,7 @@ build/o/libstrerror.rlib: build src/libstrerror.rs | ||||
| 		src/libstrerror.rs | ||||
| 
 | ||||
| build/o/libsysexits.rlib: build/include/sysexits.h | ||||
| 	bindgen --default-macro-constant-type signed --use-core --formatter=none \
 | ||||
| 	bindgen --fit-macro-constant-types --default-macro-constant-type unsigned --use-core --formatter=none \
 | ||||
| 		build/include/sysexits.h | $(RUSTC) $(RUSTFLAGS) --crate-type lib -o $@ - | ||||
| 
 | ||||
| # bandage solution until bindgen(1) gets stdin support
 | ||||
|  | ||||
| @ -13,7 +13,7 @@ | ||||
| 
 | ||||
| int main(void) { | ||||
| #ifdef __OpenBSD__ | ||||
| 	pledge(NULL, NULL); | ||||
| 	(void)pledge("stdio", ""); | ||||
| #endif | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
							
								
								
									
										71
									
								
								src/fop.rs
									
									
									
									
									
								
							
							
						
						
									
										71
									
								
								src/fop.rs
									
									
									
									
									
								
							| @ -18,8 +18,8 @@ | ||||
| 
 | ||||
| use std::{ | ||||
| 	env::args, | ||||
| 	io::{ Read, stdin, stdout, Write }, | ||||
| 	process::{ Command, exit, Stdio }, | ||||
| 	io::{ Error, Read, Write, stdin, stdout }, | ||||
| 	process::{ Command, ExitCode, Stdio, exit }, | ||||
| }; | ||||
| 
 | ||||
| extern crate getopt; | ||||
| @ -32,25 +32,36 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; | ||||
| 
 | ||||
| #[cfg(target_os="openbsd")] use sysexits::EX_OSERR; | ||||
| #[cfg(target_os="openbsd")] extern crate openbsd; | ||||
| #[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge }; | ||||
| #[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge, unveil }; | ||||
| 
 | ||||
| fn main() { | ||||
| fn err(argv0: &String, e: Error) { | ||||
| 	eprintln!("{}: {}", argv0, e.strerror()); | ||||
| } | ||||
| 
 | ||||
| fn usage(argv0: &String) -> u8 { | ||||
| 	eprintln!("Usage: {} [-d delimiter] index command [args...]", argv0); | ||||
| 	EX_USAGE | ||||
| } | ||||
| 
 | ||||
| fn main() -> ExitCode { | ||||
| 	let argv = args().collect::<Vec<String>>(); | ||||
| 	let mut d = '\u{1E}'.to_string(); /* ASCII record separator */ | ||||
| 	let mut optind = 1; | ||||
| 
 | ||||
| 	#[cfg(target_os="openbsd")] { | ||||
| 		let promises = Promises::new("stdio proc exec"); | ||||
| 		let promises = Promises::new("exec proc stdio unveil"); | ||||
| 		if let Err(e) = pledge(Some(promises), None) { | ||||
| 			eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 			exit(EX_OSERR); | ||||
| 			err(&argv[0], e); | ||||
| 			return ExitCode::from(EX_OSERR); | ||||
| 		} | ||||
| 
 | ||||
| 		if let Err(e) = unveil(None, None) { | ||||
| 			err(&argv[0], e); | ||||
| 			return ExitCode::from(EX_OSERR); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	let usage = format!( | ||||
| 		"Usage: {} [-d delimiter] index command [args...]", | ||||
| 		argv[0], | ||||
| 	); | ||||
| 	if argv.len() == 1 { return ExitCode::from(usage(&argv[0])); } | ||||
| 
 | ||||
| 	while let Some(opt) = argv.getopt("d:") { | ||||
| 		match opt.opt() { | ||||
| @ -60,8 +71,7 @@ fn main() { | ||||
| 				optind = opt.ind(); | ||||
| 			}, | ||||
| 			_ => { | ||||
| 				eprintln!("{}", usage); | ||||
| 				exit(EX_USAGE); | ||||
| 				return ExitCode::from(usage(&argv[0])); | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
| @ -69,7 +79,7 @@ fn main() { | ||||
| 	/* parse the specified index as a number we can use */ | ||||
| 	let index = argv[optind].parse::<usize>().unwrap_or_else(|e| { | ||||
| 		eprintln!("{}: {}: {}", argv[0], argv[1], e); | ||||
| 		exit(EX_DATAERR); | ||||
| 		exit(EX_DATAERR.into()); | ||||
| 	}); | ||||
| 
 | ||||
| 	/* index of the argv[0] for the operator command */ | ||||
| @ -77,15 +87,14 @@ fn main() { | ||||
| 
 | ||||
| 	/* argv[0] of the operator command */ | ||||
| 	let operator = argv.get(command_arg).unwrap_or_else(|| { | ||||
| 		eprintln!("{}", usage); | ||||
| 		exit(EX_USAGE); | ||||
| 		exit(usage(&argv[0]).into()); | ||||
| 	}); | ||||
| 
 | ||||
| 	/* read entire standard input into memory */ | ||||
| 	let mut buf = String::new(); | ||||
| 	if let Err(e) = stdin().read_to_string(&mut buf) { | ||||
| 		eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 		exit(EX_IOERR); | ||||
| 		err(&argv[0], e); | ||||
| 		exit(EX_IOERR.into()); | ||||
| 	}; | ||||
| 
 | ||||
| 	/* split the buffer by the delimiter (by default, '\u{1E}') */ | ||||
| @ -105,18 +114,14 @@ fn main() { | ||||
| 		.stdout(Stdio::piped()) /* piped stdout to handle output ourselves */ | ||||
| 		.spawn() | ||||
| 		.unwrap_or_else( |e| { | ||||
| 			eprintln!("{}: {}: {}", argv[0], argv[command_arg], e.strerror()); | ||||
| 			exit(EX_UNAVAILABLE); | ||||
| 			err(&argv[0], e); | ||||
| 			exit(EX_UNAVAILABLE.into()); | ||||
| 		}); | ||||
| 
 | ||||
| 	/* get field we want to pipe into spawned program */ | ||||
| 	let field = fields.get(index).unwrap_or_else(|| { | ||||
| 		eprintln!( | ||||
| 			"{}: {}: No such index in input", | ||||
| 			argv[0], | ||||
| 			index.to_string(), | ||||
| 		); | ||||
| 		exit(EX_DATAERR); | ||||
| 		eprintln!("{}: {}: no such index in input", argv[0], index); | ||||
| 		exit(EX_DATAERR.into()); | ||||
| 	}); | ||||
| 
 | ||||
| 	/* get the stdin of the newly spawned program and feed it the field val */ | ||||
| @ -126,8 +131,8 @@ fn main() { | ||||
| 	} | ||||
| 
 | ||||
| 	let output = spawned.wait_with_output().unwrap_or_else(|e| { | ||||
| 		eprintln!("{}: {}: {}", argv[0], argv[command_arg], e.strerror()); | ||||
| 		exit(EX_IOERR); | ||||
| 		err(&argv[0], e); | ||||
| 		exit(EX_IOERR.into()); | ||||
| 	}); | ||||
| 
 | ||||
| 	/* get the output with which the original field will be replaced */ | ||||
| @ -143,8 +148,8 @@ fn main() { | ||||
| 
 | ||||
| 	/* convert the output of the program to UTF-8 */ | ||||
| 	let new_field = String::from_utf8(replace).unwrap_or_else(|e| { | ||||
| 		eprintln!("{}: {}: {}", argv[0], argv[command_arg], e); | ||||
| 		exit(EX_IOERR); | ||||
| 		eprintln!("{}: {}", argv[0], e); | ||||
| 		exit(EX_IOERR.into()); | ||||
| 	}); | ||||
| 
 | ||||
| 	/* store the new field in the old fields vector */ | ||||
| @ -154,7 +159,9 @@ fn main() { | ||||
| 	stdout().write_all( | ||||
| 		fields.join(&d.to_string()).as_bytes() | ||||
| 	).unwrap_or_else(|e| { | ||||
| 		eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 		exit(EX_IOERR); | ||||
| 		err(&argv[0], e); | ||||
| 		exit(EX_IOERR.into()); | ||||
| 	}); | ||||
| 
 | ||||
| 	ExitCode::SUCCESS | ||||
| } | ||||
|  | ||||
							
								
								
									
										63
									
								
								src/hru.rs
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								src/hru.rs
									
									
									
									
									
								
							| @ -19,7 +19,7 @@ | ||||
| use std::{ | ||||
| 	cmp::Ordering, | ||||
| 	env::args, | ||||
| 	io::{ stdin, stdout, Write }, | ||||
| 	io::{ Write, stdin, stdout }, | ||||
| 	process::{ ExitCode, exit }, | ||||
| }; | ||||
| 
 | ||||
| @ -31,7 +31,7 @@ use sysexits::{ EX_DATAERR, EX_IOERR, EX_SOFTWARE, EX_USAGE }; | ||||
| 
 | ||||
| #[cfg(target_os="openbsd")] use sysexits::EX_OSERR; | ||||
| #[cfg(target_os="openbsd")] extern crate openbsd; | ||||
| #[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge }; | ||||
| #[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge, unveil }; | ||||
| 
 | ||||
| /* list of SI prefixes */ | ||||
| const LIST: [(u32, &str); 10] = [ | ||||
| @ -47,6 +47,16 @@ const LIST: [(u32, &str); 10] = [ | ||||
| 	(30, "Q"), /* quetta */ | ||||
| ]; | ||||
| 
 | ||||
| fn err(argv0: &String, message: String, code: Option<u8>) -> ExitCode { | ||||
| 	eprintln!("{}: {}", argv0, message); | ||||
| 	ExitCode::from(code.unwrap_or(1 /* unknown error */)) | ||||
| } | ||||
| 
 | ||||
| fn usage(argv0: &String) -> ExitCode { | ||||
| 	eprintln!("Usage: {}", argv0); | ||||
| 	ExitCode::from(EX_USAGE) | ||||
| } | ||||
| 
 | ||||
| fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> { | ||||
| 	/* preserve decimal places in output by casting to a float */ | ||||
| 	let mut out = (input as f64, (0_u32, "")); 
 | ||||
| @ -81,22 +91,25 @@ fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> { | ||||
| fn main() -> ExitCode { | ||||
| 	let argv = args().collect::<Vec<String>>(); | ||||
| 
 | ||||
| 	if let Some(_) = argv.get(1) { | ||||
| 		eprintln!("Usage: {}", argv[0]); | ||||
| 		return ExitCode::from(EX_USAGE as u8); | ||||
| 	} | ||||
| 	if let Some(_) = argv.get(1) { return usage(&argv[0]); } | ||||
| 
 | ||||
| 	#[cfg(target_os="openbsd")] { | ||||
| 		let promises = Promises::new("stdio"); | ||||
| 		if let Err(e) = pledge(Some(promises), None) { | ||||
| 			eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 			return ExitCode::from(EX_OSERR as u8); | ||||
| 		let promises = Promises::new("stdio unveil"); | ||||
| 		if let Err(e) = pledge(Some(promises), Some(Promises::default())) { | ||||
| 			return err(&argv[0], e.strerror(), Some(EX_OSERR)); | ||||
| 		} | ||||
| 
 | ||||
| 		if let Err(e) = unveil(None, None) { | ||||
| 			return err(&argv[0], e.strerror(), Some(EX_OSERR)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	let mut buf = String::new(); | ||||
| 
 | ||||
| 	while let Ok(_) = stdin().read_line(&mut buf) { | ||||
| 	if let Err(e) = stdin().read_line(&mut buf) { | ||||
| 		return err(&argv[0], e.strerror(), Some(EX_IOERR)); | ||||
| 	} | ||||
| 
 | ||||
| 	if buf.is_empty() { return ExitCode::SUCCESS; } | ||||
| 
 | ||||
| 	let n: u128 = match buf.trim().parse() { | ||||
| @ -104,30 +117,22 @@ fn main() -> ExitCode { | ||||
| 			buf.clear(); | ||||
| 			f | ||||
| 		}, | ||||
| 			Err(err) => { | ||||
| 				eprintln!("{}: {}", argv[0], err); | ||||
| 				return ExitCode::from(EX_DATAERR as u8); | ||||
| 			}, | ||||
| 		Err(e) => return err(&argv[0], e.to_string(), Some(EX_DATAERR)), | ||||
| 	}; | ||||
| 
 | ||||
| 		let (number, prefix) = match convert(n) { | ||||
| 			Ok(x) => x, | ||||
| 			Err(err) => { | ||||
| 				eprintln!("{}: {}", argv[0], err); | ||||
| 				return ExitCode::from(EX_SOFTWARE as u8); | ||||
| 			}, | ||||
| 		}; | ||||
| 	let (number, prefix) = convert(n).unwrap_or_else(|e| { | ||||
| 		let _ = err(&argv[0], e.to_string(), None); | ||||
| 		exit(EX_SOFTWARE.into()); | ||||
| 	}); | ||||
| 
 | ||||
| 		let si_prefix = format!("{}B", prefix.1); | ||||
| 	let si_prefix = prefix.1.to_owned() + "B"; | ||||
| 
 | ||||
| 	/* round output number to one decimal place */ | ||||
| 		let out = ((number * 10.0).round() / 10.0).to_string(); | ||||
| 	let rounded = (number * 10.0).round() / 10.0; | ||||
| 	let out = rounded.to_string() + " " + &si_prefix + &'\n'.to_string(); | ||||
| 
 | ||||
| 		stdout().write_all(format!("{} {}\n", out, si_prefix).as_bytes()) | ||||
| 			.unwrap_or_else(|e| { | ||||
| 				eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 				exit(EX_IOERR); | ||||
| 			}); | ||||
| 	if let Err(e) = stdout().write_all(out.as_bytes()) { | ||||
| 		return err(&argv[0], e.strerror(), Some(EX_IOERR)); | ||||
| 	} | ||||
| 
 | ||||
| 	ExitCode::SUCCESS | ||||
|  | ||||
| @ -26,27 +26,35 @@ extern crate getopt; | ||||
| extern crate sysexits; | ||||
| 
 | ||||
| use getopt::GetOpt; | ||||
| use sysexits::EX_USAGE; | ||||
| use sysexits::{ EX_DATAERR, EX_USAGE }; | ||||
| 
 | ||||
| #[cfg(target_os="openbsd")] use sysexits::EX_OSERR; | ||||
| #[cfg(target_os="openbsd")] extern crate openbsd; | ||||
| #[cfg(target_os="openbsd")] extern crate strerror; | ||||
| #[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge }; | ||||
| #[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge, unveil }; | ||||
| #[cfg(target_os="openbsd")] use strerror::StrError; | ||||
| 
 | ||||
| fn usage(s: &str) -> ExitCode { | ||||
| 	eprintln!("Usage: {} [-egl] integer integer...", s); | ||||
| 	ExitCode::from(EX_USAGE as u8) | ||||
| fn err(argv0: &String, e: String, code: u8) -> ExitCode { | ||||
| 	eprintln!("{}: {}", argv0, e); | ||||
| 	ExitCode::from(code) | ||||
| } | ||||
| 
 | ||||
| fn usage(argv0: &String) -> ExitCode { | ||||
| 	eprintln!("Usage: {} [-egl] integer integer...", argv0); | ||||
| 	ExitCode::from(EX_USAGE) | ||||
| } | ||||
| 
 | ||||
| fn main() -> ExitCode { | ||||
| 	let argv = args().collect::<Vec<String>>(); | ||||
| 
 | ||||
| 	#[cfg(target_os="openbsd")] { | ||||
| 		let promises = Promises::new("stdio"); | ||||
| 		if let Err(e) = pledge(Some(promises), None) { | ||||
| 			eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 			return ExitCode::from(EX_OSERR as u8); | ||||
| 		let promises = Promises::new("stdio unveil"); | ||||
| 		if let Err(e) = pledge(Some(promises), Some(Promises::default())) { | ||||
| 			return err(&argv[0], e.strerror(), EX_OSERR); | ||||
| 		} | ||||
| 
 | ||||
| 		if let Err(e) = unveil(None, None) { | ||||
| 			return err(&argv[0], e.strerror(), EX_OSERR); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -78,8 +86,8 @@ fn main() -> ExitCode { | ||||
| 		match arg.parse::<usize>() { /* parse current operand */ | ||||
| 			Ok(n) => currn = n, | ||||
| 			Err(e) => { | ||||
| 				eprintln!("{}: {}: {}", &argv[0], arg, e); | ||||
| 				return ExitCode::from(EX_USAGE as u8); | ||||
| 				let error = arg.to_owned() + ": " + &e.to_string(); | ||||
| 				return err(&argv[0], error, EX_DATAERR); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
| @ -43,6 +43,10 @@ impl Promises { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl Default for Promises { | ||||
| 	fn default() -> Self { Promises::new("") } | ||||
| } | ||||
| 
 | ||||
| pub fn pledge( | ||||
| 	promises: Option<Promises>, execpromises: Option<Promises> | ||||
| ) -> Result<(), Error> { | ||||
| @ -65,14 +69,12 @@ pub fn pledge( | ||||
| pub struct UnveilPerms(CString); | ||||
| 
 | ||||
| impl UnveilPerms { | ||||
| 	pub fn new(permissions: Vec<char>) -> Self { | ||||
| 		if permissions.is_empty() { | ||||
| 			return UnveilPerms(CString::new("").unwrap()); | ||||
| 		} | ||||
| 	pub fn new<T: IntoIterator<Item = char>>(permissions: T) -> Self { | ||||
| 		let perms = CString::new( | ||||
| 			permissions.into_iter().collect::<String>() | ||||
| 		).unwrap(); | ||||
| 		
 | ||||
| 		UnveilPerms( | ||||
| 			CString::new(permissions.iter().collect::<String>()).unwrap() | ||||
| 		) | ||||
| 		UnveilPerms(perms) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -83,9 +85,9 @@ pub fn unveil( | ||||
| 	let path_c = path.map(CString::new).map(Result::unwrap); | ||||
| 	let arg1 = path_c.map(|p| p.into_raw() as *const c_char).unwrap_or(null()); | ||||
| 
 | ||||
| 	let arg2 = permissions | ||||
| 		.map(|p| p.0.into_raw() as *const c_char) | ||||
| 		.unwrap_or(null()); | ||||
| 	let arg2 = permissions.map(|p| { | ||||
| 		p.0.into_raw() as *const c_char | ||||
| 	}).unwrap_or(null()); | ||||
| 
 | ||||
| 	unsafe { | ||||
| 		match openbsd::unveil(arg1, arg2) { | ||||
|  | ||||
							
								
								
									
										57
									
								
								src/mm.rs
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								src/mm.rs
									
									
									
									
									
								
							| @ -20,9 +20,9 @@ | ||||
| use std::{ | ||||
| 	env::args, | ||||
| 	fs::File, | ||||
| 	io::{ stdin, stdout, stderr, BufWriter, Read, Write }, | ||||
| 	io::{ Error, BufWriter, Read, Write, stderr, stdin, stdout }, | ||||
| 	os::fd::{ AsRawFd, FromRawFd }, | ||||
| 	process::{ exit, ExitCode }, | ||||
| 	process::{ ExitCode, exit}, | ||||
| }; | ||||
| 
 | ||||
| extern crate getopt; | ||||
| @ -47,15 +47,23 @@ use ArgMode::*; | ||||
| 
 | ||||
| enum ArgMode { In, Out } | ||||
| 
 | ||||
| fn err(argv0: &String, e: Error, code: Option<u8>) -> ExitCode { | ||||
| 	eprintln!("{}: {}", argv0, e.strerror()); | ||||
| 	ExitCode::from(code.unwrap_or(1 /* unknown error */)) | ||||
| } | ||||
| 
 | ||||
| fn usage(argv0: &String) -> ExitCode { | ||||
| 	eprintln!("Usage: {} [-aetu] [-i input] [-o output]", argv0); | ||||
| 	ExitCode::from(EX_USAGE) | ||||
| } | ||||
| 
 | ||||
| fn main() -> ExitCode { | ||||
| 	let argv = args().collect::<Vec<_>>(); | ||||
| 	let usage = format!("Usage: {} [-aetu] [-i input] [-o output]", argv[0]); | ||||
| 
 | ||||
| 	#[cfg(target_os="openbsd")] { | ||||
| 		let promises = Promises::new("cpath rpath stdio unveil wpath"); | ||||
| 		if let Err(e) = pledge(Some(promises), None) { | ||||
| 			eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 			return ExitCode::from(EX_OSERR as u8); | ||||
| 		if let Err(e) = pledge(Some(promises), Some(Promises::default())) { | ||||
| 			return err(&argv[0], e, Some(EX_OSERR)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -85,8 +93,7 @@ fn main() -> ExitCode { | ||||
| 				mode = Some(Out); /* latest argument == -o */ | ||||
| 			}, | ||||
| 			Err(_) | Ok(_) => { | ||||
| 				eprintln!("{}", usage); | ||||
| 				return ExitCode::from(EX_USAGE as u8); | ||||
| 				return usage(&argv[0]); | ||||
| 			}, | ||||
| 		}; | ||||
| 
 | ||||
| @ -108,32 +115,28 @@ fn main() -> ExitCode { | ||||
| 
 | ||||
| 	#[cfg(target_os="openbsd")] { | ||||
| 		for input in &ins { | ||||
| 			let perms = UnveilPerms::new(vec!['r']); | ||||
| 			let perms = UnveilPerms::new(['r']); | ||||
| 
 | ||||
| 			if let Err(e) = unveil(Some(&input), Some(perms)) { | ||||
| 				eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 				return ExitCode::from(EX_OSERR as u8); | ||||
| 				return err(&argv[0], e, Some(EX_OSERR)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for output in &outs { | ||||
| 			let perms = UnveilPerms::new(vec!['c', 'w']); | ||||
| 			let perms = UnveilPerms::new(['c', 'w']); | ||||
| 
 | ||||
| 			if let Err(e) = unveil(Some(&output), Some(perms)) { | ||||
| 				eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 				return ExitCode::from(EX_OSERR as u8); | ||||
| 				return err(&argv[0], e, Some(EX_OSERR)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if let Err(e) = unveil(None, None) { | ||||
| 			eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 			return ExitCode::from(EX_OSERR as u8); | ||||
| 			return err(&argv[0], e, Some(EX_OSERR)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if ins.is_empty() && outs.is_empty() && argv.len() > optind { | ||||
| 		eprintln!("Usage: {}", usage); | ||||
| 		return ExitCode::from(EX_USAGE as u8); | ||||
| 		return usage(&argv[0]); | ||||
| 	} | ||||
| 
 | ||||
| 	/* use stdin if no inputs are specified */ | ||||
| @ -153,8 +156,8 @@ fn main() -> ExitCode { | ||||
| 		match File::open(file) { | ||||
| 			Ok(f) => f, | ||||
| 			Err(e) => { | ||||
| 				eprintln!("{}: {}: {}", argv[0], file, e.strerror()); | ||||
| 				exit(EX_IOERR); | ||||
| 				let _ = err(&(argv[0].clone() + ": " + file), e, None); | ||||
| 				exit(EX_IOERR.into()); | ||||
| 			}, | ||||
| 		} | ||||
| 	}).collect::<Vec<_>>(); | ||||
| @ -180,8 +183,8 @@ fn main() -> ExitCode { | ||||
| 		match options { | ||||
| 			Ok(f) => return f, | ||||
| 			Err(e) => { | ||||
| 				eprintln!("{}: {}: {}", argv[0], file, e.strerror()); | ||||
| 				exit(EX_IOERR); | ||||
| 				let _ = err(&(argv[0].clone() + ": " + file), e, None); | ||||
| 				exit(EX_IOERR.into()); | ||||
| 			}, | ||||
| 		}; | ||||
| 	}).collect::<Vec<_>>(); | ||||
| @ -205,21 +208,19 @@ fn main() -> ExitCode { | ||||
| 	for file in inputs { | ||||
| 		for byte in file.bytes().map(|b| { | ||||
| 			b.unwrap_or_else(|e| { | ||||
| 				eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 				exit(EX_IOERR); | ||||
| 				let _ = err(&argv[0], e, None); | ||||
| 				exit(EX_IOERR.into()); | ||||
| 			}) | ||||
| 		}) { | ||||
| 			for out in &mut outputs { | ||||
| 				if let Err(e) = out.write(&[byte]) { | ||||
| 					eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 					return ExitCode::from(EX_IOERR as u8); | ||||
| 					return err(&argv[0], e, Some(EX_IOERR)); | ||||
| 				} | ||||
| 
 | ||||
| 				if u { | ||||
| 					/* immediately flush the output for -u */ | ||||
| 					if let Err(e) = out.flush() { 
 | ||||
| 						eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 						return ExitCode::from(EX_IOERR as u8); | ||||
| 						return err(&argv[0], e, Some(EX_IOERR)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| @ -20,7 +20,7 @@ | ||||
| #include <stdio.h> /* fprintf(3), fputs(3), getc(3), perror(3), putc(3), stdin, | ||||
|                     * stdout, EOF */ | ||||
| #include <sysexits.h> /* EX_IOERR, EX_OK, EX_OSERR, EX_USAGE */ | ||||
| #include <unistd.h> /* pledge(2), getopt(3) */ | ||||
| #include <unistd.h> /* NULL, getopt(3), pledge(2), unveil(2) */ | ||||
| 
 | ||||
| char *program_name = "npc"; | ||||
| 
 | ||||
| @ -44,7 +44,7 @@ int main(int argc, char *argv[]) { | ||||
| 	char showtab = 0; /* prints tab characters in caret notation */ | ||||
| 
 | ||||
| #ifdef __OpenBSD__ | ||||
| 	if (pledge("stdio", NULL) == -1) { | ||||
| 	if (pledge("stdio unveil", "") == -1 || unveil(NULL, NULL)) { | ||||
| 		perror(argv[0] == NULL ? program_name : argv[0]); | ||||
| 		return EX_OSERR; | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										185
									
								
								src/rpn.rs
									
									
									
									
									
								
							
							
						
						
									
										185
									
								
								src/rpn.rs
									
									
									
									
									
								
							| @ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media> | ||||
|  * Copyright (c) 2024–2025 Emma Tebibyte <emma@tebibyte.media> | ||||
|  * SPDX-License-Identifier: AGPL-3.0-or-later | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify it under | ||||
| @ -46,21 +46,21 @@ use std::{ | ||||
| 	collections::VecDeque, | ||||
| 	env::args, | ||||
| 	fmt::{ self, Display, Formatter }, | ||||
| 	io::stdin, | ||||
| 	io::{ Error, Write, stdin, stdout }, | ||||
| 	process::ExitCode, | ||||
| }; | ||||
| 
 | ||||
| use CalcType::*; | ||||
| 
 | ||||
| extern crate strerror; | ||||
| extern crate sysexits; | ||||
| 
 | ||||
| use sysexits::EX_DATAERR; | ||||
| use strerror::StrError; | ||||
| use sysexits::{ EX_DATAERR, EX_IOERR }; | ||||
| 
 | ||||
| #[cfg(target_os="openbsd")] use sysexits::EX_OSERR; | ||||
| #[cfg(target_os="openbsd")] extern crate strerror; | ||||
| #[cfg(target_os="openbsd")] extern crate openbsd; | ||||
| #[cfg(target_os="openbsd")] use strerror::StrError; | ||||
| #[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge }; | ||||
| #[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge, unveil }; | ||||
| 
 | ||||
| #[derive(Clone, PartialEq, PartialOrd, Debug)] | ||||
| /* enum CalcType is a type containing operations used in the calculator */ | ||||
| @ -120,12 +120,46 @@ impl Display for CalcType { | ||||
| #[derive(Debug, Clone)] | ||||
| struct EvaluationError { | ||||
| 	message: String, | ||||
| 	code: i32, | ||||
| 	code: u8, | ||||
| } | ||||
| 
 | ||||
| /* I’m no math nerd but I want the highest possible approximation of 0.9
 | ||||
|  * repeating and it seems this can give it to me */ | ||||
| const PRECISION_MOD: f64 = 0.9 + f64::EPSILON * 100.0; | ||||
| impl StrError for EvaluationError { | ||||
| 	fn strerror(&self) -> String { | ||||
| 		self.message.clone() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn err<T: StrError>(argv0: &String, e: &T, code: Option<u8>) -> ExitCode { | ||||
| 	eprintln!("{}: {}", argv0, e.strerror()); | ||||
| 	ExitCode::from(code.unwrap_or(1 /* unknown error */)) | ||||
| } | ||||
| 
 | ||||
| fn operate( | ||||
| 	mut stack: VecDeque<f64>, | ||||
| 	op: CalcType, | ||||
| ) -> Result<VecDeque<f64>, EvaluationError> { | ||||
| 	let vals = (stack.pop_back(), stack.pop_back()); | ||||
| 
 | ||||
| 	if let (Some(x), Some(y)) = vals { | ||||
| 		match op { | ||||
| 			Add => stack.push_back(y + x), | ||||
| 			Subtract => stack.push_back(y - x), | ||||
| 			Multiply => stack.push_back(y * x), | ||||
| 			Divide => stack.push_back(y / x), | ||||
| 			Power => stack.push_back(y.powf(x)), | ||||
| 			Floor => stack.push_back((y / x).floor()), | ||||
| 			Modulo => stack.push_back(y % x), | ||||
| 			_ => {}, | ||||
| 		}; | ||||
| 	} else { | ||||
| 		return Err(EvaluationError { | ||||
| 			message: format!("{}: unexpected operation", op), | ||||
| 			code: EX_DATAERR, | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	Ok(stack) | ||||
| } | ||||
| 
 | ||||
| fn eval( | ||||
| 	input: &str, | ||||
| @ -145,6 +179,7 @@ fn eval( | ||||
| 		.rev() | ||||
| 		.map(|t| CalcType::from(t)) | ||||
| 		.collect(); | ||||
| 
 | ||||
| 	let mut ops: VecDeque<CalcType> = VecDeque::new(); | ||||
| 
 | ||||
| 	while let Some(n) = toks.pop_back() { | ||||
| @ -152,36 +187,15 @@ fn eval( | ||||
| 			Val(v) => stack.push_back(v), | ||||
| 			Invalid(i) => { | ||||
| 				return Err(EvaluationError { | ||||
| 					message: format!("{}: Invalid token", i), | ||||
| 					message: format!("{}: invalid token", i), | ||||
| 					code: EX_DATAERR, | ||||
| 				}) | ||||
| 			}, | ||||
| 			op => { | ||||
| 				ops.push_back(op.clone()); | ||||
| 				oper = true; | ||||
| 
 | ||||
| 				let vals = ( | ||||
| 					stack.pop_back(), | ||||
| 					stack.pop_back(), | ||||
| 				); | ||||
| 
 | ||||
| 				if let (Some(x), Some(y)) = vals { | ||||
| 					match op { | ||||
| 						Add => stack.push_back(y + x), | ||||
| 						Subtract => stack.push_back(y - x), | ||||
| 						Multiply => stack.push_back(y * x), | ||||
| 						Divide => stack.push_back(y / x), | ||||
| 						Power => stack.push_back(y.powf(x)), | ||||
| 						Floor => stack.push_back((y / x).floor()), | ||||
| 						Modulo => stack.push_back(y % x), | ||||
| 						_ => {}, | ||||
| 					}; | ||||
| 				} else { | ||||
| 					return Err(EvaluationError { | ||||
| 						message: format!("{}: Unexpected operation", op), | ||||
| 						code: EX_DATAERR, | ||||
| 					}) | ||||
| 				} | ||||
| 				oper = true; /* this is an operation */ | ||||
| 				return operate(stack, op).map(|s| (s, oper)); | ||||
| 			}, | ||||
| 		}; | ||||
| 	} | ||||
| @ -190,51 +204,46 @@ fn eval( | ||||
| } | ||||
| 
 | ||||
| /* Round a float to the given precision level */ | ||||
| fn round_precise(value: &f64, precision: usize) -> f64 { | ||||
| 	let multiplier = 10_f64.powi(precision as i32); | ||||
| fn round_precise(value: &f64) -> f64 { | ||||
| 	/* Set floating-point precision for correcting rounding errors based on
 | ||||
| 	 * machine epsilon */ | ||||
| 	let precision = (-f64::EPSILON.log10()).floor() as i32; | ||||
| 	let multiplier = 10_f64.powi(precision); | ||||
| 
 | ||||
| 	(value * multiplier).round() / multiplier | ||||
| } | ||||
| 
 | ||||
| /* print the stack and let the caller know if evaluation should continue */ | ||||
| fn unstack(stack: VecDeque<f64>, op: bool) -> Result<bool, Error> { | ||||
| 	if let Some(val) = stack.iter().last() { | ||||
| 		if !op { return Ok(true); } | ||||
| 
 | ||||
| 		let out = round_precise(val).to_string() + &'\n'.to_string(); | ||||
| 
 | ||||
| 		return stdout().write_all(out.as_bytes()).map(|_| true); | ||||
| 	} else { | ||||
| 		return Ok(false); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn main() -> ExitCode { | ||||
| 	let argv = args().collect::<Vec<String>>(); | ||||
| 
 | ||||
| 	#[cfg(target_os="openbsd")] { | ||||
| 		let promises = Promises::new("stdio"); | ||||
| 		if let Err(e) = pledge(Some(promises), None) { | ||||
| 			eprintln!("{}: {}", argv[0], e.strerror()); | ||||
| 			return ExitCode::from(EX_OSERR as u8); | ||||
| 		let promises = Promises::new("stdio unveil"); | ||||
| 		if let Err(e) = pledge(Some(promises), Some(Promises::default())) { | ||||
| 			return err(&argv[0], &e, Some(EX_OSERR)); | ||||
| 		} | ||||
| 
 | ||||
| 		if let Err(e) = unveil(None, None) { | ||||
| 			return err(&argv[0], &e, Some(EX_OSERR)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	let mut stack = VecDeque::new(); | ||||
| 	let mut buf = String::new(); | ||||
| 	/* Set floating-point precision for correcting rounding errors based on
 | ||||
| 	 * machine epsilon */ | ||||
| 	let precision = (-f64::EPSILON.log10() * PRECISION_MOD).ceil() as usize; | ||||
| 
 | ||||
| 	if argv.get(1).is_none() { /* read from stdin */ | ||||
| 		while let Ok(_) = stdin().read_line(&mut buf) { | ||||
| 			match eval(&buf.trim(), stack) { | ||||
| 				Ok(s) => { | ||||
| 					buf.clear(); | ||||
| 					stack = s.0.clone(); | ||||
| 
 | ||||
| 					let val = match stack.iter().last() { | ||||
| 						Some(v) => v, | ||||
| 						None => break, | ||||
| 					}; | ||||
| 
 | ||||
| 					if s.1 == false { continue; } | ||||
| 
 | ||||
| 					println!("{}", round_precise(val, precision).to_string()); | ||||
| 				}, | ||||
| 				Err(err) => { | ||||
| 					eprintln!("{}: {}", argv[0], err.message); | ||||
| 					return ExitCode::from(err.code as u8); | ||||
| 				}, | ||||
| 			}; | ||||
| 		} | ||||
| 	} else { /* read from argv */ | ||||
| 	if argv.get(1).is_some() { /* read expressions from argv */ | ||||
| 		/* join argv into an owned String joined by spaces minus argv[0] */ | ||||
| 		let input = argv | ||||
| 			.iter() | ||||
| @ -245,20 +254,44 @@ fn main() -> ExitCode { | ||||
| 
 | ||||
| 		match eval(&input, stack) { | ||||
| 			Ok(s) => { | ||||
| 				stack = s.0.clone(); | ||||
| 				/* we can ignore the return value of unstack() because we are
 | ||||
| 				 * not continually evaluating from stdin */ | ||||
| 				if let Err(e) = unstack(s.0.clone(), s.1.clone()) { | ||||
| 					return err(&argv[0], &e, Some(EX_IOERR)); | ||||
| 				} | ||||
| 
 | ||||
| 				let val = match stack.iter().last() { | ||||
| 					Some(v) => v, | ||||
| 					None => return ExitCode::SUCCESS, | ||||
| 				}; | ||||
| 
 | ||||
| 				println!("{}", round_precise(val, precision).to_string()) | ||||
| 				return ExitCode::SUCCESS; | ||||
| 			}, | ||||
| 			Err(err) => { | ||||
| 				eprintln!("{}: {}", argv[0], err.message); | ||||
| 				return ExitCode::from(err.code as u8); | ||||
| 			Err(e) => { | ||||
| 				return err(&argv[0], &e, Some(e.code)); | ||||
| 			}, | ||||
| 		}; | ||||
| 	} | ||||
| 
 | ||||
| 	/* else, read from stdin */ | ||||
| 	loop { /* take input until EOF */ | ||||
| 		if let Err(e) = stdin().read_line(&mut buf) { | ||||
| 			return err(&argv[0], &e, Some(EX_IOERR)); | ||||
| 		} | ||||
| 
 | ||||
| 		match eval(&buf.trim(), stack) { | ||||
| 			Ok(s) => { | ||||
| 				buf.clear(); | ||||
| 				stack = s.0.clone(); /* out with the old, in with the new */ | ||||
| 
 | ||||
| 				match unstack(s.0, s.1) { | ||||
| 					Ok(b) if b => continue, | ||||
| 					Ok(_) => break, | ||||
| 					Err(e) => { | ||||
| 						return err(&argv[0], &e, Some(EX_IOERR)) | ||||
| 					}, | ||||
| 				}; | ||||
| 			}, | ||||
| 			Err(e) => { | ||||
| 				return err(&argv[0], &e, Some(e.code)); | ||||
| 			}, | ||||
| 		}; | ||||
| 	} | ||||
| 
 | ||||
| 	ExitCode::SUCCESS | ||||
| } | ||||
|  | ||||
| @ -46,7 +46,7 @@ int main(int argc, char *argv[]) { | ||||
| 	program_name = argv[0] == NULL ? program_name : argv[0]; | ||||
| 
 | ||||
| #ifdef __OpenBSD__ | ||||
| 	if (pledge("rpath stdio unveil", NULL) == -1) { | ||||
| 	if (pledge("rpath stdio unveil", "") == -1) { | ||||
| 		perror(program_name); | ||||
| 		return EX_OSERR; | ||||
| 	} | ||||
| @ -82,7 +82,7 @@ int main(int argc, char *argv[]) { | ||||
| 		struct stat buf; | ||||
| 
 | ||||
| #ifdef __OpenBSD__ | ||||
| 		if (unveil(*argv, "r") == -1) { | ||||
| 		if (unveil(*argv, "rw") == -1) { | ||||
| 			perror(program_name); | ||||
| 			return EX_OSERR; | ||||
| 		} | ||||
|  | ||||
| @ -25,7 +25,7 @@ | ||||
| #include <sysexits.h> /* EX_OSERR, EX_USAGE */ | ||||
| 
 | ||||
| #ifdef __OpenBSD__ | ||||
| #	include <unistd.h> /* pledge(2) */ | ||||
| #	include <unistd.h> /* pledge(2), unveil(2) */ | ||||
| #endif | ||||
| 
 | ||||
| char *program_name = "str"; | ||||
| @ -62,7 +62,7 @@ int main(int argc, char *argv[]) { | ||||
| 	program_name = argv[0] == NULL ? program_name : argv[0]; | ||||
| 
 | ||||
| #ifdef __OpenBSD__ | ||||
| 	if (pledge("stdio", NULL) == -1) { | ||||
| 	if (pledge("stdio unveil", "") == -1 || unveil(NULL, NULL) == -1) { | ||||
| 		perror(program_name); | ||||
| 		return EX_OSERR; | ||||
| 	} | ||||
|  | ||||
| @ -20,7 +20,7 @@ | ||||
| #include <sysexits.h> /* EX_OK, EX_OSERR, EX_USAGE */ | ||||
| 
 | ||||
| #ifdef __OpenBSD__ | ||||
| #	include <unistd.h> /* pledge(2) */ | ||||
| #	include <unistd.h> /* pledge(2), unveil(2) */ | ||||
| #endif | ||||
| 
 | ||||
| char *program_name = "strcmp"; | ||||
| @ -29,7 +29,7 @@ int main(int argc, char *argv[]) { | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| #ifdef __OpenBSD__ | ||||
| 	if (pledge("stdio", NULL) == -1) { | ||||
| 	if (pledge("stdio unveil", "") == -1 || unveil(NULL, NULL) == -1) { | ||||
| 		perror(argv[0] == NULL ? program_name : argv[0]); | ||||
| 
 | ||||
| 		return EX_OSERR; | ||||
|  | ||||
							
								
								
									
										34
									
								
								src/swab.rs
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								src/swab.rs
									
									
									
									
									
								
							| @ -33,31 +33,29 @@ use sysexits::{ EX_IOERR, EX_OK, EX_OSERR, EX_USAGE }; | ||||
| use strerror::StrError; | ||||
| 
 | ||||
| #[cfg(target_os="openbsd")] extern crate openbsd; | ||||
| #[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge }; | ||||
| #[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge, unveil }; | ||||
| 
 | ||||
| 
 | ||||
| fn oserr(argv0: &str, e: Error) -> ExitCode { | ||||
| fn err(argv0: &String, e: Error, code: u8) -> ExitCode { | ||||
| 	eprintln!("{}: {}", argv0, e.strerror()); | ||||
| 	ExitCode::from(EX_OSERR as u8) | ||||
| 	ExitCode::from(code) | ||||
| } | ||||
| 
 | ||||
| fn ioerr(argv0: &str, e: Error) -> ExitCode { | ||||
| 	eprintln!("{}: {}", argv0, e.strerror()); | ||||
| 	ExitCode::from(EX_IOERR as u8) | ||||
| } | ||||
| 
 | ||||
| fn usage(s: &str) -> ExitCode { | ||||
| fn usage(s: &String) -> ExitCode { | ||||
| 	eprintln!("Usage: {} [-w word_size]", s); | ||||
| 	ExitCode::from(EX_USAGE as u8) | ||||
| 	ExitCode::from(EX_USAGE) | ||||
| } | ||||
| 
 | ||||
| fn main() -> ExitCode { | ||||
| 	let argv = args().collect::<Vec<String>>(); | ||||
| 	
 | ||||
| 	#[cfg(target_os="openbsd")] { | ||||
| 		let promises = Promises::new("stdio"); | ||||
| 		if let Err(e) = pledge(Some(promises), None) { | ||||
| 			return oserr(&argv[0], e); | ||||
| 		let promises = Promises::new("stdio unveil"); | ||||
| 		if let Err(e) = pledge(Some(promises), Some(Promises::default())) { | ||||
| 			return err(&argv[0], e, EX_OSERR); | ||||
| 		} | ||||
| 
 | ||||
| 		if let Err(e) = unveil(None, None) { | ||||
| 			return err(&argv[0], e, EX_OSERR); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -88,22 +86,22 @@ fn main() -> ExitCode { | ||||
| 
 | ||||
| 	loop { | ||||
| 		match input.read(&mut buf) { | ||||
| 			Ok(0) => break ExitCode::from(EX_OK as u8), // read nothing; bye
 | ||||
| 			Ok(0) => break ExitCode::from(EX_OK), // read nothing; bye
 | ||||
| 			Ok(v) if v == wordsize => { // read full block; swab
 | ||||
| 				let (left, right) = buf.split_at(v/2); | ||||
| 
 | ||||
| 				if let Err(e) = output.write(&right) | ||||
| 						.and_then(|_| output.write(&left)) { | ||||
| 					break ioerr(&argv[0], e); | ||||
| 					break err(&argv[0], e, EX_IOERR); | ||||
| 				} | ||||
| 
 | ||||
| 			}, | ||||
| 			Ok(v) => { // partial read; partially write
 | ||||
| 				if let Err(e) = output.write(&buf[..v]) { | ||||
| 					break ioerr(&argv[0], e); | ||||
| 					break err(&argv[0], e, EX_IOERR); | ||||
| 				} | ||||
| 			}, | ||||
| 			Err(e) => break oserr(&argv[0], e) | ||||
| 			Err(e) => break err(&argv[0], e, EX_OSERR) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -13,6 +13,6 @@ | ||||
| 
 | ||||
| int main(void) { | ||||
| #ifdef __OpenBSD__ | ||||
| 	pledge(NULL, NULL); | ||||
| 	(void)pledge("stdio", ""); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| @ -24,6 +24,7 @@ fop_fail: $(BIN)/fop | ||||
| 	! printf 'test\n' | $(BIN)/fop 1 cat | ||||
| 	! printf 'test\n' | $(BIN)/fop 'test' cat | ||||
| 	! printf 'test\n' | $(BIN)/fop -d'test' cat | ||||
| 	! $(BIN)/fop | ||||
| 
 | ||||
| .PHONY: fop_functionality | ||||
| fop_functionality: $(BIN)/fop | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
| # notice are preserved.  This file is offered as-is, without any warranty.
 | ||||
| 
 | ||||
| .PHONY: mm_tests | ||||
| mm_tests: mm_args mm_help mm_stderr mm_remaining | ||||
| mm_tests: mm_args mm_help mm_stderr mm_remaining mm_remaining_options | ||||
| 
 | ||||
| .PHONY: mm_none | ||||
| mm_none: $(BIN)/mm | ||||
| @ -32,3 +32,9 @@ mm_remaining: $(BIN)/mm | ||||
| 	test "$$($(BIN)/mm -i README COPYING)" = "$$(cat README COPYING)" | ||||
| 	$(BIN)/mm -i README -o /tmp/mm_test0 /tmp/mm_test1 | ||||
| 	diff /tmp/mm_test0 /tmp/mm_test1 | ||||
| 
 | ||||
| .PHONY: mm_remaining_options | ||||
| # check to make sure mm -i with trailing arguments interprets -o as one
 | ||||
| mm_remaining_options: | ||||
| 	! $(BIN)/mm -i README COPYING -o - 2>&1 | cut -d: -f2 \
 | ||||
| 		| xargs test " -o" = | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
| # notice are preserved.  This file is offered as-is, without any warranty.
 | ||||
| 
 | ||||
| .PHONY: rpn_tests | ||||
| rpn_tests: rpn_help rpn_add rpn_sub rpn_mul rpn_div rpn_mod rpn_flr | ||||
| rpn_tests: rpn_help rpn_add rpn_sub rpn_mul rpn_div rpn_mod rpn_flr rpn_stdin | ||||
| 
 | ||||
| .PHONY: rpn_help | ||||
| rpn_help: $(BIN)/rpn | ||||
| @ -41,3 +41,8 @@ rpn_mod: $(BIN)/rpn | ||||
| rpn_flr: $(BIN)/rpn | ||||
| 	test "$$($(BIN)/rpn 12 5 //)" -eq 2 | ||||
| 	test "$$($(BIN)/rpn 9 4 //)" -eq 2 | ||||
| 
 | ||||
| # done last because all operations have been tested
 | ||||
| .PHONY: rpn_stdin | ||||
| rpn_stdin: $(BIN)/rpn | ||||
| 	test "$$(printf '1\n2\n+\n3\n-\n' | $(BIN)/rpn | tail -n1)" -eq 0 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user