@@ -2,6 +2,7 @@ pub(crate) mod function {
2
2
use bstr:: ByteSlice ;
3
3
use btoi:: btoi;
4
4
use gix_date:: { time:: Sign , OffsetInSeconds , SecondsSinceUnixEpoch , Time } ;
5
+ use nom:: multi:: many1_count;
5
6
use nom:: {
6
7
branch:: alt,
7
8
bytes:: complete:: { tag, take, take_until, take_while_m_n} ,
@@ -10,6 +11,7 @@ pub(crate) mod function {
10
11
sequence:: { terminated, tuple} ,
11
12
IResult ,
12
13
} ;
14
+ use std:: cell:: RefCell ;
13
15
14
16
use crate :: { IdentityRef , SignatureRef } ;
15
17
@@ -19,7 +21,9 @@ pub(crate) mod function {
19
21
pub fn decode < ' a , E : ParseError < & ' a [ u8 ] > + ContextError < & ' a [ u8 ] > > (
20
22
i : & ' a [ u8 ] ,
21
23
) -> IResult < & ' a [ u8 ] , SignatureRef < ' a > , E > {
22
- let ( i, ( identity, _, time, tzsign, hours, minutes) ) = context (
24
+ use nom:: Parser ;
25
+ let tzsign = RefCell :: new ( b'-' ) ; // TODO: there should be no need for this.
26
+ let ( i, ( identity, _, time, _tzsign_count, hours, minutes) ) = context (
23
27
"<name> <<email>> <timestamp> <+|-><HHMM>" ,
24
28
tuple ( (
25
29
identity,
@@ -31,7 +35,13 @@ pub(crate) mod function {
31
35
. map_err ( |_| nom:: Err :: Error ( E :: from_error_kind ( i, nom:: error:: ErrorKind :: MapRes ) ) )
32
36
} )
33
37
} ) ,
34
- context ( "+|-" , alt ( ( tag ( b"-" ) , tag ( b"+" ) ) ) ) ,
38
+ context (
39
+ "+|-" ,
40
+ alt ( (
41
+ many1_count ( tag ( b"-" ) ) . map ( |_| * tzsign. borrow_mut ( ) = b'-' ) , // TODO: this should be a non-allocating consumer of consecutive tags
42
+ many1_count ( tag ( b"+" ) ) . map ( |_| * tzsign. borrow_mut ( ) = b'+' ) ,
43
+ ) ) ,
44
+ ) ,
35
45
context ( "HH" , |i| {
36
46
take_while_m_n ( 2usize , 2 , is_digit) ( i) . and_then ( |( i, v) | {
37
47
btoi :: < OffsetInSeconds > ( v)
@@ -40,7 +50,7 @@ pub(crate) mod function {
40
50
} )
41
51
} ) ,
42
52
context ( "MM" , |i| {
43
- take_while_m_n ( 2usize , 2 , is_digit) ( i) . and_then ( |( i, v) | {
53
+ take_while_m_n ( 1usize , 2 , is_digit) ( i) . and_then ( |( i, v) | {
44
54
btoi :: < OffsetInSeconds > ( v)
45
55
. map ( |v| ( i, v) )
46
56
. map_err ( |_| nom:: Err :: Error ( E :: from_error_kind ( i, nom:: error:: ErrorKind :: MapRes ) ) )
@@ -49,8 +59,9 @@ pub(crate) mod function {
49
59
) ) ,
50
60
) ( i) ?;
51
61
52
- debug_assert ! ( tzsign[ 0 ] == b'-' || tzsign[ 0 ] == b'+' , "parser assure it's +|- only" ) ;
53
- let sign = if tzsign[ 0 ] == b'-' { Sign :: Minus } else { Sign :: Plus } ; //
62
+ let tzsign = tzsign. into_inner ( ) ;
63
+ debug_assert ! ( tzsign == b'-' || tzsign == b'+' , "parser assure it's +|- only" ) ;
64
+ let sign = if tzsign == b'-' { Sign :: Minus } else { Sign :: Plus } ; //
54
65
let offset = ( hours * 3600 + minutes * 60 ) * if sign == Sign :: Minus { -1 } else { 1 } ;
55
66
56
67
Ok ( (
@@ -148,6 +159,16 @@ mod tests {
148
159
) ;
149
160
}
150
161
162
+ #[ test]
163
+ fn negative_offset_double_dash ( ) {
164
+ assert_eq ! (
165
+ decode
( b"name <[email protected] > 1288373970 --700" )
166
+ . expect( "parse to work" )
167
+ . 1 ,
168
+ signature
( "name" , "[email protected] " , 1288373970 , Sign :: Minus , -
252000 )
169
+ ) ;
170
+ }
171
+
151
172
#[ test]
152
173
fn empty_name_and_email ( ) {
153
174
assert_eq ! (
0 commit comments