Skip to content

Commit 79cb095

Browse files
sylvestrejtracey
authored andcommitted
printf: support for invalid utf-8 page
1 parent e5980d4 commit 79cb095

File tree

1 file changed

+43
-8
lines changed

1 file changed

+43
-8
lines changed

src/uu/printf/src/printf.rs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
use clap::{Arg, ArgAction, Command};
66
use std::io::stdout;
77
use std::ops::ControlFlow;
8+
#[cfg(unix)]
9+
use std::os::unix::ffi::{OsStrExt, OsStringExt};
10+
#[cfg(windows)]
11+
use std::os::windows::ffi::OsStrExt;
812
use uucore::error::{UResult, UUsageError};
913
use uucore::format::{FormatArgument, FormatItem, parse_spec_and_escape};
1014
use uucore::{format_usage, help_about, help_section, help_usage, show_warning};
@@ -19,23 +23,50 @@ mod options {
1923
pub const FORMAT: &str = "FORMAT";
2024
pub const ARGUMENT: &str = "ARGUMENT";
2125
}
22-
2326
#[uucore::main]
2427
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
2528
let matches = uu_app().get_matches_from(args);
2629

2730
let format = matches
28-
.get_one::<String>(options::FORMAT)
31+
.get_one::<std::ffi::OsString>(options::FORMAT)
2932
.ok_or_else(|| UUsageError::new(1, "missing operand"))?;
3033

31-
let values: Vec<_> = match matches.get_many::<String>(options::ARGUMENT) {
32-
Some(s) => s.map(|s| FormatArgument::Unparsed(s.to_string())).collect(),
34+
#[cfg(unix)]
35+
let format = format.as_bytes();
36+
37+
#[cfg(windows)]
38+
let format_vec: Vec<u8> = format
39+
.encode_wide()
40+
.flat_map(|wchar| wchar.to_le_bytes())
41+
.collect();
42+
#[cfg(windows)]
43+
let format = format_vec.as_slice();
44+
45+
let values: Vec<_> = match matches.get_many::<std::ffi::OsString>(options::ARGUMENT) {
46+
Some(s) => s
47+
.map(|os_str| {
48+
#[cfg(unix)]
49+
let raw_bytes: Vec<u8> = os_str.clone().into_vec();
50+
51+
#[cfg(windows)]
52+
let raw_bytes: Vec<u8> = os_str
53+
.encode_wide()
54+
.flat_map(|wchar| wchar.to_le_bytes())
55+
.collect();
56+
FormatArgument::Unparsed(
57+
String::from_utf8(raw_bytes.clone())
58+
.unwrap_or_else(|_| raw_bytes.iter().map(|&b| b as char).collect()),
59+
)
60+
})
61+
.collect(),
3362
None => vec![],
3463
};
3564

3665
let mut format_seen = false;
3766
let mut args = values.iter().peekable();
38-
for item in parse_spec_and_escape(format.as_ref()) {
67+
68+
// Parse and process the format string
69+
for item in parse_spec_and_escape(format) {
3970
if let Ok(FormatItem::Spec(_)) = item {
4071
format_seen = true;
4172
}
@@ -58,7 +89,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
5889
}
5990

6091
while args.peek().is_some() {
61-
for item in parse_spec_and_escape(format.as_ref()) {
92+
for item in parse_spec_and_escape(format) {
6293
match item?.write(stdout(), &mut args)? {
6394
ControlFlow::Continue(()) => {}
6495
ControlFlow::Break(()) => return Ok(()),
@@ -90,6 +121,10 @@ pub fn uu_app() -> Command {
90121
.help("Print version information")
91122
.action(ArgAction::Version),
92123
)
93-
.arg(Arg::new(options::FORMAT))
94-
.arg(Arg::new(options::ARGUMENT).action(ArgAction::Append))
124+
.arg(Arg::new(options::FORMAT).value_parser(clap::value_parser!(std::ffi::OsString)))
125+
.arg(
126+
Arg::new(options::ARGUMENT)
127+
.action(ArgAction::Append)
128+
.value_parser(clap::value_parser!(std::ffi::OsString)),
129+
)
95130
}

0 commit comments

Comments
 (0)