mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
+17
-1
@@ -62,7 +62,23 @@ macro_rules! crash_if_err(
|
||||
($exitcode:expr, $exp:expr) => (
|
||||
match $exp {
|
||||
Ok(m) => m,
|
||||
Err(f) => crash!($exitcode, "{}", f.to_string())
|
||||
Err(f) => crash!($exitcode, "{}", f),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! pipe_crash_if_err(
|
||||
($exitcode:expr, $exp:expr) => (
|
||||
match $exp {
|
||||
Ok(_) => (),
|
||||
Err(f) => {
|
||||
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
|
||||
()
|
||||
} else {
|
||||
crash!($exitcode, "{}", f)
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
+114
-105
@@ -1,142 +1,151 @@
|
||||
use std;
|
||||
use std::old_io::{IoResult, IoError};
|
||||
/*
|
||||
* This file is part of the uutils coreutils package.
|
||||
*
|
||||
* (c) Rolf Morel <rolfmorel@gmail.com>
|
||||
* (c) kwantam <kwantam@gmail.com>
|
||||
* substantially rewritten to use the stdlib BufReader trait
|
||||
* rather than re-implementing it here.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
pub struct BufReader<R> {
|
||||
reader: R,
|
||||
buffer: [u8; 4096],
|
||||
start: usize,
|
||||
end: usize, // exclusive
|
||||
}
|
||||
use std::io::{BufRead, BufReader, Read, Write};
|
||||
use std::io::Result as IoResult;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub mod Bytes {
|
||||
use std::io::Write;
|
||||
|
||||
pub trait Select {
|
||||
fn select<'a>(&'a mut self, bytes: usize) -> Selected<'a>;
|
||||
fn select<W: Write>(&mut self, bytes: usize, out: Option<&mut W>) -> Selected;
|
||||
}
|
||||
|
||||
pub enum Selected<'a> {
|
||||
NewlineFound(&'a [u8]),
|
||||
Complete(&'a [u8]),
|
||||
Partial(&'a [u8]),
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum Selected {
|
||||
NewlineFound,
|
||||
Complete(usize),
|
||||
Partial(usize),
|
||||
EndOfFile,
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> BufReader<R> {
|
||||
pub fn new(reader: R) -> BufReader<R> {
|
||||
let empty_buffer = unsafe {
|
||||
std::mem::uninitialized::<[u8; 4096]>()
|
||||
};
|
||||
#[derive(Debug)]
|
||||
pub struct ByteReader<R> where R: Read {
|
||||
inner: BufReader<R>,
|
||||
}
|
||||
|
||||
BufReader {
|
||||
reader: reader,
|
||||
buffer: empty_buffer,
|
||||
start: 0,
|
||||
end: 0,
|
||||
impl<R: Read> ByteReader<R> {
|
||||
pub fn new(read: R) -> ByteReader<R> {
|
||||
ByteReader {
|
||||
inner: BufReader::with_capacity(4096, read),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read(&mut self) -> IoResult<usize> {
|
||||
let buffer_fill = &mut self.buffer[self.end..];
|
||||
impl<R: Read> Read for ByteReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
|
||||
self.inner.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
match self.reader.read(buffer_fill) {
|
||||
Ok(nread) => {
|
||||
self.end += nread;
|
||||
Ok(nread)
|
||||
}
|
||||
error => error
|
||||
}
|
||||
impl<R: Read> BufRead for ByteReader<R> {
|
||||
fn fill_buf(&mut self) -> IoResult<&[u8]> {
|
||||
self.inner.fill_buf()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn maybe_fill_buf(&mut self) -> IoResult<usize> {
|
||||
if self.end == self.start {
|
||||
self.start = 0;
|
||||
self.end = 0;
|
||||
|
||||
self.read()
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
fn consume(&mut self, amt: usize) {
|
||||
self.inner.consume(amt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> ByteReader<R> {
|
||||
pub fn consume_line(&mut self) -> usize {
|
||||
let mut bytes_consumed = 0;
|
||||
let mut consume_val;
|
||||
|
||||
loop {
|
||||
match self.maybe_fill_buf() {
|
||||
Ok(0) | Err(IoError { kind: std::old_io::EndOfFile, .. })
|
||||
if self.start == self.end => return bytes_consumed,
|
||||
Err(err) => panic!("read error: {}", err.desc),
|
||||
_ => ()
|
||||
}
|
||||
{ // need filled_buf to go out of scope
|
||||
let filled_buf = match self.fill_buf() {
|
||||
Ok(b) => {
|
||||
if b.len() == 0 {
|
||||
return bytes_consumed
|
||||
} else {
|
||||
b
|
||||
}
|
||||
},
|
||||
Err(e) => crash!(1, "read error: {}", e),
|
||||
};
|
||||
|
||||
let filled_buf = &self.buffer[self.start..self.end];
|
||||
|
||||
match filled_buf.position_elem(&b'\n') {
|
||||
Some(idx) => {
|
||||
self.start += idx + 1;
|
||||
return bytes_consumed + idx + 1;
|
||||
match filled_buf.position_elem(&b'\n') {
|
||||
Some(idx) => {
|
||||
consume_val = idx + 1;
|
||||
bytes_consumed += consume_val;
|
||||
break;
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
_ => ()
|
||||
|
||||
consume_val = filled_buf.len();
|
||||
}
|
||||
|
||||
bytes_consumed += filled_buf.len();
|
||||
|
||||
self.start = 0;
|
||||
self.end = 0;
|
||||
bytes_consumed += consume_val;
|
||||
self.consume(consume_val);
|
||||
}
|
||||
|
||||
self.consume(consume_val);
|
||||
return bytes_consumed;
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> Bytes::Select for BufReader<R> {
|
||||
fn select<'a>(&'a mut self, bytes: usize) -> Bytes::Selected<'a> {
|
||||
match self.maybe_fill_buf() {
|
||||
Err(IoError { kind: std::old_io::EndOfFile, .. }) => (),
|
||||
Err(err) => panic!("read error: {}", err.desc),
|
||||
_ => ()
|
||||
}
|
||||
|
||||
let newline_idx = match self.end - self.start {
|
||||
0 => return Bytes::Selected::EndOfFile,
|
||||
buf_used if bytes < buf_used => {
|
||||
// because the output delimiter should only be placed between
|
||||
// segments check if the byte after bytes is a newline
|
||||
let buf_slice = &self.buffer[self.start..self.start + bytes + 1];
|
||||
|
||||
match buf_slice.position_elem(&b'\n') {
|
||||
Some(idx) => idx,
|
||||
None => {
|
||||
let segment = &self.buffer[self.start..self.start + bytes];
|
||||
|
||||
self.start += bytes;
|
||||
|
||||
return Bytes::Selected::Complete(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let buf_filled = &self.buffer[self.start..self.end];
|
||||
|
||||
match buf_filled.position_elem(&b'\n') {
|
||||
Some(idx) => idx,
|
||||
None => {
|
||||
let segment = &self.buffer[self.start..self.end];
|
||||
|
||||
self.start = 0;
|
||||
self.end = 0;
|
||||
|
||||
return Bytes::Selected::Partial(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<R: Read> self::Bytes::Select for ByteReader<R> {
|
||||
fn select<W: Write>(&mut self, bytes: usize, out: Option<&mut W>) -> Bytes::Selected {
|
||||
enum SRes {
|
||||
Comp,
|
||||
Part,
|
||||
Newl,
|
||||
};
|
||||
|
||||
let new_start = self.start + newline_idx + 1;
|
||||
let segment = &self.buffer[self.start..new_start];
|
||||
use self::Bytes::Selected::*;
|
||||
|
||||
self.start = new_start;
|
||||
Bytes::Selected::NewlineFound(segment)
|
||||
let (res, consume_val) = {
|
||||
let buffer = match self.fill_buf() {
|
||||
Err(e) => crash!(1, "read error: {}", e),
|
||||
Ok(b) => b,
|
||||
};
|
||||
|
||||
let (res, consume_val) = match buffer.len() {
|
||||
0 => return EndOfFile,
|
||||
buf_used if bytes < buf_used => {
|
||||
// because the output delimiter should only be placed between
|
||||
// segments check if the byte after bytes is a newline
|
||||
let buf_slice = &buffer[0..bytes + 1];
|
||||
|
||||
match buf_slice.position_elem(&b'\n') {
|
||||
Some(idx) => (SRes::Newl, idx+1),
|
||||
None => (SRes::Comp, bytes),
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
match buffer.position_elem(&b'\n') {
|
||||
Some(idx) => (SRes::Newl, idx+1),
|
||||
None => (SRes::Part, buffer.len()),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
match out {
|
||||
Some(out) => pipe_crash_if_err!(1, out.write_all(&buffer[0..consume_val])),
|
||||
None => (),
|
||||
}
|
||||
(res, consume_val)
|
||||
};
|
||||
|
||||
self.consume(consume_val);
|
||||
match res {
|
||||
SRes::Comp => Complete(consume_val),
|
||||
SRes::Part => Partial(consume_val),
|
||||
SRes::Newl => NewlineFound,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+146
-164
File diff suppressed because it is too large
Load Diff
+25
-15
@@ -7,7 +7,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use std;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(PartialEq,Eq,PartialOrd,Ord,Debug)]
|
||||
pub struct Range {
|
||||
@@ -15,42 +15,52 @@ pub struct Range {
|
||||
pub high: usize,
|
||||
}
|
||||
|
||||
impl std::str::FromStr for Range {
|
||||
impl FromStr for Range {
|
||||
type Err = &'static str;
|
||||
|
||||
fn from_str(s: &str) -> Result<Range, &'static str> {
|
||||
use std::usize::MAX;
|
||||
|
||||
let mut parts = s.splitn(1, '-');
|
||||
let mut parts = s.splitn(2, '-');
|
||||
|
||||
let field = "fields and positions are numbered from 1";
|
||||
let order = "high end of range less than low end";
|
||||
let inval = "failed to parse range";
|
||||
|
||||
match (parts.next(), parts.next()) {
|
||||
(Some(nm), None) => {
|
||||
if let Ok(nm) = nm.parse::<usize>() {
|
||||
if nm > 0 { Ok(Range{ low: nm, high: nm}) } else { Err("invalid range") }
|
||||
if nm > 0 { Ok(Range{ low: nm, high: nm}) } else { Err(field) }
|
||||
} else {
|
||||
Err("invalid range")
|
||||
Err(inval)
|
||||
}
|
||||
}
|
||||
(Some(n), Some(m)) if m.len() == 0 => {
|
||||
if let Ok(low) = n.parse::<usize>() {
|
||||
if low > 0 { Ok(Range{ low: low, high: MAX}) } else { Err("invalid range") }
|
||||
if low > 0 { Ok(Range{ low: low, high: MAX}) } else { Err(field) }
|
||||
} else {
|
||||
Err("invalid range")
|
||||
Err(inval)
|
||||
}
|
||||
}
|
||||
(Some(n), Some(m)) if n.len() == 0 => {
|
||||
if let Ok(high) = m.parse::<usize>() {
|
||||
if high > 0 { Ok(Range{ low: 1, high: high}) } else { Err("invalid range") }
|
||||
if high > 0 { Ok(Range{ low: 1, high: high}) } else { Err(field) }
|
||||
} else {
|
||||
Err("invalid range")
|
||||
Err(inval)
|
||||
}
|
||||
}
|
||||
(Some(n), Some(m)) => {
|
||||
match (n.parse::<usize>(), m.parse::<usize>()) {
|
||||
(Ok(low), Ok(high)) if low > 0 && low <= high => {
|
||||
Ok(Range { low: low, high: high })
|
||||
}
|
||||
_ => Err("invalid range")
|
||||
(Ok(low), Ok(high)) => {
|
||||
if low > 0 && low <= high {
|
||||
Ok(Range { low: low, high: high })
|
||||
} else if low == 0 {
|
||||
Err(field)
|
||||
} else {
|
||||
Err(order)
|
||||
}
|
||||
},
|
||||
_ => Err(inval),
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
@@ -65,7 +75,7 @@ impl Range {
|
||||
let mut ranges : Vec<Range> = vec!();
|
||||
|
||||
for item in list.split(',') {
|
||||
match std::str::FromStr::from_str(item) {
|
||||
match FromStr::from_str(item) {
|
||||
Ok(range_item) => ranges.push(range_item),
|
||||
Err(e)=> return Err(format!("range '{}' was invalid: {}", item, e))
|
||||
}
|
||||
@@ -74,7 +84,7 @@ impl Range {
|
||||
ranges.sort();
|
||||
|
||||
// merge overlapping ranges
|
||||
for i in range(0, ranges.len()) {
|
||||
for i in 0..ranges.len() {
|
||||
let j = i + 1;
|
||||
|
||||
while j < ranges.len() && ranges[j].low <= ranges[i].high {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of the uutils coreutils package.
|
||||
*
|
||||
* (c) Rolf Morel <rolfmorel@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Searcher<'a> {
|
||||
haystack: &'a [u8],
|
||||
needle: &'a [u8],
|
||||
position: usize
|
||||
}
|
||||
|
||||
impl<'a> Searcher<'a> {
|
||||
pub fn new(haystack: &'a [u8], needle: &'a [u8]) -> Searcher<'a> {
|
||||
Searcher {
|
||||
haystack: haystack,
|
||||
needle: needle,
|
||||
position: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Searcher<'a> {
|
||||
type Item = (usize, usize);
|
||||
|
||||
fn next(&mut self) -> Option<(usize, usize)> {
|
||||
if self.needle.len() == 1 {
|
||||
for offset in self.position..self.haystack.len() {
|
||||
if self.haystack[offset] == self.needle[0] {
|
||||
self.position = offset + 1;
|
||||
return Some((offset, offset + 1));
|
||||
}
|
||||
}
|
||||
|
||||
self.position = self.haystack.len();
|
||||
return None;
|
||||
}
|
||||
|
||||
while self.position + self.needle.len() <= self.haystack.len() {
|
||||
if &self.haystack[self.position..self.position + self.needle.len()] == self.needle {
|
||||
let match_pos = self.position;
|
||||
self.position += self.needle.len();
|
||||
return Some((match_pos, match_pos + self.needle.len()));
|
||||
} else {
|
||||
self.position += 1;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user