LCOV - code coverage report
Current view: top level - src/io - FileTokenizer.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 119 186 64.0 %
Date: 2020-12-16 07:07:30 Functions: 14 23 60.9 %
Branches: 91 388 23.5 %

           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

Generated by: LCOV version 1.11