optimizations #161
2
Makefile
2
Makefile
@ -95,7 +95,7 @@ build/o/libstrerror.rlib: build src/libstrerror.rs
|
|||||||
src/libstrerror.rs
|
src/libstrerror.rs
|
||||||
|
|
||||||
build/o/libsysexits.rlib: build/include/sysexits.h
|
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 $@ -
|
build/include/sysexits.h | $(RUSTC) $(RUSTFLAGS) --crate-type lib -o $@ -
|
||||||
|
|
||||||
# bandage solution until bindgen(1) gets stdin support
|
# bandage solution until bindgen(1) gets stdin support
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
pledge(NULL, NULL);
|
(void)pledge("stdio", "");
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
71
src/fop.rs
71
src/fop.rs
@ -18,8 +18,8 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
env::args,
|
env::args,
|
||||||
io::{ Read, stdin, stdout, Write },
|
io::{ Error, Read, Write, stdin, stdout },
|
||||||
process::{ Command, exit, Stdio },
|
process::{ Command, ExitCode, Stdio, exit },
|
||||||
};
|
};
|
||||||
|
|
||||||
extern crate getopt;
|
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")] use sysexits::EX_OSERR;
|
||||||
#[cfg(target_os="openbsd")] extern crate openbsd;
|
#[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 argv = args().collect::<Vec<String>>();
|
||||||
let mut d = '\u{1E}'.to_string(); /* ASCII record separator */
|
let mut d = '\u{1E}'.to_string(); /* ASCII record separator */
|
||||||
let mut optind = 1;
|
let mut optind = 1;
|
||||||
|
|
||||||
#[cfg(target_os="openbsd")] {
|
#[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) {
|
if let Err(e) = pledge(Some(promises), None) {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
err(&argv[0], e);
|
||||||
exit(EX_OSERR);
|
return ExitCode::from(EX_OSERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = unveil(None, None) {
|
||||||
|
err(&argv[0], e);
|
||||||
|
return ExitCode::from(EX_OSERR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let usage = format!(
|
if argv.len() == 1 { return ExitCode::from(usage(&argv[0])); }
|
||||||
"Usage: {} [-d delimiter] index command [args...]",
|
|
||||||
argv[0],
|
|
||||||
);
|
|
||||||
|
|
||||||
while let Some(opt) = argv.getopt("d:") {
|
while let Some(opt) = argv.getopt("d:") {
|
||||||
match opt.opt() {
|
match opt.opt() {
|
||||||
@ -60,8 +71,7 @@ fn main() {
|
|||||||
optind = opt.ind();
|
optind = opt.ind();
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
eprintln!("{}", usage);
|
return ExitCode::from(usage(&argv[0]));
|
||||||
exit(EX_USAGE);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -69,7 +79,7 @@ fn main() {
|
|||||||
/* parse the specified index as a number we can use */
|
/* parse the specified index as a number we can use */
|
||||||
let index = argv[optind].parse::<usize>().unwrap_or_else(|e| {
|
let index = argv[optind].parse::<usize>().unwrap_or_else(|e| {
|
||||||
eprintln!("{}: {}: {}", argv[0], argv[1], e);
|
eprintln!("{}: {}: {}", argv[0], argv[1], e);
|
||||||
exit(EX_DATAERR);
|
exit(EX_DATAERR.into());
|
||||||
});
|
});
|
||||||
|
|
||||||
/* index of the argv[0] for the operator command */
|
/* index of the argv[0] for the operator command */
|
||||||
@ -77,15 +87,14 @@ fn main() {
|
|||||||
|
|
||||||
/* argv[0] of the operator command */
|
/* argv[0] of the operator command */
|
||||||
let operator = argv.get(command_arg).unwrap_or_else(|| {
|
let operator = argv.get(command_arg).unwrap_or_else(|| {
|
||||||
eprintln!("{}", usage);
|
exit(usage(&argv[0]).into());
|
||||||
exit(EX_USAGE);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* read entire standard input into memory */
|
/* read entire standard input into memory */
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
if let Err(e) = stdin().read_to_string(&mut buf) {
|
if let Err(e) = stdin().read_to_string(&mut buf) {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
err(&argv[0], e);
|
||||||
exit(EX_IOERR);
|
exit(EX_IOERR.into());
|
||||||
};
|
};
|
||||||
|
|
||||||
/* split the buffer by the delimiter (by default, '\u{1E}') */
|
/* 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 */
|
.stdout(Stdio::piped()) /* piped stdout to handle output ourselves */
|
||||||
.spawn()
|
.spawn()
|
||||||
.unwrap_or_else( |e| {
|
.unwrap_or_else( |e| {
|
||||||
eprintln!("{}: {}: {}", argv[0], argv[command_arg], e.strerror());
|
err(&argv[0], e);
|
||||||
exit(EX_UNAVAILABLE);
|
exit(EX_UNAVAILABLE.into());
|
||||||
});
|
});
|
||||||
|
|
||||||
/* get field we want to pipe into spawned program */
|
/* get field we want to pipe into spawned program */
|
||||||
let field = fields.get(index).unwrap_or_else(|| {
|
let field = fields.get(index).unwrap_or_else(|| {
|
||||||
eprintln!(
|
eprintln!("{}: {}: no such index in input", argv[0], index);
|
||||||
"{}: {}: No such index in input",
|
exit(EX_DATAERR.into());
|
||||||
argv[0],
|
|
||||||
index.to_string(),
|
|
||||||
);
|
|
||||||
exit(EX_DATAERR);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* get the stdin of the newly spawned program and feed it the field val */
|
/* 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| {
|
let output = spawned.wait_with_output().unwrap_or_else(|e| {
|
||||||
eprintln!("{}: {}: {}", argv[0], argv[command_arg], e.strerror());
|
err(&argv[0], e);
|
||||||
exit(EX_IOERR);
|
exit(EX_IOERR.into());
|
||||||
});
|
});
|
||||||
|
|
||||||
/* get the output with which the original field will be replaced */
|
/* 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 */
|
/* convert the output of the program to UTF-8 */
|
||||||
let new_field = String::from_utf8(replace).unwrap_or_else(|e| {
|
let new_field = String::from_utf8(replace).unwrap_or_else(|e| {
|
||||||
eprintln!("{}: {}: {}", argv[0], argv[command_arg], e);
|
eprintln!("{}: {}", argv[0], e);
|
||||||
exit(EX_IOERR);
|
exit(EX_IOERR.into());
|
||||||
});
|
});
|
||||||
|
|
||||||
/* store the new field in the old fields vector */
|
/* store the new field in the old fields vector */
|
||||||
@ -154,7 +159,9 @@ fn main() {
|
|||||||
stdout().write_all(
|
stdout().write_all(
|
||||||
fields.join(&d.to_string()).as_bytes()
|
fields.join(&d.to_string()).as_bytes()
|
||||||
).unwrap_or_else(|e| {
|
).unwrap_or_else(|e| {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
err(&argv[0], e);
|
||||||
exit(EX_IOERR);
|
exit(EX_IOERR.into());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ExitCode::SUCCESS
|
||||||
}
|
}
|
||||||
|
79
src/hru.rs
79
src/hru.rs
@ -19,7 +19,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
env::args,
|
env::args,
|
||||||
io::{ stdin, stdout, Write },
|
io::{ Write, stdin, stdout },
|
||||||
process::{ ExitCode, exit },
|
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")] use sysexits::EX_OSERR;
|
||||||
#[cfg(target_os="openbsd")] extern crate openbsd;
|
#[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 */
|
/* list of SI prefixes */
|
||||||
const LIST: [(u32, &str); 10] = [
|
const LIST: [(u32, &str); 10] = [
|
||||||
@ -47,6 +47,16 @@ const LIST: [(u32, &str); 10] = [
|
|||||||
(30, "Q"), /* quetta */
|
(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> {
|
fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> {
|
||||||
/* preserve decimal places in output by casting to a float */
|
/* preserve decimal places in output by casting to a float */
|
||||||
let mut out = (input as f64, (0_u32, ""));
|
let mut out = (input as f64, (0_u32, ""));
|
||||||
@ -81,53 +91,48 @@ fn convert(input: u128) -> Result<(f64, (u32, &'static str)), String> {
|
|||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let argv = args().collect::<Vec<String>>();
|
let argv = args().collect::<Vec<String>>();
|
||||||
|
|
||||||
if let Some(_) = argv.get(1) {
|
if let Some(_) = argv.get(1) { return usage(&argv[0]); }
|
||||||
eprintln!("Usage: {}", argv[0]);
|
|
||||||
return ExitCode::from(EX_USAGE as u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os="openbsd")] {
|
#[cfg(target_os="openbsd")] {
|
||||||
let promises = Promises::new("stdio");
|
let promises = Promises::new("stdio unveil");
|
||||||
if let Err(e) = pledge(Some(promises), None) {
|
if let Err(e) = pledge(Some(promises), Some(Promises::default())) {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
return err(&argv[0], e.strerror(), Some(EX_OSERR));
|
||||||
return ExitCode::from(EX_OSERR as u8);
|
}
|
||||||
|
|
||||||
|
if let Err(e) = unveil(None, None) {
|
||||||
|
return err(&argv[0], e.strerror(), Some(EX_OSERR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
|
|
||||||
while let Ok(_) = stdin().read_line(&mut buf) {
|
if let Err(e) = stdin().read_line(&mut buf) {
|
||||||
if buf.is_empty() { return ExitCode::SUCCESS; }
|
return err(&argv[0], e.strerror(), Some(EX_IOERR));
|
||||||
|
}
|
||||||
|
|
||||||
let n: u128 = match buf.trim().parse() {
|
if buf.is_empty() { return ExitCode::SUCCESS; }
|
||||||
Ok(f) => {
|
|
||||||
buf.clear();
|
|
||||||
f
|
|
||||||
},
|
|
||||||
Err(err) => {
|
|
||||||
eprintln!("{}: {}", argv[0], err);
|
|
||||||
return ExitCode::from(EX_DATAERR as u8);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let (number, prefix) = match convert(n) {
|
let n: u128 = match buf.trim().parse() {
|
||||||
Ok(x) => x,
|
Ok(f) => {
|
||||||
Err(err) => {
|
buf.clear();
|
||||||
eprintln!("{}: {}", argv[0], err);
|
f
|
||||||
return ExitCode::from(EX_SOFTWARE as u8);
|
},
|
||||||
},
|
Err(e) => return err(&argv[0], e.to_string(), Some(EX_DATAERR)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let si_prefix = format!("{}B", prefix.1);
|
let (number, prefix) = convert(n).unwrap_or_else(|e| {
|
||||||
|
let _ = err(&argv[0], e.to_string(), None);
|
||||||
|
exit(EX_SOFTWARE.into());
|
||||||
|
});
|
||||||
|
|
||||||
/* round output number to one decimal place */
|
let si_prefix = prefix.1.to_owned() + "B";
|
||||||
let out = ((number * 10.0).round() / 10.0).to_string();
|
|
||||||
|
|
||||||
stdout().write_all(format!("{} {}\n", out, si_prefix).as_bytes())
|
/* round output number to one decimal place */
|
||||||
.unwrap_or_else(|e| {
|
let rounded = (number * 10.0).round() / 10.0;
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
let out = rounded.to_string() + " " + &si_prefix + &'\n'.to_string();
|
||||||
exit(EX_IOERR);
|
|
||||||
});
|
if let Err(e) = stdout().write_all(out.as_bytes()) {
|
||||||
|
return err(&argv[0], e.strerror(), Some(EX_IOERR));
|
||||||
}
|
}
|
||||||
|
|
||||||
ExitCode::SUCCESS
|
ExitCode::SUCCESS
|
||||||
|
@ -26,27 +26,35 @@ extern crate getopt;
|
|||||||
extern crate sysexits;
|
extern crate sysexits;
|
||||||
|
|
||||||
use getopt::GetOpt;
|
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")] use sysexits::EX_OSERR;
|
||||||
#[cfg(target_os="openbsd")] extern crate openbsd;
|
#[cfg(target_os="openbsd")] extern crate openbsd;
|
||||||
#[cfg(target_os="openbsd")] extern crate strerror;
|
#[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;
|
#[cfg(target_os="openbsd")] use strerror::StrError;
|
||||||
|
|
||||||
fn usage(s: &str) -> ExitCode {
|
fn err(argv0: &String, e: String, code: u8) -> ExitCode {
|
||||||
eprintln!("Usage: {} [-egl] integer integer...", s);
|
eprintln!("{}: {}", argv0, e);
|
||||||
ExitCode::from(EX_USAGE as u8)
|
ExitCode::from(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(argv0: &String) -> ExitCode {
|
||||||
|
eprintln!("Usage: {} [-egl] integer integer...", argv0);
|
||||||
|
ExitCode::from(EX_USAGE)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let argv = args().collect::<Vec<String>>();
|
let argv = args().collect::<Vec<String>>();
|
||||||
|
|
||||||
#[cfg(target_os="openbsd")] {
|
#[cfg(target_os="openbsd")] {
|
||||||
let promises = Promises::new("stdio");
|
let promises = Promises::new("stdio unveil");
|
||||||
if let Err(e) = pledge(Some(promises), None) {
|
if let Err(e) = pledge(Some(promises), Some(Promises::default())) {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
return err(&argv[0], e.strerror(), EX_OSERR);
|
||||||
return ExitCode::from(EX_OSERR as u8);
|
}
|
||||||
|
|
||||||
|
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 */
|
match arg.parse::<usize>() { /* parse current operand */
|
||||||
Ok(n) => currn = n,
|
Ok(n) => currn = n,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{}: {}: {}", &argv[0], arg, e);
|
let error = arg.to_owned() + ": " + &e.to_string();
|
||||||
return ExitCode::from(EX_USAGE as u8);
|
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(
|
pub fn pledge(
|
||||||
promises: Option<Promises>, execpromises: Option<Promises>
|
promises: Option<Promises>, execpromises: Option<Promises>
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
@ -65,14 +69,12 @@ pub fn pledge(
|
|||||||
pub struct UnveilPerms(CString);
|
pub struct UnveilPerms(CString);
|
||||||
|
|
||||||
impl UnveilPerms {
|
impl UnveilPerms {
|
||||||
pub fn new(permissions: Vec<char>) -> Self {
|
pub fn new<T: IntoIterator<Item = char>>(permissions: T) -> Self {
|
||||||
if permissions.is_empty() {
|
let perms = CString::new(
|
||||||
return UnveilPerms(CString::new("").unwrap());
|
permissions.into_iter().collect::<String>()
|
||||||
}
|
).unwrap();
|
||||||
|
|
||||||
UnveilPerms(
|
UnveilPerms(perms)
|
||||||
CString::new(permissions.iter().collect::<String>()).unwrap()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,9 +85,9 @@ pub fn unveil(
|
|||||||
let path_c = path.map(CString::new).map(Result::unwrap);
|
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 arg1 = path_c.map(|p| p.into_raw() as *const c_char).unwrap_or(null());
|
||||||
|
|
||||||
let arg2 = permissions
|
let arg2 = permissions.map(|p| {
|
||||||
.map(|p| p.0.into_raw() as *const c_char)
|
p.0.into_raw() as *const c_char
|
||||||
.unwrap_or(null());
|
}).unwrap_or(null());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
match openbsd::unveil(arg1, arg2) {
|
match openbsd::unveil(arg1, arg2) {
|
||||||
|
57
src/mm.rs
57
src/mm.rs
@ -20,9 +20,9 @@
|
|||||||
use std::{
|
use std::{
|
||||||
env::args,
|
env::args,
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{ stdin, stdout, stderr, BufWriter, Read, Write },
|
io::{ Error, BufWriter, Read, Write, stderr, stdin, stdout },
|
||||||
os::fd::{ AsRawFd, FromRawFd },
|
os::fd::{ AsRawFd, FromRawFd },
|
||||||
process::{ exit, ExitCode },
|
process::{ ExitCode, exit},
|
||||||
};
|
};
|
||||||
|
|
||||||
extern crate getopt;
|
extern crate getopt;
|
||||||
@ -47,15 +47,23 @@ use ArgMode::*;
|
|||||||
|
|
||||||
enum ArgMode { In, Out }
|
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 {
|
fn main() -> ExitCode {
|
||||||
let argv = args().collect::<Vec<_>>();
|
let argv = args().collect::<Vec<_>>();
|
||||||
let usage = format!("Usage: {} [-aetu] [-i input] [-o output]", argv[0]);
|
|
||||||
|
|
||||||
#[cfg(target_os="openbsd")] {
|
#[cfg(target_os="openbsd")] {
|
||||||
let promises = Promises::new("cpath rpath stdio unveil wpath");
|
let promises = Promises::new("cpath rpath stdio unveil wpath");
|
||||||
if let Err(e) = pledge(Some(promises), None) {
|
if let Err(e) = pledge(Some(promises), Some(Promises::default())) {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
return err(&argv[0], e, Some(EX_OSERR));
|
||||||
return ExitCode::from(EX_OSERR as u8);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,8 +93,7 @@ fn main() -> ExitCode {
|
|||||||
mode = Some(Out); /* latest argument == -o */
|
mode = Some(Out); /* latest argument == -o */
|
||||||
},
|
},
|
||||||
Err(_) | Ok(_) => {
|
Err(_) | Ok(_) => {
|
||||||
eprintln!("{}", usage);
|
return usage(&argv[0]);
|
||||||
return ExitCode::from(EX_USAGE as u8);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,32 +115,28 @@ fn main() -> ExitCode {
|
|||||||
|
|
||||||
#[cfg(target_os="openbsd")] {
|
#[cfg(target_os="openbsd")] {
|
||||||
for input in &ins {
|
for input in &ins {
|
||||||
let perms = UnveilPerms::new(vec!['r']);
|
let perms = UnveilPerms::new(['r']);
|
||||||
|
|
||||||
if let Err(e) = unveil(Some(&input), Some(perms)) {
|
if let Err(e) = unveil(Some(&input), Some(perms)) {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
return err(&argv[0], e, Some(EX_OSERR));
|
||||||
return ExitCode::from(EX_OSERR as u8);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for output in &outs {
|
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)) {
|
if let Err(e) = unveil(Some(&output), Some(perms)) {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
return err(&argv[0], e, Some(EX_OSERR));
|
||||||
return ExitCode::from(EX_OSERR as u8);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = unveil(None, None) {
|
if let Err(e) = unveil(None, None) {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
return err(&argv[0], e, Some(EX_OSERR));
|
||||||
return ExitCode::from(EX_OSERR as u8);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ins.is_empty() && outs.is_empty() && argv.len() > optind {
|
if ins.is_empty() && outs.is_empty() && argv.len() > optind {
|
||||||
eprintln!("Usage: {}", usage);
|
return usage(&argv[0]);
|
||||||
return ExitCode::from(EX_USAGE as u8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use stdin if no inputs are specified */
|
/* use stdin if no inputs are specified */
|
||||||
@ -153,8 +156,8 @@ fn main() -> ExitCode {
|
|||||||
match File::open(file) {
|
match File::open(file) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{}: {}: {}", argv[0], file, e.strerror());
|
let _ = err(&(argv[0].clone() + ": " + file), e, None);
|
||||||
exit(EX_IOERR);
|
exit(EX_IOERR.into());
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
@ -180,8 +183,8 @@ fn main() -> ExitCode {
|
|||||||
match options {
|
match options {
|
||||||
Ok(f) => return f,
|
Ok(f) => return f,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{}: {}: {}", argv[0], file, e.strerror());
|
let _ = err(&(argv[0].clone() + ": " + file), e, None);
|
||||||
exit(EX_IOERR);
|
exit(EX_IOERR.into());
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
@ -205,21 +208,19 @@ fn main() -> ExitCode {
|
|||||||
for file in inputs {
|
for file in inputs {
|
||||||
for byte in file.bytes().map(|b| {
|
for byte in file.bytes().map(|b| {
|
||||||
b.unwrap_or_else(|e| {
|
b.unwrap_or_else(|e| {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
let _ = err(&argv[0], e, None);
|
||||||
exit(EX_IOERR);
|
exit(EX_IOERR.into());
|
||||||
})
|
})
|
||||||
}) {
|
}) {
|
||||||
for out in &mut outputs {
|
for out in &mut outputs {
|
||||||
if let Err(e) = out.write(&[byte]) {
|
if let Err(e) = out.write(&[byte]) {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
return err(&argv[0], e, Some(EX_IOERR));
|
||||||
return ExitCode::from(EX_IOERR as u8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if u {
|
if u {
|
||||||
/* immediately flush the output for -u */
|
/* immediately flush the output for -u */
|
||||||
if let Err(e) = out.flush() {
|
if let Err(e) = out.flush() {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
return err(&argv[0], e, Some(EX_IOERR));
|
||||||
return ExitCode::from(EX_IOERR as u8);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <stdio.h> /* fprintf(3), fputs(3), getc(3), perror(3), putc(3), stdin,
|
#include <stdio.h> /* fprintf(3), fputs(3), getc(3), perror(3), putc(3), stdin,
|
||||||
* stdout, EOF */
|
* stdout, EOF */
|
||||||
#include <sysexits.h> /* EX_IOERR, EX_OK, EX_OSERR, EX_USAGE */
|
#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";
|
char *program_name = "npc";
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ int main(int argc, char *argv[]) {
|
|||||||
char showtab = 0; /* prints tab characters in caret notation */
|
char showtab = 0; /* prints tab characters in caret notation */
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
if (pledge("stdio", NULL) == -1) {
|
if (pledge("stdio unveil", "") == -1 || unveil(NULL, NULL)) {
|
||||||
perror(argv[0] == NULL ? program_name : argv[0]);
|
perror(argv[0] == NULL ? program_name : argv[0]);
|
||||||
return EX_OSERR;
|
return EX_OSERR;
|
||||||
}
|
}
|
||||||
|
179
src/rpn.rs
179
src/rpn.rs
@ -46,7 +46,7 @@ use std::{
|
|||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
env::args,
|
env::args,
|
||||||
fmt::{ self, Display, Formatter },
|
fmt::{ self, Display, Formatter },
|
||||||
io::stdin,
|
io::{ Error, Write, stdin, stdout },
|
||||||
process::ExitCode,
|
process::ExitCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,13 +54,13 @@ use CalcType::*;
|
|||||||
|
|
||||||
extern crate sysexits;
|
extern crate sysexits;
|
||||||
|
|
||||||
use sysexits::EX_DATAERR;
|
use sysexits::{ EX_DATAERR, EX_IOERR };
|
||||||
|
|
||||||
#[cfg(target_os="openbsd")] use sysexits::EX_OSERR;
|
#[cfg(target_os="openbsd")] use sysexits::EX_OSERR;
|
||||||
#[cfg(target_os="openbsd")] extern crate strerror;
|
#[cfg(target_os="openbsd")] extern crate strerror;
|
||||||
#[cfg(target_os="openbsd")] extern crate openbsd;
|
#[cfg(target_os="openbsd")] extern crate openbsd;
|
||||||
#[cfg(target_os="openbsd")] use strerror::StrError;
|
#[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)]
|
#[derive(Clone, PartialEq, PartialOrd, Debug)]
|
||||||
/* enum CalcType is a type containing operations used in the calculator */
|
/* enum CalcType is a type containing operations used in the calculator */
|
||||||
@ -120,12 +120,46 @@ impl Display for CalcType {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct EvaluationError {
|
struct EvaluationError {
|
||||||
message: String,
|
message: String,
|
||||||
code: i32,
|
code: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* I’m no math nerd but I want the highest possible approximation of 0.9
|
impl StrError for EvaluationError {
|
||||||
* repeating and it seems this can give it to me */
|
fn strerror(&self) -> String {
|
||||||
const PRECISION_MOD: f64 = 0.9 + f64::EPSILON * 100.0;
|
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(
|
fn eval(
|
||||||
input: &str,
|
input: &str,
|
||||||
@ -145,6 +179,7 @@ fn eval(
|
|||||||
.rev()
|
.rev()
|
||||||
.map(|t| CalcType::from(t))
|
.map(|t| CalcType::from(t))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut ops: VecDeque<CalcType> = VecDeque::new();
|
let mut ops: VecDeque<CalcType> = VecDeque::new();
|
||||||
|
|
||||||
while let Some(n) = toks.pop_back() {
|
while let Some(n) = toks.pop_back() {
|
||||||
@ -152,36 +187,15 @@ fn eval(
|
|||||||
Val(v) => stack.push_back(v),
|
Val(v) => stack.push_back(v),
|
||||||
Invalid(i) => {
|
Invalid(i) => {
|
||||||
return Err(EvaluationError {
|
return Err(EvaluationError {
|
||||||
message: format!("{}: Invalid token", i),
|
message: format!("{}: invalid token", i),
|
||||||
code: EX_DATAERR,
|
code: EX_DATAERR,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
op => {
|
op => {
|
||||||
ops.push_back(op.clone());
|
ops.push_back(op.clone());
|
||||||
oper = true;
|
|
||||||
|
|
||||||
let vals = (
|
oper = true; /* this is an operation */
|
||||||
stack.pop_back(),
|
return operate(stack, op).map(|s| (s, oper));
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -190,51 +204,46 @@ fn eval(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Round a float to the given precision level */
|
/* Round a float to the given precision level */
|
||||||
fn round_precise(value: &f64, precision: usize) -> f64 {
|
fn round_precise(value: &f64) -> f64 {
|
||||||
let multiplier = 10_f64.powi(precision as i32);
|
/* 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
|
(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 {
|
fn main() -> ExitCode {
|
||||||
let argv = args().collect::<Vec<String>>();
|
let argv = args().collect::<Vec<String>>();
|
||||||
|
|
||||||
#[cfg(target_os="openbsd")] {
|
#[cfg(target_os="openbsd")] {
|
||||||
let promises = Promises::new("stdio");
|
let promises = Promises::new("stdio unveil");
|
||||||
if let Err(e) = pledge(Some(promises), None) {
|
if let Err(e) = pledge(Some(promises), Some(Promises::default())) {
|
||||||
eprintln!("{}: {}", argv[0], e.strerror());
|
return err(&argv[0], &e, Some(EX_OSERR));
|
||||||
return ExitCode::from(EX_OSERR as u8);
|
}
|
||||||
|
|
||||||
|
if let Err(e) = unveil(None, None) {
|
||||||
|
return err(&argv[0], &e, Some(EX_OSERR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut stack = VecDeque::new();
|
let mut stack = VecDeque::new();
|
||||||
let mut buf = String::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 */
|
if argv.get(1).is_some() { /* read expressions from argv */
|
||||||
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 */
|
|
||||||
/* join argv into an owned String joined by spaces minus argv[0] */
|
/* join argv into an owned String joined by spaces minus argv[0] */
|
||||||
let input = argv
|
let input = argv
|
||||||
.iter()
|
.iter()
|
||||||
@ -245,20 +254,44 @@ fn main() -> ExitCode {
|
|||||||
|
|
||||||
match eval(&input, stack) {
|
match eval(&input, stack) {
|
||||||
Ok(s) => {
|
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() {
|
return ExitCode::SUCCESS;
|
||||||
Some(v) => v,
|
|
||||||
None => return ExitCode::SUCCESS,
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("{}", round_precise(val, precision).to_string())
|
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(e) => {
|
||||||
eprintln!("{}: {}", argv[0], err.message);
|
return err(&argv[0], &e, Some(e.code));
|
||||||
return ExitCode::from(err.code as u8);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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
|
ExitCode::SUCCESS
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ int main(int argc, char *argv[]) {
|
|||||||
program_name = argv[0] == NULL ? program_name : argv[0];
|
program_name = argv[0] == NULL ? program_name : argv[0];
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
if (pledge("rpath stdio unveil", NULL) == -1) {
|
if (pledge("rpath stdio unveil", "") == -1) {
|
||||||
perror(program_name);
|
perror(program_name);
|
||||||
return EX_OSERR;
|
return EX_OSERR;
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ int main(int argc, char *argv[]) {
|
|||||||
struct stat buf;
|
struct stat buf;
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
if (unveil(*argv, "r") == -1) {
|
if (unveil(*argv, "rw") == -1) {
|
||||||
perror(program_name);
|
perror(program_name);
|
||||||
return EX_OSERR;
|
return EX_OSERR;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include <sysexits.h> /* EX_OSERR, EX_USAGE */
|
#include <sysexits.h> /* EX_OSERR, EX_USAGE */
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
# include <unistd.h> /* pledge(2) */
|
# include <unistd.h> /* pledge(2), unveil(2) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *program_name = "str";
|
char *program_name = "str";
|
||||||
@ -62,7 +62,7 @@ int main(int argc, char *argv[]) {
|
|||||||
program_name = argv[0] == NULL ? program_name : argv[0];
|
program_name = argv[0] == NULL ? program_name : argv[0];
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
if (pledge("stdio", NULL) == -1) {
|
if (pledge("stdio unveil", "") == -1 || unveil(NULL, NULL) == -1) {
|
||||||
perror(program_name);
|
perror(program_name);
|
||||||
return EX_OSERR;
|
return EX_OSERR;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <sysexits.h> /* EX_OK, EX_OSERR, EX_USAGE */
|
#include <sysexits.h> /* EX_OK, EX_OSERR, EX_USAGE */
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
# include <unistd.h> /* pledge(2) */
|
# include <unistd.h> /* pledge(2), unveil(2) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *program_name = "strcmp";
|
char *program_name = "strcmp";
|
||||||
@ -29,7 +29,7 @@ int main(int argc, char *argv[]) {
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
if (pledge("stdio", NULL) == -1) {
|
if (pledge("stdio unveil", "") == -1 || unveil(NULL, NULL) == -1) {
|
||||||
perror(argv[0] == NULL ? program_name : argv[0]);
|
perror(argv[0] == NULL ? program_name : argv[0]);
|
||||||
|
|
||||||
return EX_OSERR;
|
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;
|
use strerror::StrError;
|
||||||
|
|
||||||
#[cfg(target_os="openbsd")] extern crate openbsd;
|
#[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 err(argv0: &String, e: Error, code: u8) -> ExitCode {
|
||||||
fn oserr(argv0: &str, e: Error) -> ExitCode {
|
|
||||||
eprintln!("{}: {}", argv0, e.strerror());
|
eprintln!("{}: {}", argv0, e.strerror());
|
||||||
ExitCode::from(EX_OSERR as u8)
|
ExitCode::from(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioerr(argv0: &str, e: Error) -> ExitCode {
|
fn usage(s: &String) -> ExitCode {
|
||||||
eprintln!("{}: {}", argv0, e.strerror());
|
|
||||||
ExitCode::from(EX_IOERR as u8)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(s: &str) -> ExitCode {
|
|
||||||
eprintln!("Usage: {} [-w word_size]", s);
|
eprintln!("Usage: {} [-w word_size]", s);
|
||||||
ExitCode::from(EX_USAGE as u8)
|
ExitCode::from(EX_USAGE)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let argv = args().collect::<Vec<String>>();
|
let argv = args().collect::<Vec<String>>();
|
||||||
|
|
||||||
#[cfg(target_os="openbsd")] {
|
#[cfg(target_os="openbsd")] {
|
||||||
let promises = Promises::new("stdio");
|
let promises = Promises::new("stdio unveil");
|
||||||
if let Err(e) = pledge(Some(promises), None) {
|
if let Err(e) = pledge(Some(promises), Some(Promises::default())) {
|
||||||
return oserr(&argv[0], e);
|
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 {
|
loop {
|
||||||
match input.read(&mut buf) {
|
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
|
Ok(v) if v == wordsize => { // read full block; swab
|
||||||
let (left, right) = buf.split_at(v/2);
|
let (left, right) = buf.split_at(v/2);
|
||||||
|
|
||||||
if let Err(e) = output.write(&right)
|
if let Err(e) = output.write(&right)
|
||||||
.and_then(|_| output.write(&left)) {
|
.and_then(|_| output.write(&left)) {
|
||||||
break ioerr(&argv[0], e);
|
break err(&argv[0], e, EX_IOERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
Ok(v) => { // partial read; partially write
|
Ok(v) => { // partial read; partially write
|
||||||
if let Err(e) = output.write(&buf[..v]) {
|
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) {
|
int main(void) {
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
pledge(NULL, NULL);
|
(void)pledge("stdio", "");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ fop_fail: $(BIN)/fop
|
|||||||
! printf 'test\n' | $(BIN)/fop 1 cat
|
! printf 'test\n' | $(BIN)/fop 1 cat
|
||||||
! printf 'test\n' | $(BIN)/fop 'test' cat
|
! printf 'test\n' | $(BIN)/fop 'test' cat
|
||||||
! printf 'test\n' | $(BIN)/fop -d'test' cat
|
! printf 'test\n' | $(BIN)/fop -d'test' cat
|
||||||
|
! $(BIN)/fop
|
||||||
|
|
||||||
.PHONY: fop_functionality
|
.PHONY: fop_functionality
|
||||||
fop_functionality: $(BIN)/fop
|
fop_functionality: $(BIN)/fop
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# notice are preserved. This file is offered as-is, without any warranty.
|
# notice are preserved. This file is offered as-is, without any warranty.
|
||||||
|
|
||||||
.PHONY: mm_tests
|
.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
|
.PHONY: mm_none
|
||||||
mm_none: $(BIN)/mm
|
mm_none: $(BIN)/mm
|
||||||
@ -32,3 +32,9 @@ mm_remaining: $(BIN)/mm
|
|||||||
test "$$($(BIN)/mm -i README COPYING)" = "$$(cat README COPYING)"
|
test "$$($(BIN)/mm -i README COPYING)" = "$$(cat README COPYING)"
|
||||||
$(BIN)/mm -i README -o /tmp/mm_test0 /tmp/mm_test1
|
$(BIN)/mm -i README -o /tmp/mm_test0 /tmp/mm_test1
|
||||||
diff /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.
|
# notice are preserved. This file is offered as-is, without any warranty.
|
||||||
|
|
||||||
.PHONY: rpn_tests
|
.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
|
.PHONY: rpn_help
|
||||||
rpn_help: $(BIN)/rpn
|
rpn_help: $(BIN)/rpn
|
||||||
@ -41,3 +41,8 @@ rpn_mod: $(BIN)/rpn
|
|||||||
rpn_flr: $(BIN)/rpn
|
rpn_flr: $(BIN)/rpn
|
||||||
test "$$($(BIN)/rpn 12 5 //)" -eq 2
|
test "$$($(BIN)/rpn 12 5 //)" -eq 2
|
||||||
test "$$($(BIN)/rpn 9 4 //)" -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…
Reference in New Issue
Block a user