// spell-checker:ignore memmem//! Implementations of digest functions, like md5 and sha1.
@@ -435,13 +504,31 @@
/// "\n" before passing input bytes to the [`digest`].#[allow(dead_code)]binary: bool,
- // TODO This is dead code only on non-Windows operating systems. It
- // might be better to use a `#[cfg(windows)]` guard here.
+
+ /// Whether the previous
+ #[allow(dead_code)]
+ was_last_character_carriage_return: bool,
+ // TODO These are dead code only on non-Windows operating systems.
+ // It might be better to use a `#[cfg(windows)]` guard here.
}
impl<'a>DigestWriter<'a> {
pubfnnew(digest: &'amutBox<dynDigest>, binary: bool) ->DigestWriter {
- DigestWriter { digest, binary }
+ letwas_last_character_carriage_return=false;
+ DigestWriter {
+ digest,
+ binary,
+ was_last_character_carriage_return,
+ }
+ }
+
+ pubfnfinalize(&mutself) ->bool {
+ ifself.was_last_character_carriage_return {
+ self.digest.input(&[b'\r']);
+ true
+ } else {
+ false
+ }
}
}
@@ -459,22 +546,40 @@
returnOk(buf.len());
}
- // In Windows text mode, replace each occurrence of "\r\n"
- // with "\n".
+ // The remaining code handles Windows text mode, where we must
+ // replace each occurrence of "\r\n" with "\n".//
- // Find all occurrences of "\r\n", inputting the slice just
- // before the "\n" in the previous instance of "\r\n" and
- // the beginning of this "\r\n".
- //
- // FIXME This fails if one call to `write()` ends with the
- // "\r" and the next call to `write()` begins with the "\n".
+ // First, if the last character written was "\r" and the first
+ // character in the current buffer to write is not "\n", then we
+ // need to write the "\r" that we buffered from the previous
+ // call to `write()`.letn=buf.len();
+ ifself.was_last_character_carriage_return&&n>0&&buf[0] !=b'\n' {
+ self.digest.input(&[b'\r']);
+ }
+
+ // Next, find all occurrences of "\r\n", inputting the slice
+ // just before the "\n" in the previous instance of "\r\n" and
+ // the beginning of this "\r\n".letmuti_prev=0;
foriinmemmem::find_iter(buf, b"\r\n") {
self.digest.input(&buf[i_prev..i]);
i_prev=i+1;
}
- self.digest.input(&buf[i_prev..n]);
+
+ // Finally, check whether the last character is "\r". If so,
+ // buffer it until we know that the next character is not "\n",
+ // which can only be known on the next call to `write()`.
+ //
+ // This all assumes that `write()` will be called on adjacent
+ // blocks of the input.
+ ifn>0&&buf[n-1] ==b'\r' {
+ self.was_last_character_carriage_return=true;
+ self.digest.input(&buf[i_prev..n-1]);
+ } else {
+ self.was_last_character_carriage_return=false;
+ self.digest.input(&buf[i_prev..n]);
+ }
// Even though we dropped a "\r" for each "\r\n" we found, we// still report the number of bytes written as `n`. This is
@@ -489,6 +594,39 @@
Ok(())
}
}
+
+#[cfg(test)]
+modtests {
+
+ /// Test for replacing a "\r\n" sequence with "\n" when the "\r" is
+ /// at the end of one block and the "\n" is at the beginning of the
+ /// next block, when reading in blocks.
+ #[cfg(windows)]
+ #[test]
+ fntest_crlf_across_blocks() {
+ usestd::io::Write;
+
+ usecrate::digest::Digest;
+ usecrate::digest::DigestWriter;
+
+ // Writing "\r" in one call to `write()`, and then "\n" in another.
+ letmutdigest=Box::new(md5::Context::new()) asBox<dynDigest>;
+ letmutwriter_crlf=DigestWriter::new(&mutdigest, false);
+ writer_crlf.write_all(&[b'\r']).unwrap();
+ writer_crlf.write_all(&[b'\n']).unwrap();
+ writer_crlf.finalize();
+ letresult_crlf=digest.result_str();
+
+ // We expect "\r\n" to be replaced with "\n" in text mode on Windows.
+ letmutdigest=Box::new(md5::Context::new()) asBox<dynDigest>;
+ letmutwriter_lf=DigestWriter::new(&mutdigest, false);
+ writer_lf.write_all(&[b'\n']).unwrap();
+ writer_lf.finalize();
+ letresult_lf=digest.result_str();
+
+ assert_eq!(result_crlf, result_lf);
+ }
+}
// * This file is part of the uutils coreutils package.// *
@@ -1238,8 +1246,16 @@
// If `binary` is `false` and the operating system is Windows, then// `DigestWriter` replaces "\r\n" with "\n" before it writes the// bytes into `digest`. Otherwise, it just inserts the bytes as-is.
+ //
+ // In order to support replacing "\r\n", we must call `finalize()`
+ // in order to support the possibility that the last character read
+ // from the reader was "\r". (This character gets buffered by
+ // `DigestWriter` and only written if the following character is
+ // "\n". But when "\r" is the last character read, we need to force
+ // it to be written.)letmutdigest_writer=DigestWriter::new(digest, binary);
std::io::copy(reader, &mutdigest_writer)?;
+ digest_writer.finalize();
ifdigest.output_bits() >0 {
Ok(digest.result_str())
diff --git a/src/uu_head/head.rs.html b/src/uu_head/head.rs.html
index 31d680eb1..f660693dd 100644
--- a/src/uu_head/head.rs.html
+++ b/src/uu_head/head.rs.html
@@ -589,7 +589,6 @@
589590591
-592
// * This file is part of the uutils coreutils package.// *
@@ -612,7 +611,6 @@
constABOUT: &str="\
Print the first 10 lines of each FILE to standard output.\n\
With more than one FILE, precede each with a header giving the file name.\n\
- \n\
With no FILE, or when FILE is -, read standard input.\n\
\n\
Mandatory arguments to long flags are mandatory for short flags too.\
diff --git a/src/uu_tail/tail.rs.html b/src/uu_tail/tail.rs.html
index 873ef4599..639a6decd 100644
--- a/src/uu_tail/tail.rs.html
+++ b/src/uu_tail/tail.rs.html
@@ -480,6 +480,15 @@
480481482
+483
+484
+485
+486
+487
+488
+489
+490
+491
// * This file is part of the uutils coreutils package.// *
@@ -518,6 +527,15 @@
#[cfg(unix)]usestd::os::unix::fs::MetadataExt;
+constABOUT: &str="\
+ Print the last 10 lines of each FILE to standard output.\n\
+ With more than one FILE, precede each with a header giving the file name.\n\
+ With no FILE, or when FILE is -, read standard input.\n\
+ \n\
+ Mandatory arguments to long flags are mandatory for short flags too.\
+ ";
+constUSAGE: &str="tail [FLAG]... [FILE]...";
+
pubmodoptions {
pubmodverbosity {
pubstaticQUIET: &str="quiet";
@@ -701,8 +719,8 @@
pubfnuu_app() ->App<'static, 'static> {
App::new(uucore::util_name())
.version(crate_version!())
- .about("output the last part of files")
- // TODO: add usage
+ .about(ABOUT)
+ .usage(USAGE)
.arg(
Arg::with_name(options::BYTES)
.short("c")
diff --git a/uu_hashsum/index.html b/uu_hashsum/index.html
index 6e58e5627..16be3ec86 100644
--- a/uu_hashsum/index.html
+++ b/uu_hashsum/index.html
@@ -1,4 +1,4 @@
-uu_hashsum - Rust
\ No newline at end of file
diff --git a/uu_head/fn.uu_app.html b/uu_head/fn.uu_app.html
index 9462a2b60..2752ab186 100644
--- a/uu_head/fn.uu_app.html
+++ b/uu_head/fn.uu_app.html
@@ -1,3 +1,3 @@
-uu_app in uu_head - Rust
\ No newline at end of file
diff --git a/uu_head/fn.uumain.html b/uu_head/fn.uumain.html
index 5f0c58034..bb05d2ab3 100644
--- a/uu_head/fn.uumain.html
+++ b/uu_head/fn.uumain.html
@@ -1,3 +1,3 @@
-uumain in uu_head - Rust
\ No newline at end of file
diff --git a/uu_head/index.html b/uu_head/index.html
index 39b40cb96..cbcab7618 100644
--- a/uu_head/index.html
+++ b/uu_head/index.html
@@ -1,4 +1,4 @@
-uu_head - Rust
\ No newline at end of file
diff --git a/uu_tail/fn.uu_app.html b/uu_tail/fn.uu_app.html
index b95b7cd84..7c23f36e7 100644
--- a/uu_tail/fn.uu_app.html
+++ b/uu_tail/fn.uu_app.html
@@ -1,3 +1,3 @@
-uu_app in uu_tail - Rust
\ No newline at end of file
diff --git a/uu_tail/fn.uumain.html b/uu_tail/fn.uumain.html
index 5b2606f45..dfab8915b 100644
--- a/uu_tail/fn.uumain.html
+++ b/uu_tail/fn.uumain.html
@@ -1,3 +1,3 @@
-uumain in uu_tail - Rust
\ No newline at end of file
diff --git a/uu_tail/index.html b/uu_tail/index.html
index 409de5d0d..0c849a5ad 100644
--- a/uu_tail/index.html
+++ b/uu_tail/index.html
@@ -1,4 +1,4 @@
-uu_tail - Rust
\ No newline at end of file
diff --git a/uu_tail/options/static.BYTES.html b/uu_tail/options/static.BYTES.html
index 1346f57d6..e80d9ba50 100644
--- a/uu_tail/options/static.BYTES.html
+++ b/uu_tail/options/static.BYTES.html
@@ -1,3 +1,3 @@
-BYTES in uu_tail::options - Rust
\ No newline at end of file
diff --git a/uu_tail/options/static.FOLLOW.html b/uu_tail/options/static.FOLLOW.html
index fbcd2b5ee..b944f6b3e 100644
--- a/uu_tail/options/static.FOLLOW.html
+++ b/uu_tail/options/static.FOLLOW.html
@@ -1,3 +1,3 @@
-FOLLOW in uu_tail::options - Rust
\ No newline at end of file
diff --git a/uu_tail/options/static.LINES.html b/uu_tail/options/static.LINES.html
index 9530484b9..76acf024c 100644
--- a/uu_tail/options/static.LINES.html
+++ b/uu_tail/options/static.LINES.html
@@ -1,3 +1,3 @@
-LINES in uu_tail::options - Rust
\ No newline at end of file
diff --git a/uu_tail/options/static.PID.html b/uu_tail/options/static.PID.html
index ab47df9a3..3a2e23954 100644
--- a/uu_tail/options/static.PID.html
+++ b/uu_tail/options/static.PID.html
@@ -1,3 +1,3 @@
-PID in uu_tail::options - Rust
\ No newline at end of file
diff --git a/uu_tail/options/static.SLEEP_INT.html b/uu_tail/options/static.SLEEP_INT.html
index b48d2c118..d9ddc6dee 100644
--- a/uu_tail/options/static.SLEEP_INT.html
+++ b/uu_tail/options/static.SLEEP_INT.html
@@ -1,3 +1,3 @@
-SLEEP_INT in uu_tail::options - Rust
\ No newline at end of file
diff --git a/uu_tail/options/static.ZERO_TERM.html b/uu_tail/options/static.ZERO_TERM.html
index 19874c94b..7fb96f02f 100644
--- a/uu_tail/options/static.ZERO_TERM.html
+++ b/uu_tail/options/static.ZERO_TERM.html
@@ -1,3 +1,3 @@
-ZERO_TERM in uu_tail::options - Rust
\ No newline at end of file
diff --git a/uu_tail/options/verbosity/index.html b/uu_tail/options/verbosity/index.html
index 36b1a299f..b15d19a8c 100644
--- a/uu_tail/options/verbosity/index.html
+++ b/uu_tail/options/verbosity/index.html
@@ -1,4 +1,4 @@
-uu_tail::options::verbosity - Rust
\ No newline at end of file
diff --git a/uu_tail/options/verbosity/static.QUIET.html b/uu_tail/options/verbosity/static.QUIET.html
index e3eb9119f..6b4d6ca79 100644
--- a/uu_tail/options/verbosity/static.QUIET.html
+++ b/uu_tail/options/verbosity/static.QUIET.html
@@ -1,3 +1,3 @@
-QUIET in uu_tail::options::verbosity - Rust
\ No newline at end of file
diff --git a/uu_tail/options/verbosity/static.VERBOSE.html b/uu_tail/options/verbosity/static.VERBOSE.html
index 642fce429..a8916b25d 100644
--- a/uu_tail/options/verbosity/static.VERBOSE.html
+++ b/uu_tail/options/verbosity/static.VERBOSE.html
@@ -1,3 +1,3 @@
-VERBOSE in uu_tail::options::verbosity - Rust