Branch data Line data Source code
1 : : /**
2 : : * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3 : : * storing and accessing finite element mesh data.
4 : : *
5 : : * Copyright 2004 Sandia Corporation. Under the terms of Contract
6 : : * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7 : : * retains certain rights in this software.
8 : : *
9 : : * This library is free software; you can redistribute it and/or
10 : : * modify it under the terms of the GNU Lesser General Public
11 : : * License as published by the Free Software Foundation; either
12 : : * version 2.1 of the License, or (at your option) any later version.
13 : : *
14 : : */
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 : 25 : FileTokenizer::FileTokenizer( FILE* file_ptr, ReadUtilIface* )
31 : 25 : : filePtr( file_ptr ), nextToken( buffer ), bufferEnd( buffer ), lineNumber( 1 ), lastChar( '\0' )
32 : : {
33 : 25 : }
34 : :
35 : 25 : FileTokenizer::~FileTokenizer()
36 : : {
37 : 25 : fclose( filePtr );
38 : 25 : }
39 : :
40 : 85 : bool FileTokenizer::eof() const
41 : : {
42 [ + + ][ + - ]: 85 : return nextToken == bufferEnd && feof( filePtr );
43 : : }
44 : :
45 : 93876 : const char* FileTokenizer::get_string()
46 : : {
47 : : // If the whitespace character marking the end of the
48 : : // last token was a newline, increment the line count.
49 [ + + ]: 93876 : if( lastChar == '\n' ) ++lineNumber;
50 : :
51 : : // Loop until either found the start of a token to return or have
52 : : // reached the end of the file.
53 : : for( ;; )
54 : : {
55 : : // If the buffer is empty, read more.
56 [ + + ]: 139391 : if( nextToken == bufferEnd )
57 : : {
58 : 205 : size_t count = fread( buffer, 1, sizeof( buffer ) - 1, filePtr );
59 [ + + ]: 205 : if( 0 == count )
60 : : {
61 [ + - ]: 9 : if( feof( filePtr ) )
62 : 9 : return NULL;
63 : : else
64 [ # # ][ # # ]: 0 : MB_SET_ERR_RET_VAL( "I/O Error", NULL );
[ # # ][ # # ]
[ # # ]
65 : : }
66 : :
67 : 196 : nextToken = buffer;
68 : 196 : bufferEnd = buffer + count;
69 : : }
70 : :
71 : : // If the current character is not a space, we've found a token.
72 [ + + ]: 139382 : if( !isspace( *nextToken ) ) break;
73 : :
74 : : // If the current space character is a newline,
75 : : // increment the line number count.
76 [ + + ]: 45515 : if( *nextToken == '\n' ) ++lineNumber;
77 : 45515 : ++nextToken;
78 : 45515 : }
79 : :
80 : : // Store the start of the token in "result" and
81 : : // advance "nextToken" to one past the end of the
82 : : // token.
83 : 93867 : char* result = nextToken;
84 [ + + ][ + + ]: 516158 : while( nextToken != bufferEnd && !isspace( static_cast< unsigned char >( *nextToken ) ) )
85 : 422291 : ++nextToken;
86 : :
87 : : // If we have reached the end of the buffer without finding
88 : : // a whitespace character terminating the token, we need to
89 : : // read more from the file. Only try once. If the token is
90 : : // too large to fit in the buffer, give up.
91 [ + + ]: 93867 : if( nextToken == bufferEnd )
92 : : {
93 : : // Shift the (possibly) partial token to the start of the buffer.
94 : 947 : size_t remaining = bufferEnd - result;
95 : 947 : memmove( buffer, result, remaining );
96 : 947 : result = buffer;
97 : 947 : nextToken = result + remaining;
98 : :
99 : : // Fill the remainder of the buffer after the token.
100 : 947 : size_t count = fread( nextToken, 1, sizeof( buffer ) - remaining - 1, filePtr );
101 [ + + ][ - + ]: 947 : if( 0 == count && !feof( filePtr ) ) MB_SET_ERR_RET_VAL( "I/O Error", NULL );
[ - + ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
102 : 947 : bufferEnd = nextToken + count;
103 : :
104 : : // Continue to advance nextToken until we find the space
105 : : // terminating the token.
106 [ + + ][ + + ]: 7850 : while( nextToken != bufferEnd && !isspace( *nextToken ) )
107 : 6903 : ++nextToken;
108 : :
109 [ + + ]: 947 : if( nextToken == bufferEnd )
110 : : { // EOF
111 : 10 : *bufferEnd = '\0';
112 : 947 : ++bufferEnd;
113 : : }
114 : : }
115 : :
116 : : // Save terminating whitespace character (or NULL char if EOF).
117 : 93867 : lastChar = *nextToken;
118 : : // Put null in buffer to mark end of current token.
119 : 93867 : *nextToken = '\0';
120 : : // Advance nextToken to the next character to search next time.
121 : 93867 : ++nextToken;
122 : :
123 : 93876 : return result;
124 : : }
125 : :
126 : 21667 : bool FileTokenizer::get_double_internal( double& result )
127 : : {
128 : : // Get a token
129 [ + - ]: 21667 : const char *token_end, *token = get_string();
130 [ - + ]: 21667 : if( !token ) return false;
131 : :
132 : : // Check for hex value -- on some platforms (e.g. Linux), strtod
133 : : // will accept hex values, on others (e.g. Sun) it will not. Force
134 : : // failure on hex numbers for consistency.
135 [ + - ][ + + ]: 21667 : if( token[0] && token[1] && token[0] == '0' && toupper( token[1] ) == 'X' )
[ + + ][ - + ]
136 [ # # ][ # # ]: 0 : MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected number, got \"" << token << "\"",
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
137 : : false );
138 : :
139 : : // Parse token as double
140 : 21667 : result = strtod( token, (char**)&token_end );
141 : :
142 : : // If the one past the last char read by strtod is
143 : : // not the NULL character terminating the string,
144 : : // then parse failed.
145 [ - + ]: 21667 : if( *token_end )
146 [ # # ][ # # ]: 0 : MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected number, got \"" << token << "\"",
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
147 : : false );
148 : :
149 : 21667 : return true;
150 : : }
151 : :
152 : 0 : bool FileTokenizer::get_float_internal( float& result )
153 : : {
154 : : double d;
155 [ # # ][ # # ]: 0 : if( !get_double_internal( d ) ) return false;
156 : :
157 : 0 : result = (float)d;
158 : :
159 : 0 : return true;
160 : : }
161 : :
162 : 71865 : bool FileTokenizer::get_long_int_internal( long& result )
163 : : {
164 : : // Get a token
165 [ + - ]: 71865 : const char *token_end, *token = get_string();
166 [ - + ]: 71865 : if( !token ) return false;
167 : :
168 : : // Parse token as long
169 : 71865 : result = strtol( token, (char**)&token_end, 0 );
170 : :
171 : : // If the one past the last char read by strtol is
172 : : // not the NULL character terminating the string,
173 : : // then parse failed.
174 [ - + ]: 71865 : if( *token_end )
175 [ # # ][ # # ]: 0 : MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected number, got \"" << token << "\"",
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
176 : : false );
177 : :
178 : 71865 : return true;
179 : : }
180 : :
181 : 0 : bool FileTokenizer::get_byte_internal( unsigned char& result )
182 : : {
183 : : long i;
184 [ # # ][ # # ]: 0 : if( !get_long_int_internal( i ) ) return false;
185 : :
186 : 0 : result = (unsigned char)i;
187 [ # # ][ # # ]: 0 : if( i != (long)result ) MB_SET_ERR_RET_VAL( "Numeric overflow at line " << line_number(), false );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
188 : :
189 : 0 : return true;
190 : : }
191 : :
192 : 0 : bool FileTokenizer::get_short_int_internal( short& result )
193 : : {
194 : : long i;
195 [ # # ][ # # ]: 0 : if( !get_long_int_internal( i ) ) return false;
196 : :
197 : 0 : result = (short)i;
198 [ # # ][ # # ]: 0 : if( i != (long)result ) MB_SET_ERR_RET_VAL( "Numeric overflow at line " << line_number(), false );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
199 : :
200 : 0 : return true;
201 : : }
202 : :
203 : 2489 : bool FileTokenizer::get_integer_internal( int& result )
204 : : {
205 : : long i;
206 [ + - ][ - + ]: 2489 : if( !get_long_int_internal( i ) ) return false;
207 : :
208 : 2489 : result = (int)i;
209 [ - + ][ # # ]: 2489 : if( i != (long)result ) MB_SET_ERR_RET_VAL( "Numeric overflow at line " << line_number(), false );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
210 : :
211 : 2489 : return true;
212 : : }
213 : :
214 : 0 : bool FileTokenizer::get_boolean_internal( bool& result )
215 : : {
216 : : // Get a token
217 : 0 : const char* token = get_string();
218 [ # # ]: 0 : if( !token ) return false;
219 : :
220 [ # # ][ # # ]: 0 : if( token[1] || ( token[0] != '0' && token[0] != '1' ) )
[ # # ]
221 [ # # ][ # # ]: 0 : MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected 0 or 1, got \"" << token << "\"",
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
222 : : false );
223 : :
224 : 0 : result = token[0] == '1';
225 : :
226 : 0 : return true;
227 : : }
228 : :
229 : 0 : bool FileTokenizer::get_floats( size_t count, float* array )
230 : : {
231 [ # # ]: 0 : for( size_t i = 0; i < count; ++i )
232 : : {
233 [ # # ]: 0 : if( !get_float_internal( *array ) ) return false;
234 : 0 : ++array;
235 : : }
236 : :
237 : 0 : return true;
238 : : }
239 : :
240 : 18113 : bool FileTokenizer::get_doubles( size_t count, double* array )
241 : : {
242 [ + + ]: 39780 : for( size_t i = 0; i < count; ++i )
243 : : {
244 [ - + ]: 21667 : if( !get_double_internal( *array ) ) return false;
245 : 21667 : ++array;
246 : : }
247 : :
248 : 18113 : return true;
249 : : }
250 : :
251 : 0 : bool FileTokenizer::get_bytes( size_t count, unsigned char* array )
252 : : {
253 [ # # ]: 0 : for( size_t i = 0; i < count; ++i )
254 : : {
255 [ # # ]: 0 : if( !get_byte_internal( *array ) ) return false;
256 : 0 : ++array;
257 : : }
258 : :
259 : 0 : return true;
260 : : }
261 : :
262 : 0 : bool FileTokenizer::get_short_ints( size_t count, short* array )
263 : : {
264 [ # # ]: 0 : for( size_t i = 0; i < count; ++i )
265 : : {
266 [ # # ]: 0 : if( !get_short_int_internal( *array ) ) return false;
267 : 0 : ++array;
268 : : }
269 : :
270 : 0 : return true;
271 : : }
272 : :
273 : 22 : bool FileTokenizer::get_integers( size_t count, int* array )
274 : : {
275 [ + + ]: 2511 : for( size_t i = 0; i < count; ++i )
276 : : {
277 [ - + ]: 2489 : if( !get_integer_internal( *array ) ) return false;
278 : 2489 : ++array;
279 : : }
280 : :
281 : 22 : return true;
282 : : }
283 : :
284 : 114 : bool FileTokenizer::get_long_ints( size_t count, long* array )
285 : : {
286 [ + + ]: 69490 : for( size_t i = 0; i < count; ++i )
287 : : {
288 [ - + ]: 69376 : if( !get_long_int_internal( *array ) ) return false;
289 : 69376 : ++array;
290 : : }
291 : :
292 : 114 : return true;
293 : : }
294 : :
295 : 0 : bool FileTokenizer::get_booleans( size_t count, bool* array )
296 : : {
297 [ # # ]: 0 : for( size_t i = 0; i < count; ++i )
298 : : {
299 [ # # ]: 0 : if( !get_boolean_internal( *array ) ) return false;
300 : 0 : ++array;
301 : : }
302 : :
303 : 0 : return true;
304 : : }
305 : :
306 : 16 : void FileTokenizer::unget_token()
307 : : {
308 [ - + ]: 16 : if( nextToken - buffer < 2 ) return;
309 : :
310 : 16 : --nextToken;
311 : 16 : *nextToken = lastChar;
312 : 16 : --nextToken;
313 [ + - ][ + + ]: 144 : while( nextToken > buffer && *nextToken )
314 : 128 : --nextToken;
315 : :
316 [ + - ]: 16 : if( !*nextToken ) ++nextToken;
317 : :
318 : 16 : lastChar = '\0';
319 : : }
320 : :
321 : 96 : bool FileTokenizer::match_token( const char* str, bool print_error )
322 : : {
323 : : // Get a token
324 : 96 : const char* token = get_string();
325 [ - + ]: 96 : if( !token ) return false;
326 : :
327 : : // Check if it matches
328 [ + - ]: 96 : if( 0 == strcmp( token, str ) ) return true;
329 : :
330 : : // Construct error message
331 [ # # ]: 0 : if( print_error )
332 [ # # ][ # # ]: 0 : MB_SET_ERR_CONT( "Syntax error at line " << line_number() << ": expected \"" << str << "\", got \"" << token
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
333 : : << "\"" );
334 : :
335 : 96 : return false;
336 : : }
337 : :
338 : 200 : int FileTokenizer::match_token( const char* const* list, bool print_error )
339 : : {
340 : : // Get a token
341 [ + - ]: 200 : const char* token = get_string();
342 [ + + ]: 200 : if( !token ) return 0;
343 : :
344 : : // Check if it matches any input string
345 : : const char* const* ptr;
346 [ + + ]: 708 : for( ptr = list; *ptr; ++ptr )
347 : : {
348 [ + + ]: 691 : if( 0 == strcmp( token, *ptr ) ) return ptr - list + 1;
349 : : }
350 : :
351 [ + + ]: 17 : if( !print_error ) return 0;
352 : :
353 : : // No match, constuct error message
354 [ + - ]: 1 : std::string message( "Parsing error at line " );
355 : : char lineno[16];
356 [ + - ]: 1 : sprintf( lineno, "%d", line_number() );
357 [ + - ]: 1 : message += lineno;
358 [ + - ]: 1 : message += ": expected one of {";
359 [ + + ]: 3 : for( ptr = list; *ptr; ++ptr )
360 : : {
361 [ + - ]: 2 : message += " ";
362 [ + - ]: 2 : message += *ptr;
363 : : }
364 [ + - ]: 1 : message += " } got \"";
365 [ + - ]: 1 : message += token;
366 [ + - ]: 1 : message += "\"";
367 [ + - ][ + - ]: 1 : MB_SET_ERR_CONT( message.c_str() );
[ + - ][ - + ]
[ + - ]
368 : :
369 : 200 : return 0;
370 : : }
371 : :
372 : 72 : bool FileTokenizer::get_newline( bool report_error )
373 : : {
374 [ + + ]: 72 : if( lastChar == '\n' )
375 : : {
376 : 70 : lastChar = ' ';
377 : 70 : ++lineNumber;
378 : 70 : return true;
379 : : }
380 : :
381 : : // Loop until either we a) find a newline, b) find a non-whitespace
382 : : // character or c) reach the end of the file.
383 : : for( ;; )
384 : : {
385 : : // If the buffer is empty, read more.
386 [ - + ]: 2 : if( nextToken == bufferEnd )
387 : : {
388 : 0 : size_t count = fread( buffer, 1, sizeof( buffer ), filePtr );
389 [ # # ]: 0 : if( 0 == count )
390 : : {
391 [ # # ]: 0 : if( eof() )
392 [ # # ][ # # ]: 0 : MB_SET_ERR_RET_VAL( "File truncated at line " << line_number(), false );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
393 : : else
394 [ # # ][ # # ]: 0 : MB_SET_ERR_RET_VAL( "I/O Error", false );
[ # # ][ # # ]
[ # # ]
395 : : }
396 : :
397 : 0 : nextToken = buffer;
398 : 0 : bufferEnd = buffer + count;
399 : : }
400 : :
401 : : // If the current character is not a space, the we've failed.
402 [ - + ]: 2 : if( !isspace( *nextToken ) )
403 [ # # ][ # # ]: 0 : if( report_error ) MB_SET_ERR_RET_VAL( "Expected newline at line " << line_number(), false );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
404 : :
405 : : // If the current space character is a newline,
406 : : // increment the line number count.
407 [ + - ]: 2 : if( *nextToken == '\n' )
408 : : {
409 : 2 : ++lineNumber;
410 : 2 : ++nextToken;
411 : 2 : lastChar = ' ';
412 : 2 : return true;
413 : : }
414 : 0 : ++nextToken;
415 : 72 : }
416 : :
417 : : return false;
418 : : }
419 : :
420 : 0 : bool FileTokenizer::get_binary( size_t size, void* mem )
421 : : {
422 : : // If data in buffer
423 [ # # ]: 0 : if( nextToken != bufferEnd )
424 : : {
425 : : // If requested size is less than buffer contents,
426 : : // just pass back part of the buffer
427 [ # # ]: 0 : if( bufferEnd - nextToken <= (int)size )
428 : : {
429 : 0 : memcpy( mem, nextToken, size );
430 : 0 : nextToken += size;
431 : 0 : return true;
432 : : }
433 : :
434 : : // Copy buffer contents into memory and clear buffer
435 : 0 : memcpy( mem, nextToken, bufferEnd - nextToken );
436 : 0 : size -= bufferEnd - nextToken;
437 : 0 : mem = reinterpret_cast< char* >( mem ) + ( bufferEnd - nextToken );
438 : 0 : nextToken = bufferEnd;
439 : : }
440 : :
441 : : // Read any additional data from file
442 : 0 : return size == fread( mem, 1, size, filePtr );
443 : : }
444 : :
445 : : } // namespace moab
|