Merge pull request #369 from Arcterus/busybox-fixes

Fix more bugs to pass Busybox tests
This commit is contained in:
Heather 2014-07-25 11:38:02 +04:00
commit 5b1eee0e98
10 changed files with 283 additions and 114 deletions

2
.busybox-config Normal file
View file

@ -0,0 +1,2 @@
CONFIG_FEATURE_FANCY_HEAD=y
CONFIG_UNICODE_SUPPORT=y

View file

@ -268,9 +268,8 @@ $(BUILDDIR)/busybox: $(BUILDDIR)/uutils
ln -s $(BUILDDIR)/uutils $(BUILDDIR)/busybox ln -s $(BUILDDIR)/uutils $(BUILDDIR)/busybox
# This is a busybox-specific config file their test suite wants to parse. # This is a busybox-specific config file their test suite wants to parse.
# For now it's blank. $(BUILDDIR)/.config: $(BASEDIR)/.busybox-config $(BUILDDIR)/uutils
$(BUILDDIR)/.config: $(BUILDDIR)/uutils cp $< $@
touch $@
ifeq ($(BUSYBOX_SRC),) ifeq ($(BUSYBOX_SRC),)
busytest: busytest:

View file

@ -14,42 +14,41 @@ extern crate libc;
#[macro_export] #[macro_export]
macro_rules! show_error( macro_rules! show_error(
($($args:expr),+) => ({ ($($args:expr),+) => ({
safe_write!(&mut ::std::io::stderr(), "{}: error: ", ::NAME); pipe_write!(&mut ::std::io::stderr(), "{}: error: ", ::NAME);
safe_writeln!(&mut ::std::io::stderr(), $($args),+); pipe_writeln!(&mut ::std::io::stderr(), $($args),+);
}) })
) )
#[macro_export] #[macro_export]
macro_rules! show_warning( macro_rules! show_warning(
($($args:expr),+) => ({ ($($args:expr),+) => ({
safe_write!(&mut ::std::io::stderr(), "{}: warning: ", ::NAME); pipe_write!(&mut ::std::io::stderr(), "{}: warning: ", ::NAME);
safe_writeln!(&mut ::std::io::stderr(), $($args),+); pipe_writeln!(&mut ::std::io::stderr(), $($args),+);
}) })
) )
#[macro_export] #[macro_export]
macro_rules! show_info( macro_rules! show_info(
($($args:expr),+) => ({ ($($args:expr),+) => ({
safe_write!(&mut ::std::io::stderr(), "{}: ", ::NAME); pipe_write!(&mut ::std::io::stderr(), "{}: ", ::NAME);
safe_writeln!(&mut ::std::io::stderr(), $($args),+); pipe_writeln!(&mut ::std::io::stderr(), $($args),+);
}) })
) )
#[macro_export] #[macro_export]
macro_rules! eprint( macro_rules! eprint(
($($args:expr),+) => (safe_write!(&mut ::std::io::stderr(), $($args),+)) ($($args:expr),+) => (pipe_write!(&mut ::std::io::stderr(), $($args),+))
) )
#[macro_export] #[macro_export]
macro_rules! eprintln( macro_rules! eprintln(
($($args:expr),+) => (safe_writeln!(&mut ::std::io::stderr(), $($args),+)) ($($args:expr),+) => (pipe_writeln!(&mut ::std::io::stderr(), $($args),+))
) )
#[macro_export] #[macro_export]
macro_rules! crash( macro_rules! crash(
($exitcode:expr, $($args:expr),+) => ({ ($exitcode:expr, $($args:expr),+) => ({
safe_write!(&mut ::std::io::stderr(), "{}: error: ", ::NAME); show_error!($($args),+);
safe_writeln!(&mut ::std::io::stderr(), $($args),+);
unsafe { ::util::libc::exit($exitcode as ::util::libc::c_int); } unsafe { ::util::libc::exit($exitcode as ::util::libc::c_int); }
}) })
) )
@ -84,12 +83,78 @@ macro_rules! return_if_err(
) )
) )
// XXX: should the pipe_* macros return an Err just to show the write failed?
#[macro_export]
macro_rules! pipe_print(
($($args:expr),+) => (
match write!(&mut ::std::io::stdout() as &mut Writer, $($args),+) {
Ok(_) => true,
Err(f) => {
if f.kind == ::std::io::BrokenPipe {
false
} else {
fail!("{}", f)
}
}
}
)
)
#[macro_export]
macro_rules! pipe_println(
($($args:expr),+) => (
match writeln!(&mut ::std::io::stdout() as &mut Writer, $($args),+) {
Ok(_) => true,
Err(f) => {
if f.kind == ::std::io::BrokenPipe {
false
} else {
fail!("{}", f)
}
}
}
)
)
#[macro_export]
macro_rules! pipe_write(
($fd:expr, $($args:expr),+) => (
match write!($fd, $($args),+) {
Ok(_) => true,
Err(f) => {
if f.kind == ::std::io::BrokenPipe {
false
} else {
fail!("{}", f)
}
}
}
)
)
#[macro_export]
macro_rules! pipe_writeln(
($fd:expr, $($args:expr),+) => (
match write!($fd, $($args),+) {
Ok(_) => true,
Err(f) => {
if f.kind == ::std::io::BrokenPipe {
false
} else {
fail!("{}", f)
}
}
}
)
)
#[macro_export] #[macro_export]
macro_rules! safe_write( macro_rules! safe_write(
($fd:expr, $($args:expr),+) => ( ($fd:expr, $($args:expr),+) => (
match write!($fd, $($args),+) { match write!($fd, $($args),+) {
Ok(_) => {} Ok(_) => {}
Err(f) => { fail!(f.to_string()); } Err(f) => fail!(f.to_string())
} }
) )
) )
@ -99,7 +164,7 @@ macro_rules! safe_writeln(
($fd:expr, $($args:expr),+) => ( ($fd:expr, $($args:expr),+) => (
match writeln!($fd, $($args),+) { match writeln!($fd, $($args),+) {
Ok(_) => {} Ok(_) => {}
Err(f) => { fail!(f.to_string()); } Err(f) => fail!(f.to_string())
} }
) )
) )

