use std::io::Write;
pub(super) const BANNER: &str = "bzip2recover 1.0.8: extracts blocks from damaged .bz2 files.\n";
pub(super) const USAGE: &str = "%s: usage is `%s damaged_file_name'.\n";
pub(super) const USAGE_SIZE: &str = "\trestrictions on size of recovered file: None\n";
pub(super) const NAME_TOO_LONG: &str =
"%s: supplied filename is suspiciously (>= %d chars) long. Bye!\n";
pub(super) const CANT_READ: &str = "%s: can't read `%s'\n";
pub(super) const SEARCHING: &str = "%s: searching for block boundaries ...\n";
pub(super) const BLOCK: &str = " block %d runs from %Lu to %Lu\n";
pub(super) const BLOCK_INCOMPLETE: &str = " block %d runs from %Lu to %Lu (incomplete)\n";
pub(super) const NO_BLOCKS: &str = "%s: sorry, I couldn't find any block boundaries.\n";
pub(super) const SPLITTING: &str = "%s: splitting into blocks\n";
pub(super) const CANT_OPEN: &str = "%s: can't open `%s'\n";
pub(super) const WRITING: &str = " writing block %d to `%s' ...\n";
pub(super) const CANT_WRITE: &str = "%s: can't write `%s'\n";
pub(super) const FINISHED: &str = "%s: finished\n";
pub(super) const IO_ERROR: &str = "%s: I/O error reading `%s', possible reason follows.\n";
pub(super) const PERROR: &str = "%s: %s\n";
pub(super) const MAY_BE_INCOMPLETE: &str = "%s: warning: output file(s) may be incomplete.\n";
pub(super) const TOO_MANY_BLOCKS: &str = concat!(
"%s: `%s' appears to contain more than %d blocks\n",
"%s: and cannot be handled. To fix, increase\n",
"%s: BZ_MAX_HANDLED_BLOCKS in bzip2recover.c, and recompile.\n",
);
pub(super) fn printf(w: &mut dyn Write, fmt: &str, args: &[&[u8]]) {
let mut out = Vec::with_capacity(fmt.len() + 64);
let mut args = args.iter();
let mut bytes = fmt.as_bytes().iter().copied().peekable();
while let Some(b) = bytes.next() {
if b != b'%' {
out.push(b);
continue;
}
match bytes.next() {
Some(b's' | b'd') => out.extend_from_slice(args.next().copied().unwrap_or_default()),
Some(b'L') if bytes.peek() == Some(&b'u') => {
bytes.next();
out.extend_from_slice(args.next().copied().unwrap_or_default());
}
Some(other) => out.extend_from_slice(&[b'%', other]),
None => out.push(b'%'),
}
}
let _ = w.write_all(&out);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn printf_fills_s_d_and_lu_in_order() {
let mut v = Vec::new();
printf(&mut v, BLOCK, &[b"3", b"80", b"269145"]);
assert_eq!(v, b" block 3 runs from 80 to 269145\n");
let mut v = Vec::new();
printf(&mut v, USAGE, &[b"p", b"p"]);
assert_eq!(v, b"p: usage is `p damaged_file_name'.\n");
}
#[test]
fn too_many_blocks_is_three_lines_each_with_the_program_name() {
let mut v = Vec::new();
printf(&mut v, TOO_MANY_BLOCKS, &[b"p", b"f", b"50000", b"p", b"p"]);
assert_eq!(
String::from_utf8(v).unwrap(),
"p: `f' appears to contain more than 50000 blocks\n\
p: and cannot be handled. To fix, increase\n\
p: BZ_MAX_HANDLED_BLOCKS in bzip2recover.c, and recompile.\n"
);
}
}