@@ -11,6 +11,9 @@ mod error {
11
11
PatternNegation { line_number: usize , line: BString } {
12
12
display( "Line {} has a negative pattern, for literal characters use \\ !: {}" , line_number, line)
13
13
}
14
+ AttributeName { line_number: usize , attribute: BString } {
15
+ display( "Line {} has non-ascii characters or starts with '-': {}" , line_number, attribute)
16
+ }
14
17
Unquote ( err: git_quote:: ansi_c:: undo:: Error ) {
15
18
display( "Could not unquote attributes line" )
16
19
from( )
@@ -29,42 +32,63 @@ pub struct Lines<'a> {
29
32
30
33
pub struct Iter < ' a > {
31
34
attrs : bstr:: Fields < ' a > ,
35
+ line_no : usize ,
32
36
}
33
37
34
38
impl < ' a > Iter < ' a > {
35
- pub fn new ( attrs : & ' a BStr ) -> Self {
36
- Iter { attrs : attrs. fields ( ) }
39
+ pub fn new ( attrs : & ' a BStr , line_no : usize ) -> Self {
40
+ Iter {
41
+ attrs : attrs. fields ( ) ,
42
+ line_no,
43
+ }
44
+ }
45
+
46
+ fn parse_attr ( & self , attr : & ' a [ u8 ] ) -> Result < ( & ' a BStr , crate :: State < ' a > ) , Error > {
47
+ let mut tokens = attr. splitn ( 2 , |b| * b == b'=' ) ;
48
+ let attr = tokens. next ( ) . expect ( "attr itself" ) . as_bstr ( ) ;
49
+ let possibly_value = tokens. next ( ) ;
50
+ let ( attr, state) = if attr. first ( ) == Some ( & b'-' ) {
51
+ ( & attr[ 1 ..] , crate :: State :: Unset )
52
+ } else if attr. first ( ) == Some ( & b'!' ) {
53
+ ( & attr[ 1 ..] , crate :: State :: Unspecified )
54
+ } else {
55
+ (
56
+ attr,
57
+ possibly_value
58
+ . map ( |v| crate :: State :: Value ( v. as_bstr ( ) ) )
59
+ . unwrap_or ( crate :: State :: Set ) ,
60
+ )
61
+ } ;
62
+ if !attr_valid ( attr) {
63
+ return Err ( Error :: AttributeName {
64
+ line_number : self . line_no ,
65
+ attribute : attr. into ( ) ,
66
+ } ) ;
67
+ }
68
+ Ok ( ( attr, state) )
37
69
}
38
70
}
39
71
72
+ fn attr_valid ( attr : & BStr ) -> bool {
73
+ if attr. first ( ) == Some ( & b'-' ) {
74
+ return false ;
75
+ }
76
+
77
+ attr. bytes ( ) . all ( |b| match b {
78
+ b'-' | b'.' | b'_' | b'A' ..=b'Z' | b'a' ..=b'z' | b'0' ..=b'9' => true ,
79
+ _ => false ,
80
+ } )
81
+ }
82
+
40
83
impl < ' a > Iterator for Iter < ' a > {
41
84
type Item = Result < ( & ' a BStr , crate :: State < ' a > ) , Error > ;
42
85
43
86
fn next ( & mut self ) -> Option < Self :: Item > {
44
87
let attr = self . attrs . next ( ) . filter ( |a| !a. is_empty ( ) ) ?;
45
- parse_attr ( attr) . into ( )
88
+ self . parse_attr ( attr) . into ( )
46
89
}
47
90
}
48
91
49
- fn parse_attr ( attr : & [ u8 ] ) -> Result < ( & BStr , crate :: State < ' _ > ) , Error > {
50
- let mut tokens = attr. splitn ( 2 , |b| * b == b'=' ) ;
51
- let attr = tokens. next ( ) . expect ( "attr itself" ) . as_bstr ( ) ;
52
- let possibly_value = tokens. next ( ) ;
53
- let ( attr, state) = if attr. first ( ) == Some ( & b'-' ) {
54
- ( & attr[ 1 ..] , crate :: State :: Unset )
55
- } else if attr. first ( ) == Some ( & b'!' ) {
56
- ( & attr[ 1 ..] , crate :: State :: Unspecified )
57
- } else {
58
- (
59
- attr,
60
- possibly_value
61
- . map ( |v| crate :: State :: Value ( v. as_bstr ( ) ) )
62
- . unwrap_or ( crate :: State :: Set ) ,
63
- )
64
- } ;
65
- Ok ( ( attr, state) )
66
- }
67
-
68
92
impl < ' a > Lines < ' a > {
69
93
pub fn new ( buf : & ' a [ u8 ] ) -> Self {
70
94
let bom = unicode_bom:: Bom :: from ( buf) ;
@@ -85,7 +109,7 @@ impl<'a> Iterator for Lines<'a> {
85
109
if line. first ( ) == Some ( & b'#' ) {
86
110
continue ;
87
111
}
88
- match parse_line ( line) {
112
+ match parse_line ( line, self . line_no ) {
89
113
None => continue ,
90
114
Some ( Ok ( ( pattern, flags, attrs) ) ) => {
91
115
return Some ( if flags. contains ( ignore:: pattern:: Mode :: NEGATIVE ) {
@@ -104,7 +128,10 @@ impl<'a> Iterator for Lines<'a> {
104
128
}
105
129
}
106
130
107
- fn parse_line ( line : & BStr ) -> Option < Result < ( BString , crate :: ignore:: pattern:: Mode , Iter < ' _ > ) , Error > > {
131
+ fn parse_line (
132
+ line : & BStr ,
133
+ line_number : usize ,
134
+ ) -> Option < Result < ( BString , crate :: ignore:: pattern:: Mode , Iter < ' _ > ) , Error > > {
108
135
if line. is_empty ( ) {
109
136
return None ;
110
137
}
@@ -122,7 +149,7 @@ fn parse_line(line: &BStr) -> Option<Result<(BString, crate::ignore::pattern::Mo
122
149
} ;
123
150
124
151
let ( pattern, flags) = super :: ignore:: parse_line ( line. as_ref ( ) ) ?;
125
- Ok ( ( pattern, flags, Iter :: new ( attrs) ) ) . into ( )
152
+ Ok ( ( pattern, flags, Iter :: new ( attrs, line_number ) ) ) . into ( )
126
153
}
127
154
128
155
const BLANKS : & [ u8 ] = b" \t \r " ;
0 commit comments