![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /**
00002 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
00003 * storing and accessing finite element mesh data.
00004 *
00005 * Copyright 2004 Sandia Corporation. Under the terms of Contract
00006 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
00007 * retains certain rights in this software.
00008 *
00009 * This library is free software; you can redistribute it and/or
00010 * modify it under the terms of the GNU Lesser General Public
00011 * License as published by the Free Software Foundation; either
00012 * version 2.1 of the License, or (at your option) any later version.
00013 *
00014 */
00015
00016 #include "FileTokenizer.hpp"
00017 #include "moab/ReadUtilIface.hpp"
00018 #include "moab/ErrorHandler.hpp"
00019
00020 #include
00021 #include
00022 #include
00023 #include
00024
00025 namespace moab
00026 {
00027
00028 using namespace std;
00029
00030 FileTokenizer::FileTokenizer( FILE* file_ptr, ReadUtilIface* )
00031 : filePtr( file_ptr ), nextToken( buffer ), bufferEnd( buffer ), lineNumber( 1 ), lastChar( '\0' )
00032 {
00033 }
00034
00035 FileTokenizer::~FileTokenizer()
00036 {
00037 fclose( filePtr );
00038 }
00039
00040 bool FileTokenizer::eof() const
00041 {
00042 return nextToken == bufferEnd && feof( filePtr );
00043 }
00044
00045 const char* FileTokenizer::get_string()
00046 {
00047 // If the whitespace character marking the end of the
00048 // last token was a newline, increment the line count.
00049 if( lastChar == '\n' ) ++lineNumber;
00050
00051 // Loop until either found the start of a token to return or have
00052 // reached the end of the file.
00053 for( ;; )
00054 {
00055 // If the buffer is empty, read more.
00056 if( nextToken == bufferEnd )
00057 {
00058 size_t count = fread( buffer, 1, sizeof( buffer ) - 1, filePtr );
00059 if( 0 == count )
00060 {
00061 if( feof( filePtr ) )
00062 return NULL;
00063 else
00064 MB_SET_ERR_RET_VAL( "I/O Error", NULL );
00065 }
00066
00067 nextToken = buffer;
00068 bufferEnd = buffer + count;
00069 }
00070
00071 // If the current character is not a space, we've found a token.
00072 if( !isspace( *nextToken ) ) break;
00073
00074 // If the current space character is a newline,
00075 // increment the line number count.
00076 if( *nextToken == '\n' ) ++lineNumber;
00077 ++nextToken;
00078 }
00079
00080 // Store the start of the token in "result" and
00081 // advance "nextToken" to one past the end of the
00082 // token.
00083 char* result = nextToken;
00084 while( nextToken != bufferEnd && !isspace( static_cast< unsigned char >( *nextToken ) ) )
00085 ++nextToken;
00086
00087 // If we have reached the end of the buffer without finding
00088 // a whitespace character terminating the token, we need to
00089 // read more from the file. Only try once. If the token is
00090 // too large to fit in the buffer, give up.
00091 if( nextToken == bufferEnd )
00092 {
00093 // Shift the (possibly) partial token to the start of the buffer.
00094 size_t remaining = bufferEnd - result;
00095 memmove( buffer, result, remaining );
00096 result = buffer;
00097 nextToken = result + remaining;
00098
00099 // Fill the remainder of the buffer after the token.
00100 size_t count = fread( nextToken, 1, sizeof( buffer ) - remaining - 1, filePtr );
00101 if( 0 == count && !feof( filePtr ) ) MB_SET_ERR_RET_VAL( "I/O Error", NULL );
00102 bufferEnd = nextToken + count;
00103
00104 // Continue to advance nextToken until we find the space
00105 // terminating the token.
00106 while( nextToken != bufferEnd && !isspace( *nextToken ) )
00107 ++nextToken;
00108
00109 if( nextToken == bufferEnd )
00110 { // EOF
00111 *bufferEnd = '\0';
00112 ++bufferEnd;
00113 }
00114 }
00115
00116 // Save terminating whitespace character (or NULL char if EOF).
00117 lastChar = *nextToken;
00118 // Put null in buffer to mark end of current token.
00119 *nextToken = '\0';
00120 // Advance nextToken to the next character to search next time.
00121 ++nextToken;
00122
00123 return result;
00124 }
00125
00126 bool FileTokenizer::get_double_internal( double& result )
00127 {
00128 // Get a token
00129 const char *token_end, *token = get_string();
00130 if( !token ) return false;
00131
00132 // Check for hex value -- on some platforms (e.g. Linux), strtod
00133 // will accept hex values, on others (e.g. Sun) it will not. Force
00134 // failure on hex numbers for consistency.
00135 if( token[0] && token[1] && token[0] == '0' && toupper( token[1] ) == 'X' )
00136 MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected number, got \"" << token << "\"",
00137 false );
00138
00139 // Parse token as double
00140 result = strtod( token, (char**)&token_end );
00141
00142 // If the one past the last char read by strtod is
00143 // not the NULL character terminating the string,
00144 // then parse failed.
00145 if( *token_end )
00146 MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected number, got \"" << token << "\"",
00147 false );
00148
00149 return true;
00150 }
00151
00152 bool FileTokenizer::get_float_internal( float& result )
00153 {
00154 double d;
00155 if( !get_double_internal( d ) ) return false;
00156
00157 result = (float)d;
00158
00159 return true;
00160 }
00161
00162 bool FileTokenizer::get_long_int_internal( long& result )
00163 {
00164 // Get a token
00165 const char *token_end, *token = get_string();
00166 if( !token ) return false;
00167
00168 // Parse token as long
00169 result = strtol( token, (char**)&token_end, 0 );
00170
00171 // If the one past the last char read by strtol is
00172 // not the NULL character terminating the string,
00173 // then parse failed.
00174 if( *token_end )
00175 MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected number, got \"" << token << "\"",
00176 false );
00177
00178 return true;
00179 }
00180
00181 bool FileTokenizer::get_byte_internal( unsigned char& result )
00182 {
00183 long i;
00184 if( !get_long_int_internal( i ) ) return false;
00185
00186 result = (unsigned char)i;
00187 if( i != (long)result ) MB_SET_ERR_RET_VAL( "Numeric overflow at line " << line_number(), false );
00188
00189 return true;
00190 }
00191
00192 bool FileTokenizer::get_short_int_internal( short& result )
00193 {
00194 long i;
00195 if( !get_long_int_internal( i ) ) return false;
00196
00197 result = (short)i;
00198 if( i != (long)result ) MB_SET_ERR_RET_VAL( "Numeric overflow at line " << line_number(), false );
00199
00200 return true;
00201 }
00202
00203 bool FileTokenizer::get_integer_internal( int& result )
00204 {
00205 long i;
00206 if( !get_long_int_internal( i ) ) return false;
00207
00208 result = (int)i;
00209 if( i != (long)result ) MB_SET_ERR_RET_VAL( "Numeric overflow at line " << line_number(), false );
00210
00211 return true;
00212 }
00213
00214 bool FileTokenizer::get_boolean_internal( bool& result )
00215 {
00216 // Get a token
00217 const char* token = get_string();
00218 if( !token ) return false;
00219
00220 if( token[1] || ( token[0] != '0' && token[0] != '1' ) )
00221 MB_SET_ERR_RET_VAL( "Syntax error at line " << line_number() << ": expected 0 or 1, got \"" << token << "\"",
00222 false );
00223
00224 result = token[0] == '1';
00225
00226 return true;
00227 }
00228
00229 bool FileTokenizer::get_floats( size_t count, float* array )
00230 {
00231 for( size_t i = 0; i < count; ++i )
00232 {
00233 if( !get_float_internal( *array ) ) return false;
00234 ++array;
00235 }
00236
00237 return true;
00238 }
00239
00240 bool FileTokenizer::get_doubles( size_t count, double* array )
00241 {
00242 for( size_t i = 0; i < count; ++i )
00243 {
00244 if( !get_double_internal( *array ) ) return false;
00245 ++array;
00246 }
00247
00248 return true;
00249 }
00250
00251 bool FileTokenizer::get_bytes( size_t count, unsigned char* array )
00252 {
00253 for( size_t i = 0; i < count; ++i )
00254 {
00255 if( !get_byte_internal( *array ) ) return false;
00256 ++array;
00257 }
00258
00259 return true;
00260 }
00261
00262 bool FileTokenizer::get_short_ints( size_t count, short* array )
00263 {
00264 for( size_t i = 0; i < count; ++i )
00265 {
00266 if( !get_short_int_internal( *array ) ) return false;
00267 ++array;
00268 }
00269
00270 return true;
00271 }
00272
00273 bool FileTokenizer::get_integers( size_t count, int* array )
00274 {
00275 for( size_t i = 0; i < count; ++i )
00276 {
00277 if( !get_integer_internal( *array ) ) return false;
00278 ++array;
00279 }
00280
00281 return true;
00282 }
00283
00284 bool FileTokenizer::get_long_ints( size_t count, long* array )
00285 {
00286 for( size_t i = 0; i < count; ++i )
00287 {
00288 if( !get_long_int_internal( *array ) ) return false;
00289 ++array;
00290 }
00291
00292 return true;
00293 }
00294
00295 bool FileTokenizer::get_booleans( size_t count, bool* array )
00296 {
00297 for( size_t i = 0; i < count; ++i )
00298 {
00299 if( !get_boolean_internal( *array ) ) return false;
00300 ++array;
00301 }
00302
00303 return true;
00304 }
00305
00306 void FileTokenizer::unget_token()
00307 {
00308 if( nextToken - buffer < 2 ) return;
00309
00310 --nextToken;
00311 *nextToken = lastChar;
00312 --nextToken;
00313 while( nextToken > buffer && *nextToken )
00314 --nextToken;
00315
00316 if( !*nextToken ) ++nextToken;
00317
00318 lastChar = '\0';
00319 }
00320
00321 bool FileTokenizer::match_token( const char* str, bool print_error )
00322 {
00323 // Get a token
00324 const char* token = get_string();
00325 if( !token ) return false;
00326
00327 // Check if it matches
00328 if( 0 == strcmp( token, str ) ) return true;
00329
00330 // Construct error message
00331 if( print_error )
00332 MB_SET_ERR_CONT( "Syntax error at line " << line_number() << ": expected \"" << str << "\", got \"" << token
00333 << "\"" );
00334
00335 return false;
00336 }
00337
00338 int FileTokenizer::match_token( const char* const* list, bool print_error )
00339 {
00340 // Get a token
00341 const char* token = get_string();
00342 if( !token ) return 0;
00343
00344 // Check if it matches any input string
00345 const char* const* ptr;
00346 for( ptr = list; *ptr; ++ptr )
00347 {
00348 if( 0 == strcmp( token, *ptr ) ) return ptr - list + 1;
00349 }
00350
00351 if( !print_error ) return 0;
00352
00353 // No match, constuct error message
00354 std::string message( "Parsing error at line " );
00355 char lineno[16];
00356 sprintf( lineno, "%d", line_number() );
00357 message += lineno;
00358 message += ": expected one of {";
00359 for( ptr = list; *ptr; ++ptr )
00360 {
00361 message += " ";
00362 message += *ptr;
00363 }
00364 message += " } got \"";
00365 message += token;
00366 message += "\"";
00367 MB_SET_ERR_CONT( message.c_str() );
00368
00369 return 0;
00370 }
00371
00372 bool FileTokenizer::get_newline( bool report_error )
00373 {
00374 if( lastChar == '\n' )
00375 {
00376 lastChar = ' ';
00377 ++lineNumber;
00378 return true;
00379 }
00380
00381 // Loop until either we a) find a newline, b) find a non-whitespace
00382 // character or c) reach the end of the file.
00383 for( ;; )
00384 {
00385 // If the buffer is empty, read more.
00386 if( nextToken == bufferEnd )
00387 {
00388 size_t count = fread( buffer, 1, sizeof( buffer ), filePtr );
00389 if( 0 == count )
00390 {
00391 if( eof() )
00392 MB_SET_ERR_RET_VAL( "File truncated at line " << line_number(), false );
00393 else
00394 MB_SET_ERR_RET_VAL( "I/O Error", false );
00395 }
00396
00397 nextToken = buffer;
00398 bufferEnd = buffer + count;
00399 }
00400
00401 // If the current character is not a space, the we've failed.
00402 if( !isspace( *nextToken ) )
00403 if( report_error ) MB_SET_ERR_RET_VAL( "Expected newline at line " << line_number(), false );
00404
00405 // If the current space character is a newline,
00406 // increment the line number count.
00407 if( *nextToken == '\n' )
00408 {
00409 ++lineNumber;
00410 ++nextToken;
00411 lastChar = ' ';
00412 return true;
00413 }
00414 ++nextToken;
00415 }
00416
00417 return false;
00418 }
00419
00420 bool FileTokenizer::get_binary( size_t size, void* mem )
00421 {
00422 // If data in buffer
00423 if( nextToken != bufferEnd )
00424 {
00425 // If requested size is less than buffer contents,
00426 // just pass back part of the buffer
00427 if( bufferEnd - nextToken <= (int)size )
00428 {
00429 memcpy( mem, nextToken, size );
00430 nextToken += size;
00431 return true;
00432 }
00433
00434 // Copy buffer contents into memory and clear buffer
00435 memcpy( mem, nextToken, bufferEnd - nextToken );
00436 size -= bufferEnd - nextToken;
00437 mem = reinterpret_cast< char* >( mem ) + ( bufferEnd - nextToken );
00438 nextToken = bufferEnd;
00439 }
00440
00441 // Read any additional data from file
00442 return size == fread( mem, 1, size, filePtr );
00443 }
00444
00445 } // namespace moab