1
1
//! Parsers and utility functions.
2
2
3
+ use std:: borrow:: ToOwned ;
4
+ use std:: fs:: File ;
3
5
use std:: io:: { Error , ErrorKind , Read , Result } ;
4
6
use std:: str:: { self , FromStr } ;
5
- use std:: fs:: File ;
6
7
7
8
use byteorder:: { ByteOrder , LittleEndian } ;
8
- use nom:: { IResult , alphanumeric, digit, is_digit, not_line_ending, space} ;
9
+ use libc:: clock_t;
10
+ use nom:: {
11
+ alphanumeric,
12
+ digit,
13
+ Err ,
14
+ ErrorCode ,
15
+ IResult ,
16
+ is_digit,
17
+ not_line_ending,
18
+ space
19
+ } ;
9
20
10
21
/// Read all bytes in the file until EOF, placing them into `buf`.
11
22
///
@@ -54,12 +65,13 @@ pub fn map_result<T>(result: IResult<&[u8], T>) -> Result<T> {
54
65
}
55
66
}
56
67
IResult :: Error ( err) => Err ( Error :: new ( ErrorKind :: InvalidInput ,
57
- format ! ( "unable to parse input: {:?}" , err) ) ) ,
68
+ format ! ( "unable to parse input: {:?}" , err) ) ) ,
58
69
_ => Err ( Error :: new ( ErrorKind :: InvalidInput , "unable to parse input" ) ) ,
59
70
}
60
71
}
61
72
62
73
74
+ /// Recognizes numerical characters: 0-9, and periods: '.'.
63
75
fn fdigit ( input : & [ u8 ] ) -> IResult < & [ u8 ] , & [ u8 ] > {
64
76
for idx in 0 ..input. len ( ) {
65
77
if ( !is_digit ( input[ idx] ) ) && ( '.' as u8 != input[ idx] ) {
@@ -69,26 +81,44 @@ fn fdigit(input: &[u8]) -> IResult<&[u8], &[u8]> {
69
81
IResult :: Done ( b"" , input)
70
82
}
71
83
72
- /// Parses the remainder of the line to a string.
73
- named ! ( pub parse_to_end<String >,
74
- map_res!( map_res!( not_line_ending, str :: from_utf8) , FromStr :: from_str) ) ;
84
+ /// Recognizes numerical characters: 0-9, and an optional leading dash: '-'.
85
+ pub fn sdigit ( input : & [ u8 ] ) -> IResult < & [ u8 ] , & [ u8 ] > {
86
+ if input. is_empty ( ) {
87
+ return IResult :: Done ( b"" , input)
88
+ }
75
89
76
- /// Parses a u32 in base-10 format.
77
- named ! ( pub parse_u32<u32 >,
78
- map_res!( map_res!( digit, str :: from_utf8) , FromStr :: from_str) ) ;
90
+ let start = if input[ 0 ] == '-' as u8 { 1 } else { 0 } ;
91
+ for ( idx, item) in input. iter ( ) . enumerate ( ) . skip ( start) {
92
+ if !is_digit ( * item) {
93
+ if idx == start {
94
+ return IResult :: Error ( Err :: Position ( ErrorCode :: Digit as u32 , input) ) ;
95
+ } else {
96
+ return IResult :: Done ( & input[ idx..] , & input[ 0 ..idx] ) ;
97
+ }
98
+ }
99
+ }
100
+ IResult :: Done ( b"" , input)
101
+ }
79
102
80
- /// Parses a f32 in base-10 format .
81
- named ! ( pub parse_f32< f32 >,
82
- map_res !( map_res!( fdigit , str :: from_utf8) , FromStr :: from_str ) ) ;
103
+ /// Parses a line to a string .
104
+ named ! ( pub parse_line< String >,
105
+ map !( map_res!( not_line_ending , str :: from_utf8) , ToOwned :: to_owned ) ) ;
83
106
84
- /// Parses a sequence of whitespace seperated u32s.
85
- named ! ( pub parse_u32s<Vec <u32 > >, separated_list!( space, parse_u32) ) ;
107
+ /// Parses a clock_t in base-10 format.
108
+ named ! ( pub parse_clock<clock_t>,
109
+ map_res!( map_res!( sdigit, str :: from_utf8) , FromStr :: from_str) ) ;
86
110
87
111
/// Parses an i32 in base-10 format.
88
- named ! ( pub parse_i32<i32 >, map!( parse_u32, { |n| { n as i32 } } ) ) ;
112
+ named ! ( pub parse_i32<i32 >,
113
+ map_res!( map_res!( sdigit, str :: from_utf8) , FromStr :: from_str) ) ;
89
114
90
- /// Parses a sequence of whitespace seperated i32s.
91
- named ! ( pub parse_i32s<Vec <i32 > >, separated_list!( space, parse_i32) ) ;
115
+ /// Parses an i64 in base-10 format.
116
+ named ! ( pub parse_i64<i64 >,
117
+ map_res!( map_res!( sdigit, str :: from_utf8) , FromStr :: from_str) ) ;
118
+
119
+ /// Parses a u32 in base-10 format.
120
+ named ! ( pub parse_u32<u32 >,
121
+ map_res!( map_res!( digit, str :: from_utf8) , FromStr :: from_str) ) ;
92
122
93
123
/// Parses a u64 in base-10 format.
94
124
named ! ( pub parse_u64<u64 >,
@@ -98,6 +128,16 @@ named!(pub parse_u64<u64>,
98
128
named ! ( pub parse_usize<usize >,
99
129
map_res!( map_res!( digit, str :: from_utf8) , FromStr :: from_str) ) ;
100
130
131
+ /// Parses a f32 in base-10 format.
132
+ named ! ( pub parse_f32<f32 >,
133
+ map_res!( map_res!( fdigit, str :: from_utf8) , FromStr :: from_str) ) ;
134
+
135
+ /// Parses a sequence of whitespace seperated u32s.
136
+ named ! ( pub parse_u32s<Vec <u32 > >, separated_list!( space, parse_u32) ) ;
137
+
138
+ /// Parses a sequence of whitespace seperated i32s.
139
+ named ! ( pub parse_i32s<Vec <i32 > >, separated_list!( space, parse_i32) ) ;
140
+
101
141
/// Parses a usize followed by a kB unit tag.
102
142
named ! ( pub parse_kb<usize >,
103
143
chain!( space ~ bytes: parse_usize ~ space ~ tag!( "kB" ) , || { bytes } ) ) ;
@@ -138,6 +178,35 @@ named!(pub parse_u32_mask_list<Box<[u8]> >,
138
178
bytes. into_boxed_slice( )
139
179
} ) ) ;
140
180
181
+ /// `take_until_right_and_consume!(tag) => &[T] -> IResult<&[T], &[T]>`
182
+ /// generates a parser consuming bytes until the specified byte sequence is found, and consumes it.
183
+ /// The sequence is searched for in the input in right to left order.
184
+ macro_rules! take_until_right_and_consume(
185
+ ( $i: expr, $inp: expr) => ( {
186
+ #[ inline( always) ]
187
+ fn as_bytes<T : nom:: AsBytes >( b: & T ) -> & [ u8 ] {
188
+ b. as_bytes( )
189
+ }
190
+
191
+ let expected = $inp;
192
+ let bytes = as_bytes( & expected) ;
193
+ let mut index = 0 ;
194
+ let mut parsed = false ;
195
+ for idx in ( 0 ..( ( $i. len( ) + 1 ) - bytes. len( ) ) ) . rev( ) {
196
+ if & $i[ idx..idx + bytes. len( ) ] == bytes {
197
+ index = idx;
198
+ parsed = true ;
199
+ break ;
200
+ }
201
+ }
202
+ if parsed {
203
+ nom:: IResult :: Done ( & $i[ ( index + bytes. len( ) ) ..] , & $i[ 0 ..index] )
204
+ } else {
205
+ nom:: IResult :: Error ( nom:: Err :: Position ( nom:: ErrorCode :: TakeUntilAndConsume as u32 , $i) )
206
+ }
207
+ } ) ;
208
+ ) ;
209
+
141
210
#[ cfg( test) ]
142
211
pub mod tests {
143
212
@@ -147,8 +216,8 @@ pub mod tests {
147
216
148
217
use nom:: IResult ;
149
218
150
- use super :: { map_result, parse_f32, parse_i32s , parse_u32_hex , parse_u32_mask_list , parse_u32s ,
151
- reverse} ;
219
+ use super :: { map_result, parse_f32, parse_i32 , parse_i32s , parse_i64 , parse_u32_hex ,
220
+ parse_u32_mask_list , parse_u32s , reverse} ;
152
221
153
222
/// Unwrap a complete parse result.
154
223
pub fn unwrap < T > ( result : IResult < & [ u8 ] , T > ) -> T {
@@ -208,7 +277,23 @@ pub mod tests {
208
277
assert_eq ! ( Vec :: <i32 >:: new( ) , & * unwrap( parse_i32s( b"" ) ) ) ;
209
278
assert_eq ! ( vec![ 0i32 ] , & * unwrap( parse_i32s( b"0" ) ) ) ;
210
279
assert_eq ! ( vec![ 0i32 , 1 ] , & * unwrap( parse_i32s( b"0 1" ) ) ) ;
211
- assert_eq ! ( vec![ 99999i32 , 32 , 22 , 888 ] , & * unwrap( parse_i32s( b"99999 32 22 888" ) ) ) ;
280
+ assert_eq ! ( vec![ 99999i32 , 0 , -22 , 32 , 888 ] , & * unwrap( parse_i32s( b"99999 0 -22 32 888" ) ) ) ;
281
+ }
282
+
283
+ #[ test]
284
+ fn test_parse_i32 ( ) {
285
+ assert_eq ! ( 0i32 , unwrap( parse_i32( b"0" ) ) ) ;
286
+ assert_eq ! ( 0i32 , unwrap( parse_i32( b"-0" ) ) ) ;
287
+ assert_eq ! ( 32i32 , unwrap( parse_i32( b"32" ) ) ) ;
288
+ assert_eq ! ( -32i32 , unwrap( parse_i32( b"-32" ) ) ) ;
289
+ }
290
+
291
+ #[ test]
292
+ fn test_parse_i64 ( ) {
293
+ assert_eq ! ( 0i64 , unwrap( parse_i64( b"0" ) ) ) ;
294
+ assert_eq ! ( 0i64 , unwrap( parse_i64( b"-0" ) ) ) ;
295
+ assert_eq ! ( 32i64 , unwrap( parse_i64( b"32" ) ) ) ;
296
+ assert_eq ! ( -32i64 , unwrap( parse_i64( b"-32" ) ) ) ;
212
297
}
213
298
214
299
#[ test]
0 commit comments