View file

@ -26,7 +26,6 @@ static NAME: &'static str = "fold";
static VERSION: &'static str = "1.0.0"; static VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> int { pub fn uumain(args: Vec<String>) -> int {
let (args, obs_width) = handle_obsolete(args.as_slice()); let (args, obs_width) = handle_obsolete(args.as_slice());
let program = args[0].clone(); let program = args[0].clone();
@ -98,11 +97,15 @@ fn handle_obsolete(args: &[String]) -> (Vec<String>, Option<String>) {
fn fold(filenames: Vec<String>, bytes: bool, spaces: bool, width: uint) { fn fold(filenames: Vec<String>, bytes: bool, spaces: bool, width: uint) {
for filename in filenames.iter() { for filename in filenames.iter() {
let filename: &str = filename.as_slice(); let filename: &str = filename.as_slice();
let mut stdin_buf;
let mut file_buf;
let buffer = BufferedReader::new( let buffer = BufferedReader::new(
if filename == "-" { if filename == "-" {
box io::stdio::stdin_raw() as Box<Reader> stdin_buf = io::stdio::stdin_raw();
&mut stdin_buf as &mut Reader
} else { } else {
box safe_unwrap!(File::open(&Path::new(filename))) as Box<Reader> file_buf = safe_unwrap!(File::open(&Path::new(filename)));
&mut file_buf as &mut Reader
} }
); );
fold_file(buffer, bytes, spaces, width); fold_file(buffer, bytes, spaces, width);
@ -112,19 +115,24 @@ fn fold(filenames: Vec<String>, bytes: bool, spaces: bool, width: uint) {
fn fold_file<T: io::Reader>(file: BufferedReader<T>, bytes: bool, spaces: bool, width: uint) { fn fold_file<T: io::Reader>(file: BufferedReader<T>, bytes: bool, spaces: bool, width: uint) {
let mut file = file; let mut file = file;
for line in file.lines() { for line in file.lines() {
let line = safe_unwrap!(line); let line_string = safe_unwrap!(line);
if line.len() == 1 { let mut line = line_string.as_slice();
println!(""); let len = line.len();
continue; if line.char_at(len - 1) == '\n' {
if len == 1 {
println!("");
continue;
} else {
line = line.slice_to(len - 1);
}
} }
let line = line.as_slice().slice_to(line.len() - 1);
if bytes { if bytes {
let mut i = 0; let mut i = 0;
while i < line.len() { while i < line.len() {
let width = if line.len() - i >= width { width } else { line.len() - i }; let width = if line.len() - i >= width { width } else { line.len() - i };
let slice = { let slice = {
let slice = line.slice(i, i + width); let slice = line.slice(i, i + width);
if spaces && i + width != line.len() { if spaces && i + width < line.len() {
match slice.rfind(|ch: char| ch.is_whitespace()) { match slice.rfind(|ch: char| ch.is_whitespace()) {
Some(m) => slice.slice_to(m + 1), Some(m) => slice.slice_to(m + 1),
None => slice None => slice
@ -140,11 +148,40 @@ fn fold_file<T: io::Reader>(file: BufferedReader<T>, bytes: bool, spaces: bool,
let mut output = String::new(); let mut output = String::new();
let mut count = 0; let mut count = 0;
for (i, ch) in line.chars().enumerate() { for (i, ch) in line.chars().enumerate() {
if count >= width {
let (val, ncount) = {
let slice = output.as_slice();
let (out, val, ncount) =
if spaces && i + 1 < line.len() {
match slice.rfind(|ch: char| ch.is_whitespace()) {
Some(m) => {
let routput = slice.slice_from(m + 1).to_string();
let ncount = routput.as_slice().chars().fold(0u, |out, ch: char| {
out + match ch {
'\t' => 8,
'\x08' => if out > 0 { -1 } else { 0 },
'\r' => return 0,
_ => 1
}
});
(slice.slice_to(m + 1), routput, ncount)
},
None => (slice, "".to_string(), 0)
}
} else {
(slice, "".to_string(), 0)
};
println!("{}", out);
(val, ncount)
};
output = val.into_string();
count = ncount;
}
match ch { match ch {
'\t' => { '\t' => {
count += 8; count += 8;
if count > width { if count > width {
println!("{}", output.as_slice()); println!("{}", output);
output.truncate(0); output.truncate(0);
count = 8; count = 8;
} }
@ -165,31 +202,9 @@ fn fold_file<T: io::Reader>(file: BufferedReader<T>, bytes: bool, spaces: bool,
_ => count += 1 _ => count += 1
}; };
output.push_char(ch); output.push_char(ch);
if count == width {
let (val, ncount) = {
let slice = output.as_slice();
let (out, val, ncount) =
if spaces && i + 1 != line.len() {
match slice.rfind(|ch: char| ch.is_whitespace()) {
Some(m) => {
let routput = slice.slice_from(m + 1).to_string();
let ncount = routput.as_slice().chars().fold(0, |out, ch: char| out + if ch == '\t' { 8 } else { 1 });
(slice.slice_to(m + 1), routput, ncount)
},
None => (slice, "".to_string(), 0)
}
} else {
(slice, "".to_string(), 0)
};
println!("{}", out);
(val, ncount)
};
output = val.into_string();
count = ncount;
}
} }
if count > 0 { if count > 0 {
println!("{}", output); print!("{}", output);
} }
} }
} }

View file

@ -151,20 +151,20 @@ pub fn uumain(args: Vec<String>) -> int {
} }
fn version() { fn version() {
println!("{} v{}", NAME, VERSION); pipe_println!("{} v{}", NAME, VERSION);
} }
fn usage(program: &str, binary_name: &str, opts: &[getopts::OptGroup]) { fn usage(program: &str, binary_name: &str, opts: &[getopts::OptGroup]) {
version(); version();
println!(""); pipe_println!("");
println!("Usage:"); pipe_println!("Usage:");
if is_custom_binary(binary_name) { if is_custom_binary(binary_name) {
println!(" {} [OPTION]... [FILE]...", program); pipe_println!(" {} [OPTION]... [FILE]...", program);
} else { } else {
println!(" {} {{--md5|--sha1|--sha224|--sha256|--sha384|--sha512}} [OPTION]... [FILE]...", program); pipe_println!(" {} {{--md5|--sha1|--sha224|--sha256|--sha384|--sha512}} [OPTION]... [FILE]...", program);
} }
println!(""); pipe_println!("");
print!("{}", getopts::usage("Compute and check message digests.", opts)); pipe_print!("{}", getopts::usage("Compute and check message digests.", opts));
} }
fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), int> { fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), int> {
@ -177,15 +177,18 @@ fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary:
}; };
for filename in files.iter() { for filename in files.iter() {
let filename: &str = filename.as_slice(); let filename: &str = filename.as_slice();
let mut stdin_buf;
let mut file_buf;
let mut file = BufferedReader::new( let mut file = BufferedReader::new(
if filename == "-" { if filename == "-" {
box stdin_raw() as Box<Reader> stdin_buf = stdin_raw();
&mut stdin_buf as &mut Reader
} else { } else {
box safe_unwrap!(File::open(&Path::new(filename))) as Box<Reader> file_buf = safe_unwrap!(File::open(&Path::new(filename)));
&mut file_buf as &mut Reader
} }
); );
if check { if check {
// Set up Regexes for line validation and parsing // Set up Regexes for line validation and parsing
let bytes = digest.output_bits() / 4; let bytes = digest.output_bits() / 4;
let gnu_re = safe_unwrap!( let gnu_re = safe_unwrap!(
@ -229,11 +232,11 @@ fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary:
.as_slice().to_ascii().to_lower(); .as_slice().to_ascii().to_lower();
if sum.as_slice() == real_sum.as_slice() { if sum.as_slice() == real_sum.as_slice() {
if !quiet { if !quiet {
println!("{}: OK", ck_filename); pipe_println!("{}: OK", ck_filename);
} }
} else { } else {
if !status { if !status {
println!("{}: FAILED", ck_filename); pipe_println!("{}: FAILED", ck_filename);
} }
failed += 1; failed += 1;
} }
@ -241,9 +244,9 @@ fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary:
} else { } else {
let sum = safe_unwrap!(digest_reader(&mut digest, &mut file, binary)); let sum = safe_unwrap!(digest_reader(&mut digest, &mut file, binary));
if tag { if tag {
println!("{} ({}) = {}", algoname, filename, sum); pipe_println!("{} ({}) = {}", algoname, filename, sum);
} else { } else {
println!("{} {}{}", sum, binary_marker, filename); pipe_println!("{} {}{}", sum, binary_marker, filename);
} }
} }
} }

View file

@ -10,6 +10,8 @@
* Synced with: https://raw.github.com/avsm/src/master/usr.bin/head/head.c * Synced with: https://raw.github.com/avsm/src/master/usr.bin/head/head.c
*/ */
#![feature(macro_rules)]
extern crate getopts; extern crate getopts;
use std::char; use std::char;
@ -20,10 +22,14 @@ use std::path::Path;
use std::str::from_utf8; use std::str::from_utf8;
use getopts::{optopt, optflag, getopts, usage}; use getopts::{optopt, optflag, getopts, usage};
static PROGRAM: &'static str = "head"; #[path = "../common/util.rs"]
mod util;
static NAME: &'static str = "head";
pub fn uumain(args: Vec<String>) -> int { pub fn uumain(args: Vec<String>) -> int {
let mut line_count = 10u; let mut line_count = 10u;
let mut byte_count = 0u;
// handle obsolete -number syntax // handle obsolete -number syntax
let options = match obsolete(args.tail()) { let options = match obsolete(args.tail()) {
@ -34,7 +40,8 @@ pub fn uumain(args: Vec<String>) -> int {
let args = options; let args = options;
let possible_options = [ let possible_options = [
optopt("n", "number", "Number of lines to print", "n"), optopt("c", "bytes", "Print the first K bytes. With the leading '-', print all but the last K bytes", "[-]K"),
optopt("n", "lines", "Print the first K lines. With the leading '-', print all but the last K lines", "[-]K"),
optflag("h", "help", "help"), optflag("h", "help", "help"),
optflag("V", "version", "version") optflag("V", "version", "version")
]; ];
@ -42,32 +49,58 @@ pub fn uumain(args: Vec<String>) -> int {
let given_options = match getopts(args.as_slice(), possible_options) { let given_options = match getopts(args.as_slice(), possible_options) {
Ok (m) => { m } Ok (m) => { m }
Err(_) => { Err(_) => {
println!("{:s}", usage(PROGRAM, possible_options)); println!("{:s}", usage(NAME, possible_options));
return 1; return 1;
} }
}; };
if given_options.opt_present("h") { if given_options.opt_present("h") {
println!("{:s}", usage(PROGRAM, possible_options)); println!("{:s}", usage(NAME, possible_options));
return 0; return 0;
} }
if given_options.opt_present("V") { version(); return 0 } if given_options.opt_present("V") { version(); return 0 }
let use_bytes = given_options.opt_present("c");
// TODO: suffixes (e.g. b, kB, etc.)
match given_options.opt_str("n") { match given_options.opt_str("n") {
Some(n) => { Some(n) => {
if use_bytes {
show_error!("cannot specify both --bytes and --lines.");
return 1;
}
match from_str(n.as_slice()) { match from_str(n.as_slice()) {
Some(m) => { line_count = m } Some(m) => { line_count = m }
None => {} None => {
show_error!("invalid line count '{}'", n);
return 1;
}
} }
} }
None => {} None => match given_options.opt_str("c") {
Some(count) => match from_str(count.as_slice()) {
Some(m) => byte_count = m,
None => {
show_error!("invalid byte count '{}'", count);
return 1;
}
},
None => {}
}
}; };
let files = given_options.free; let files = given_options.free;
let count =
if use_bytes {
byte_count
} else {
line_count
};
if files.is_empty() { if files.is_empty() {
let mut buffer = BufferedReader::new(stdin()); let mut buffer = BufferedReader::new(stdin());
head(&mut buffer, line_count); head(&mut buffer, count, use_bytes);
} else { } else {
let mut multiple = false; let mut multiple = false;
let mut firstime = true; let mut firstime = true;
@ -76,18 +109,19 @@ pub fn uumain(args: Vec<String>) -> int {
multiple = true; multiple = true;
} }
for file in files.iter() { for file in files.iter() {
if multiple { if multiple {
if !firstime { println!(""); } if !firstime { pipe_println!(""); }
println!("==> {:s} <==", file.as_slice()); pipe_println!("==> {:s} <==", file.as_slice());
} }
firstime = false; firstime = false;
let path = Path::new(file.as_slice()); let path = Path::new(file.as_slice());
let reader = File::open(&path).unwrap(); let reader = File::open(&path).unwrap();
let mut buffer = BufferedReader::new(reader); let mut buffer = BufferedReader::new(reader);
head(&mut buffer, line_count); if !head(&mut buffer, count, use_bytes) {
break;
}
} }
} }
@ -98,7 +132,7 @@ pub fn uumain(args: Vec<String>) -> int {
// //
// In case is found, the options vector will get rid of that object so that // In case is found, the options vector will get rid of that object so that
// getopts works correctly. // getopts works correctly.
fn obsolete (options: &[String]) -> (Vec<String>, Option<uint>) { fn obsolete(options: &[String]) -> (Vec<String>, Option<uint>) {
let mut options: Vec<String> = Vec::from_slice(options); let mut options: Vec<String> = Vec::from_slice(options);
let mut a = 0; let mut a = 0;
let b = options.len(); let b = options.len();
@ -116,7 +150,7 @@ fn obsolete (options: &[String]) -> (Vec<String>, Option<uint>) {
// If this is the last number // If this is the last number
if pos == len - 1 { if pos == len - 1 {
options.remove(a); options.remove(a);
let number : Option<uint> = from_str(from_utf8(current.slice(1,len)).unwrap()); let number: Option<uint> = from_str(from_utf8(current.slice(1,len)).unwrap());
return (options, Some(number.unwrap())); return (options, Some(number.unwrap()));
} }
} }
@ -128,10 +162,24 @@ fn obsolete (options: &[String]) -> (Vec<String>, Option<uint>) {
(options, None) (options, None)
} }
fn head<T: Reader> (reader: &mut BufferedReader<T>, line_count:uint) { // TODO: handle errors on read
for line in reader.lines().take(line_count) { print!("{}", line.unwrap()); } fn head<T: Reader>(reader: &mut BufferedReader<T>, count: uint, use_bytes: bool) -> bool {
if use_bytes {
for byte in reader.bytes().take(count) {
if !pipe_print!("{}", byte.unwrap() as char) {
return false;
}
}
} else {
for line in reader.lines().take(count) {
if !pipe_print!("{}", line.unwrap()) {
return false;
}
}
}
true
} }
fn version () { fn version() {
println!("head version 1.0.0"); println!("head version 1.0.0");
} }

View file

@ -12,12 +12,21 @@
* https://www.opensource.apple.com/source/shell_cmds/shell_cmds-170/hostname/hostname.c?txt * https://www.opensource.apple.com/source/shell_cmds/shell_cmds-170/hostname/hostname.c?txt
*/ */
#![feature(macro_rules)]
extern crate getopts; extern crate getopts;
extern crate libc; extern crate libc;
use std::collections::hashmap::HashSet;
use std::io::net::addrinfo;
use std::str; use std::str;
use getopts::{optflag, getopts, usage}; use getopts::{optflag, getopts, usage};
#[path = "../common/util.rs"]
mod util;
static NAME: &'static str = "hostname";
extern { extern {
fn gethostname(name: *mut libc::c_char, namelen: libc::size_t) -> libc::c_int; fn gethostname(name: *mut libc::c_char, namelen: libc::size_t) -> libc::c_int;
} }
@ -36,8 +45,10 @@ pub fn uumain(args: Vec<String>) -> int {
let program = &args[0]; let program = &args[0];
let options = [ let options = [
optflag("f", "full", "Default option to show full name"), optflag("d", "domain", "Display the name of the DNS domain if possible"),
optflag("s", "slice subdomain", "Cuts the subdomain off if any"), optflag("i", "ip-address", "Display the network address(es) of the host"),
optflag("f", "fqdn", "Display the FQDN (Fully Qualified Domain Name) (default)"), // TODO: support --long
optflag("s", "short", "Display the short hostname (the portion before the first dot) if possible"),
optflag("h", "help", "Show help"), optflag("h", "help", "Show help"),
optflag("V", "version", "Show program's version") optflag("V", "version", "Show program's version")
]; ];
@ -57,18 +68,49 @@ pub fn uumain(args: Vec<String>) -> int {
0 => { 0 => {
let hostname = xgethostname(); let hostname = xgethostname();
if matches.opt_present("s") { if matches.opt_present("i") {
let pos = hostname.as_slice().find_str("."); match addrinfo::get_host_addresses(hostname.as_slice()) {
if pos.is_some() { Ok(addresses) => {
println!("{:s}", hostname.as_slice().slice_to(pos.unwrap())); let mut hashset = HashSet::new();
return 0; let mut output = String::new();
for addr in addresses.iter() {
// XXX: not sure why this is necessary...
if !hashset.contains(addr) {
output.push_str(addr.to_string().as_slice());
output.push_str(" ");
hashset.insert(addr.clone());
}
}
let len = output.len();
if len > 0 {
println!("{}", output.as_slice().slice_to(len - 1));
}
}
Err(f) => {
show_error!("{}", f);
return 1;
}
}
} else {
if matches.opt_present("s") {
let pos = hostname.as_slice().find_str(".");
if pos.is_some() {
println!("{:s}", hostname.as_slice().slice_to(pos.unwrap()));
return 0;
}
} else if matches.opt_present("d") {
let pos = hostname.as_slice().find_str(".");
if pos.is_some() {
println!("{}", hostname.as_slice().slice_from(pos.unwrap() + 1));
return 0;
}
} }
}
println!("{:s}", hostname.as_slice()); println!("{:s}", hostname);
}
} }
1 => { xsethostname( matches.free.last().unwrap().as_slice() ) } 1 => xsethostname(matches.free.last().unwrap().as_slice()),
_ => { help_menu(program.as_slice(), options); } _ => help_menu(program.as_slice(), options)
}; };
0 0

View file

@ -9,27 +9,12 @@ extern crate getopts;
extern crate libc; extern crate libc;
use std::cmp; use std::cmp;
use std::io;
#[path = "../common/util.rs"] #[path = "../common/util.rs"]
mod util; mod util;
static NAME: &'static str = "seq"; static NAME: &'static str = "seq";
macro_rules! pipe_write(
($($args:expr),+) => (
match write!(&mut io::stdout() as &mut Writer, $($args),+) {
Ok(_) => {}
Err(f) =>
if f.kind == io::BrokenPipe {
return
} else {
fail!("{}", f.to_string())
}
}
)
)
#[deriving(Clone)] #[deriving(Clone)]
struct SeqOptions { struct SeqOptions {
separator: String, separator: String,
@ -237,27 +222,35 @@ fn print_seq(first: f64, step: f64, last: f64, largest_dec: uint, separator: Str
let before_dec = istr.as_slice().find('.').unwrap_or(ilen); let before_dec = istr.as_slice().find('.').unwrap_or(ilen);
if pad && before_dec < padding { if pad && before_dec < padding {
for _ in range(0, padding - before_dec) { for _ in range(0, padding - before_dec) {
pipe_write!("0"); if !pipe_print!("0") {
return;
}
} }
} }
pipe_write!("{}", istr); pipe_print!("{}", istr);
let mut idec = ilen - before_dec; let mut idec = ilen - before_dec;
if idec < largest_dec { if idec < largest_dec {
if idec == 0 { if idec == 0 {
pipe_write!("."); if !pipe_print!(".") {
return;
}
idec += 1; idec += 1;
} }
for _ in range(idec, largest_dec) { for _ in range(idec, largest_dec) {
pipe_write!("0") if !pipe_print!("0") {
return;
}
} }
} }
i += 1; i += 1;
value = first + i as f64 * step; value = first + i as f64 * step;
if !done_printing(value, step, last) { if !done_printing(value, step, last) {
pipe_write!("{:s}", separator); if !pipe_print!("{:s}", separator) {
return;
}
} }
} }
if (first >= last && step < 0f64) || (first <= last && step > 0f64) { if (first >= last && step < 0f64) || (first <= last && step > 0f64) {
pipe_write!("{:s}", terminator); pipe_print!("{:s}", terminator);
} }
} }

View file

@ -54,8 +54,8 @@ fn main() {
None => (), None => (),
} }
if binary_as_util.ends_with("uutils") if binary_as_util.ends_with("uutils") || binary_as_util.starts_with("uutils") ||
|| binary_as_util.ends_with("busybox") { binary_as_util.ends_with("busybox") || binary_as_util.starts_with("busybox") {
// uutils can be called as either "uutils", "busybox" // uutils can be called as either "uutils", "busybox"
// "uutils-suffix" or "busybox-suffix". Not sure // "uutils-suffix" or "busybox-suffix". Not sure
// what busybox uses the -suffix pattern for. // what busybox uses the -suffix pattern for.

View file

@ -16,7 +16,7 @@
extern crate getopts; extern crate getopts;
extern crate libc; extern crate libc;
use std::io::{print, println}; use std::io::print;
#[path = "../common/util.rs"] #[path = "../common/util.rs"]
mod util; mod util;
@ -60,6 +60,8 @@ pub fn uumain(args: Vec<String>) -> int {
pub fn exec(string: &str) { pub fn exec(string: &str) {
loop { loop {
println(string); if !pipe_println!("{}", string) {
break;
}
} }
} }