From cd0c24af07d1412a746c5dbfe8a3df0a8cb56191 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Fri, 17 Nov 2023 14:41:14 +0100 Subject: [PATCH] printf: implement %b --- src/uucore/src/lib/features/format/mod.rs | 6 +-- src/uucore/src/lib/features/format/spec.rs | 43 +++++++++++++++++++--- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/uucore/src/lib/features/format/mod.rs b/src/uucore/src/lib/features/format/mod.rs index 8fa8d0717..7417d48fa 100644 --- a/src/uucore/src/lib/features/format/mod.rs +++ b/src/uucore/src/lib/features/format/mod.rs @@ -169,17 +169,17 @@ fn parse_spec_only(fmt: &[u8]) -> impl Iterator, Fo }) } -fn parse_escape_only(fmt: &[u8]) -> impl Iterator> + '_ { +fn parse_escape_only(fmt: &[u8]) -> impl Iterator + '_ { let mut current = fmt; std::iter::from_fn(move || match current { [] => return None, [b'\\', rest @ ..] => { current = rest; - Some(Ok(parse_escape_code(&mut current))) + Some(parse_escape_code(&mut current)) } [c, rest @ ..] => { current = rest; - Some(Ok(EscapedChar::Char(*c))) + Some(EscapedChar::Char(*c)) } }) } diff --git a/src/uucore/src/lib/features/format/spec.rs b/src/uucore/src/lib/features/format/spec.rs index 258005bb5..dc55bc653 100644 --- a/src/uucore/src/lib/features/format/spec.rs +++ b/src/uucore/src/lib/features/format/spec.rs @@ -5,9 +5,9 @@ use super::{ self, Case, FloatVariant, ForceDecimal, Formatter, NumberAlignment, PositiveSign, Prefix, UnsignedIntVariant, }, - FormatArgument, FormatError, + parse_escape_only, FormatArgument, FormatChar, FormatError, }; -use std::{fmt::Display, io::Write}; +use std::{fmt::Display, io::Write, ops::ControlFlow}; #[derive(Debug)] pub enum Spec { @@ -17,6 +17,7 @@ pub enum Spec { }, String { width: Option>, + parse_escape: bool, align_left: bool, }, SignedInt { @@ -145,6 +146,12 @@ impl Spec { }, b's' => Spec::String { width, + parse_escape: false, + align_left: minus, + }, + b'b' => Spec::String { + width, + parse_escape: true, align_left: minus, }, b'd' | b'i' => Spec::SignedInt { @@ -230,12 +237,36 @@ impl Spec { _ => Err(FormatError::InvalidArgument(arg.clone())), } } - &Spec::String { width, align_left } => { + &Spec::String { + width, + parse_escape, + align_left, + } => { let width = resolve_asterisk(width, &mut args)?.unwrap_or(0); let arg = next_arg(&mut args)?; - match arg.get_str() { - Some(s) => write_padded(writer, s, width, false, align_left), - _ => Err(FormatError::InvalidArgument(arg.clone())), + let Some(s) = arg.get_str() else { + return Err(FormatError::InvalidArgument(arg.clone())); + }; + if parse_escape { + let mut parsed = Vec::new(); + for c in parse_escape_only(s.as_bytes()) { + match c.write(&mut parsed)? { + ControlFlow::Continue(()) => {} + ControlFlow::Break(()) => { + // TODO: This should break the _entire execution_ of printf + break; + } + }; + } + write_padded( + writer, + std::str::from_utf8(&parsed).expect("TODO: Accept invalid utf8"), + width, + false, + align_left, + ) + } else { + write_padded(writer, s, width, false, align_left) } } &Spec::SignedInt {