Skip to content

Commit 7369f4d

Browse files
can1357sylvestre
authored andcommitted
tr: reject unknown character classes during sequence parsing
1 parent 593f5b1 commit 7369f4d

4 files changed

Lines changed: 46 additions & 26 deletions

File tree

src/uu/tr/locales/en-US.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ tr-warning-invalid-utf8 = invalid utf8 sequence
2727
2828
# Sequence parsing error messages
2929
tr-error-missing-char-class-name = missing character class name '[::]'
30+
tr-error-invalid-char-class = invalid character class { $class }
3031
tr-error-missing-equivalence-class-char = missing equivalence class character '[==]'
3132
tr-error-multiple-char-repeat-in-set2 = only one [c*] repeat construct may appear in string2
3233
tr-error-char-repeat-in-set1 = the [c*] repeat construct may not appear in string1

src/uu/tr/locales/fr-FR.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ tr-warning-invalid-utf8 = séquence UTF-8 non valide
2828
2929
# Messages d'erreur d'analyse de séquence
3030
tr-error-missing-char-class-name = nom de classe de caractères manquant '[::]'
31+
tr-error-invalid-char-class = classe de caractères non valide { $class }
3132
tr-error-missing-equivalence-class-char = caractère de classe d'équivalence manquant '[==]'
3233
tr-error-multiple-char-repeat-in-set2 = seule une construction de répétition [c*] peut apparaître dans string2
3334
tr-error-char-repeat-in-set1 = la construction de répétition [c*] ne peut pas apparaître dans string1

src/uu/tr/src/operation.rs

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub trait ChunkProcessor {
3434
#[derive(Debug, Clone)]
3535
pub enum BadSequence {
3636
MissingCharClassName,
37+
InvalidCharClass(String),
3738
MissingEquivalentClassChar,
3839
MultipleCharRepeatInSet2,
3940
CharRepeatInSet1,
@@ -53,6 +54,13 @@ impl Display for BadSequence {
5354
Self::MissingCharClassName => {
5455
write!(f, "{}", translate!("tr-error-missing-char-class-name"))
5556
}
57+
Self::InvalidCharClass(class) => {
58+
write!(
59+
f,
60+
"{}",
61+
translate!("tr-error-invalid-char-class", "class" => format!("'{}'", class))
62+
)
63+
}
5664
Self::MissingEquivalentClassChar => {
5765
write!(
5866
f,
@@ -499,31 +507,32 @@ impl Sequence {
499507
}
500508

501509
fn parse_class(input: &[u8]) -> IResult<&[u8], Result<Self, BadSequence>> {
502-
delimited(
503-
tag("[:"),
504-
alt((
505-
map(
506-
alt((
507-
value(Self::Class(Class::Alnum), tag("alnum")),
508-
value(Self::Class(Class::Alpha), tag("alpha")),
509-
value(Self::Class(Class::Blank), tag("blank")),
510-
value(Self::Class(Class::Control), tag("cntrl")),
511-
value(Self::Class(Class::Digit), tag("digit")),
512-
value(Self::Class(Class::Graph), tag("graph")),
513-
value(Self::Class(Class::Lower), tag("lower")),
514-
value(Self::Class(Class::Print), tag("print")),
515-
value(Self::Class(Class::Punct), tag("punct")),
516-
value(Self::Class(Class::Space), tag("space")),
517-
value(Self::Class(Class::Upper), tag("upper")),
518-
value(Self::Class(Class::Xdigit), tag("xdigit")),
519-
)),
520-
Ok,
521-
),
522-
value(Err(BadSequence::MissingCharClassName), tag("")),
523-
)),
524-
tag(":]"),
525-
)
526-
.parse(input)
510+
preceded(tag("[:"), terminated(take_until(":]"), tag(":]")))
511+
.parse(input)
512+
.map(|(l, class_name)| {
513+
(
514+
l,
515+
match class_name {
516+
b"" => Err(BadSequence::MissingCharClassName),
517+
b"alnum" => Ok(Self::Class(Class::Alnum)),
518+
b"alpha" => Ok(Self::Class(Class::Alpha)),
519+
b"blank" => Ok(Self::Class(Class::Blank)),
520+
b"cntrl" => Ok(Self::Class(Class::Control)),
521+
b"digit" => Ok(Self::Class(Class::Digit)),
522+
b"graph" => Ok(Self::Class(Class::Graph)),
523+
b"lower" => Ok(Self::Class(Class::Lower)),
524+
b"print" => Ok(Self::Class(Class::Print)),
525+
b"punct" => Ok(Self::Class(Class::Punct)),
526+
b"space" => Ok(Self::Class(Class::Space)),
527+
b"upper" => Ok(Self::Class(Class::Upper)),
528+
b"xdigit" => Ok(Self::Class(Class::Xdigit)),
529+
_ => Err(BadSequence::InvalidCharClass(format!(
530+
"[:{}:]",
531+
String::from_utf8_lossy(class_name)
532+
))),
533+
},
534+
)
535+
})
527536
}
528537

529538
fn parse_char_equal(input: &[u8]) -> IResult<&[u8], Result<Self, BadSequence>> {

tests/by-util/test_tr.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
5-
// spell-checker:ignore aabbaa aabbcc aabc abbb abbbcddd abcc abcdefabcdef abcdefghijk abcdefghijklmn abcdefghijklmnop ABCDEFGHIJKLMNOPQRS abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFZZ abcxyz ABCXYZ abcxyzabcxyz ABCXYZABCXYZ acbdef alnum amzamz AMZXAMZ bbbd cclass cefgm cntrl compl dabcdef dncase Gzabcdefg PQRST upcase wxyzz xdigit XXXYYY xycde xyyye xyyz xyzzzzxyzzzz ZABCDEF Zamz Cdefghijkl Cdefghijklmn asdfqqwweerr qwerr asdfqwer qwer aassddffqwer asdfqwer
5+
// spell-checker:ignore aabbaa aabbcc aabc abbb abbbcddd abcc abcdefabcdef abcdefghijk abcdefghijklmn abcdefghijklmnop ABCDEFGHIJKLMNOPQRS abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFZZ abcxyz ABCXYZ abcxyzabcxyz ABCXYZABCXYZ acbdef alnum amzamz AMZXAMZ bbbd cclass cefgm cntrl compl dabcdef dncase fooclass Gzabcdefg PQRST upcase wxyzz xdigit XXXYYY xycde xyyye xyyz xyzzzzxyzzzz ZABCDEF Zamz Cdefghijkl Cdefghijklmn asdfqqwweerr qwerr asdfqwer qwer aassddffqwer asdfqwer
66
use uutests::at_and_ucmd;
77
use uutests::new_ucmd;
88

@@ -1185,6 +1185,15 @@ fn check_against_gnu_tr_tests_empty_cc() {
11851185
.stderr_is("tr: missing character class name '[::]'\n");
11861186
}
11871187

1188+
#[test]
1189+
fn check_against_gnu_tr_tests_invalid_cc() {
1190+
new_ucmd!()
1191+
.args(&["[:fooclass:]", "x"])
1192+
.pipe_in("")
1193+
.fails()
1194+
.stderr_is("tr: invalid character class '[:fooclass:]'\n");
1195+
}
1196+
11881197
#[test]
11891198
fn check_against_gnu_tr_tests_repeat_set1() {
11901199
new_ucmd!()

0 commit comments

Comments
 (0)