1
15
16 #include "FileTokenizer.hpp"
17 #include "moab/ReadUtilIface.hpp"
18 #include "moab/ErrorHandler.hpp"
19
20 #include <cstring>
21 #include <cctype>
22 #include <string>
23 #include <cstdlib>
24
25 namespace moab
26 {
27
28 using namespace std;
29
30 FileTokenizer::FileTokenizer( FILE* file_ptr, ReadUtilIface* )
31 : filePtr( file_ptr ), nextToken( buffer ), bufferEnd( buffer ), lineNumber( 1 ), lastChar( '\0' )
32 {
33 }
34
35 FileTokenizer::~FileTokenizer()
36 {
37 fclose( filePtr );
38 }
39
40 bool FileTokenizer::eof() const
41 {
42 return nextToken == bufferEnd && feof( filePtr );
43 }
44
45 const char* FileTokenizer::get_string()
46 {
47
48
49 if( lastChar == '\n' ) ++lineNumber;
50
51
52
53 for( ;; )
54 {
55
56 if( nextToken == bufferEnd )
57 {
58 size_t count = fread( buffer, 1, sizeof( buffer ) - 1, filePtr );
59 if( 0 == count )
60 {
61 if( feof( filePtr ) )
62 return NULL;
63 else
64 MB_SET_ERR_RET_VAL( "I/O Error", NULL );
65 }
66
67 nextToken = buffer;
68 bufferEnd = buffer + count;
69 }
70
71
72 if( !isspace( *nextToken ) ) break;
73
74
75
76 if( *nextToken == '\n' ) ++lineNumber;
77 ++nextToken;
78 }
79
80
81
82
83 char* result = nextToken;
84 while( nextToken != bufferEnd && !isspace( static_cast< unsigned char >( *nextToken ) ) )
85 ++nextToken;
86
87
88
89
90
91 if( nextToken == bufferEnd )
92 {
93
94 size_t remaining = bufferEnd - result;
95 memmove( buffer, result, remaining );
96 result = buffer;
97 nextToken = result + remaining;
98
99
100 size_t count = fread( nextToken, 1, sizeof( buffer ) - remaining - 1, filePtr );
101 if( 0 == count && !feof( filePtr ) ) MB_SET_ERR_RET_VAL( "I/O Error", NULL );
102 bufferEnd = nextToken + count;
103
104
105
106 while( nextToken != bufferEnd && !isspace( *nextToken ) )
107 ++nextToken;
108
109 if( nextToken == bufferEnd )
110 {
111 *bufferEnd = '\0';
112 ++bufferEnd;
113 }
114 }
115
116
117 lastChar = *nextToken;
118
119 *nextToken = '\0';
120
121 ++nextToken;
122
123 return result;
124 }
125
126 bool FileTokenizer::get_double_internal( double& result )
127 {
128
129 const char *token_end, *token = get_string();
130 if( !token ) return false;
131
132
133
134
135 if( token[0] && token[1] && token[0] == '0' && toupper( token[1] ) == 'X' )
136 MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected number, got \"" << token << "\"",
137 false );
138
139
140 result = strtod( token, (char**)&token_end );
141
142
143
144
145 if( *token_end )
146 MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected number, got \"" << token << "\"",
147 false );
148
149 return true;
150 }
151
152 bool FileTokenizer::get_float_internal( float& result )
153 {
154 double d;
155 if( !get_double_internal( d ) ) return false;
156
157 result = (float)d;
158
159 return true;
160 }
161
162 bool FileTokenizer::get_long_int_internal( long& result )
163 {
164
165 const char *token_end, *token = get_string();
166 if( !token ) return false;
167
168
169 result = strtol( token, (char**)&token_end, 0 );
170
171
172
173
174 if( *token_end )
175 MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected number, got \"" << token << "\"",
176 false );
177
178 return true;
179 }
180
181 bool FileTokenizer::get_byte_internal( unsigned char& result )
182 {
183 long i;
184 if( !get_long_int_internal( i ) ) return false;
185
186 result = (unsigned char)i;
187 if( i != (long)result ) MB_SET_ERR_RET_VAL( "Numeric overflow at line " << line_number(), false );
188
189 return true;
190 }
191
192 bool FileTokenizer::get_short_int_internal( short& result )
193 {
194 long i;
195 if( !get_long_int_internal( i ) ) return false;
196
197 result = (short)i;
198 if( i != (long)result ) MB_SET_ERR_RET_VAL( "Numeric overflow at line " << line_number(), false );
199
200 return true;
201 }
202
203 bool FileTokenizer::get_integer_internal( int& result )
204 {
205 long i;
206 if( !get_long_int_internal( i ) ) return false;
207
208 result = (int)i;
209 if( i != (long)result ) MB_SET_ERR_RET_VAL( "Numeric overflow at line " << line_number(), false );
210
211 return true;
212 }
213
214 bool FileTokenizer::get_boolean_internal( bool& result )
215 {
216
217 const char* token = get_string();
218 if( !token ) return false;
219
220 if( token[1] || ( token[0] != '0' && token[0] != '1' ) )
221 MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected 0 or 1, got \"" << token << "\"",
222 false );
223
224 result = token[0] == '1';
225
226 return true;
227 }
228
229 bool FileTokenizer::get_floats( size_t count, float* array )
230 {
231 for( size_t i = 0; i < count; ++i )
232 {
233 if( !get_float_internal( *array ) ) return false;
234 ++array;
235 }
236
237 return true;
238 }
239
240 bool FileTokenizer::get_doubles( size_t count, double* array )
241 {
242 for( size_t i = 0; i < count; ++i )
243 {
244 if( !get_double_internal( *array ) ) return false;
245 ++array;
246 }
247
248 return true;
249 }
250
251 bool FileTokenizer::get_bytes( size_t count, unsigned char* array )
252 {
253 for( size_t i = 0; i < count; ++i )
254 {
255 if( !get_byte_internal( *array ) ) return false;
256 ++array;
257 }
258
259 return true;
260 }
261
262 bool FileTokenizer::get_short_ints( size_t count, short* array )
263 {
264 for( size_t i = 0; i < count; ++i )
265 {
266 if( !get_short_int_internal( *array ) ) return false;
267 ++array;
268 }
269
270 return true;
271 }
272
273 bool FileTokenizer::get_integers( size_t count, int* array )
274 {
275 for( size_t i = 0; i < count; ++i )
276 {
277 if( !get_integer_internal( *array ) ) return false;
278 ++array;
279 }
280
281 return true;
282 }
283
284 bool FileTokenizer::get_long_ints( size_t count, long* array )
285 {
286 for( size_t i = 0; i < count; ++i )
287 {
288 if( !get_long_int_internal( *array ) ) return false;
289 ++array;
290 }
291
292 return true;
293 }
294
295 bool FileTokenizer::get_booleans( size_t count, bool* array )
296 {
297 for( size_t i = 0; i < count; ++i )
298 {
299 if( !get_boolean_internal( *array ) ) return false;
300 ++array;
301 }
302
303 return true;
304 }
305
306 void FileTokenizer::unget_token()
307 {
308 if( nextToken - buffer < 2 ) return;
309
310 --nextToken;
311 *nextToken = lastChar;
312 --nextToken;
313 while( nextToken > buffer && *nextToken )
314 --nextToken;
315
316 if( !*nextToken ) ++nextToken;
317
318 lastChar = '\0';
319 }
320
321 bool FileTokenizer::match_token( const char* str, bool print_error )
322 {
323
324 const char* token = get_string();
325 if( !token ) return false;
326
327
328 if( 0 == strcmp( token, str ) ) return true;
329
330
331 if( print_error )
332 MB_SET_ERR_CONT( "Syntax error at line " << line_number() << ": expected \"" << str << "\", got \"" << token
333 << "\"" );
334
335 return false;
336 }
337
338 int FileTokenizer::match_token( const char* const* list, bool print_error )
339 {
340
341 const char* token = get_string();
342 if( !token ) return 0;
343
344
345 const char* const* ptr;
346 for( ptr = list; *ptr; ++ptr )
347 {
348 if( 0 == strcmp( token, *ptr ) ) return ptr - list + 1;
349 }
350
351 if( !print_error ) return 0;
352
353
354 std::string message( "Parsing error at line " );
355 char lineno[16];
356 snprintf( lineno, 16, "%d", line_number() );
357 message += lineno;
358 message += ": expected one of {";
359 for( ptr = list; *ptr; ++ptr )
360 {
361 message += " ";
362 message += *ptr;
363 }
364 message += " } got \"";
365 message += token;
366 message += "\"";
367 MB_SET_ERR_CONT( message.c_str() );
368
369 return 0;
370 }
371
372 bool FileTokenizer::get_newline( bool report_error )
373 {
374 if( lastChar == '\n' )
375 {
376 lastChar = ' ';
377 ++lineNumber;
378 return true;
379 }
380
381
382
383 for( ;; )
384 {
385
386 if( nextToken == bufferEnd )
387 {
388 size_t count = fread( buffer, 1, sizeof( buffer ), filePtr );
389 if( 0 == count )
390 {
391 if( eof() )
392 MB_SET_ERR_RET_VAL( "File truncated at line " << line_number(), false );
393 else
394 MB_SET_ERR_RET_VAL( "I/O Error", false );
395 }
396
397 nextToken = buffer;
398 bufferEnd = buffer + count;
399 }
400
401
402 if( !isspace( *nextToken ) )
403 if( report_error ) MB_SET_ERR_RET_VAL( "Expected newline at line " << line_number(), false );
404
405
406
407 if( *nextToken == '\n' )
408 {
409 ++lineNumber;
410 ++nextToken;
411 lastChar = ' ';
412 return true;
413 }
414 ++nextToken;
415 }
416
417 return false;
418 }
419
420 bool FileTokenizer::get_binary( size_t size, void* mem )
421 {
422
423 if( nextToken != bufferEnd )
424 {
425
426
427 if( bufferEnd - nextToken <= (int)size )
428 {
429 memcpy( mem, nextToken, size );
430 nextToken += size;
431 return true;
432 }
433
434
435 memcpy( mem, nextToken, bufferEnd - nextToken );
436 size -= bufferEnd - nextToken;
437 mem = reinterpret_cast< char* >( mem ) + ( bufferEnd - nextToken );
438 nextToken = bufferEnd;
439 }
440
441
442 return size == fread( mem, 1, size, filePtr );
443 }
444
445 }