diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 100 |
1 files changed, 100 insertions, 0 deletions
@@ -5,3 +5,103 @@ pub use crate::input::Input; mod cli; mod error; mod input; + +pub const HELP: &str = r#"Usage: cat [OPTION]... [FILE]... +Concatenate FILE(s) to standard output. + +With no FILE, or when FILE is -, read standard input. + + -A, --show-all equivalent to -vET + -b, --number-nonblank number nonempty output lines, overrides -n + -e equivalent to -vE + -E, --show-ends display $ at end of each line + -n, --number number all output lines + -s, --squeeze-blank suppress repeated empty output lines + -t equivalent to -vT + -T, --show-tabs display TAB characters as ^I + -u (ignored) + -v, --show-nonprinting use ^ and M- notation, except for LFD and TAB + --help display this help and exit + --version output version information and exit + +Examples: + cat f - g Output f's contents, then standard input, then g's contents. + cat Copy standard input to standard output."#; + +pub fn run(cli: Cli) -> Result<()> { + use std::io::{BufReader, Read, Write}; + + let stdout = std::io::stdout(); + let mut writer = stdout.lock(); + + for file in cli.files.into_iter() { + let mut reader = BufReader::new(file.reader()?); + + let mut nonblank_line_nr = 0; + let mut buf = Vec::new(); + reader.read_to_end(&mut buf)?; + + for (index, arr) in buf.split(|c| *c == b'\n').enumerate() { + if arr.is_empty() && cli.opts.squeeze_blank { + continue; + } + + let mut line = Vec::new(); + for c in arr { + let parsed = match *c { + b'\t' if cli.opts.show_tabs => vec![b'^', b'I'], + b'\t' => vec![b'\t'], + c if cli.opts.show_nonprinting => parse_nonprinting_char(c), + c => vec![c], + }; + line.extend(parsed) + } + + if cli.opts.show_ends { + line.push(b'$'); + } + + line.push(b'\n'); + + if cli.opts.number_nonblank { + if !line.is_empty() { + nonblank_line_nr += 1; + write!(writer, "{:>6} ", nonblank_line_nr)?; + } + } else if cli.opts.number { + write!(writer, "{:>6} ", index + 1)?; + } + + writer.write_all(&line)? + } + } + + Ok(()) +} + +fn parse_nonprinting_char(c: u8) -> Vec<u8> { + match c { + c @ 0..=31 => into_ctrl_char(c), + c @ 32..=126 => vec![c], + 127 => into_unknown_char(), + c @ 128.. => into_meta_char(c), + } +} + +fn into_ctrl_char(c: u8) -> Vec<u8> { + vec![b'^', c + 64] +} + +fn into_meta_char(c: u8) -> Vec<u8> { + let mut buf = "M-^".as_bytes().to_vec(); + match c - 128 { + c @ 0..=31 => buf.extend(vec![b'^', c + 64]), + c @ 32..=127 => buf.push(c), + 128.. => buf.extend(into_unknown_char()), + }; + buf +} + +fn into_unknown_char() -> Vec<u8> { + vec![b'^', b'?'] +} |