Thread: Check for missing EOF

  1. #1
    Registered User
    Join Date
    Sep 2004
    Posts
    13

    Check for missing EOF

    Is it possible to check for a missing EOF?

    I have a program that uses data files to store data and it reads and writes from the files with no problems at all, however I occassionally get an issue if the program is killed whilst writing out a data file this results in the EOF never being written and the program effectively getting stuck the next time it attempts to read in the file.

    I create backup files and I do various checks on the data files to make sure they contain valid fields and automatically restore back the last good version if a problem is found, but the problem I have is that these checks also cause the program to enter the loop when the EOF is missing.

    The datafiles can be anywhere from a few bytes to hundreds of megabytes in size, so I cannot rely on a counter to break me out of the loop at a fixed point as this could still only be part of the way through a large file.

    Any ideas on how best to check for this error would be greatly appreciated.

  2. #2
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    EOF is unlikely to actually be "missing". The file will end somewhere, the OS will recognise that, maybe your app won't.

    What kind of data are we talking here, binary (ie structs etc), or text (like regular lines).

    Of course, the best way to get round it is to not let your app die uncontrollably in the first place

    Care to show some code for the read and write parts?
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  3. #3
    Registered User
    Join Date
    Sep 2004
    Posts
    13
    The datafiles only contain ascii data, here is the code I have to read in each item from a data file:
    Code:
    void *read_next_item( FILE *fp, int *status )
    {
        char *word;
        void *value = NULL;
        int letter, errstatus;
    
        do      // while( !value )
        {
            letter = fread_letter( fp );
            if( letter == EOF )
            {
                *status = -1;
                return status;
            }
            while( letter == '#' )
            {
                fread_to_eol( fp );
                letter = fread_letter( fp );
                if( letter == EOF )
                {
                    *status = -1;
                    return status;
                }
            }
    
            ungetc( letter, fp );
            word = fread_word( fp, &errstatus );
    
            if( errstatus )
            {
                *status = -1;
                return NULL;
            }
    
            if( !str_cmp( word, "eof" ) || !str_cmp( word, "end" )
                    || !str_cmp( word, "eof;" ) || !str_cmp( word, "end;" ) )
            {
                *status = -1;
                return status;
            }
            else if( !str_cmp( word, "-Version" ) )
            {
                errstatus = (int)!fread_number_ii( fp, &file_version, NULL );
                if( errstatus )
                    return NULL;
            }
            else if( !str_cmp( word, "-Date" ) )
            {
                file_date = fread_time( fp, &errstatus );
                if( errstatus )
                    return NULL;
            }
            else
            {
                *status = get_top_entry( word );
    
                if( global_data_table[*status].name == NULL )
                {
                    bug( "Read unknown section header: %s", word );
                    return NULL;
                }
    
                value = load_complex_block( fp, global_data_table + *status );
                if( !value )
                {
                    bug( "read_next_item: error reading item" );
                    return NULL;
                }
            }
    
            if( ( letter = fread_letter( fp ) != ';' ) )
            {
                if( letter == EOF )
                    bug( "read_next_item: EOF reached early." );
                else
                    bug( "read_next_item: missing ';' character." );
                return NULL;
            }
    
        }
        while( !value );
    
        return value;
    }
    The fread_word function follows:
    Code:
    char *fread_word( FILE *fp, int *status )
    {
        static char word[MAX_INPUT_LENGTH];
        char *pword;
        char cEnd;
    
        *status = 0;
    
        do
        {
            if( feof( fp ) )
            {
                bug( "fread_word: EOF encountered on read.\n\r" );
                if( fBootDb )
                    exit( 1 );
                return &str_empty[0];
            }
            cEnd = getc( fp );
        }
        while( isspace( cEnd ) );
    
        if( cEnd == '\'' || cEnd == '"' )
        {
            pword = word;
        }
        else
        {
            word[0] = cEnd;
            pword = word + 1;
            cEnd = ' ';
        }
    
        for( ; pword < word + MAX_INPUT_LENGTH; pword++ )
        {
            int c = getc( fp );
            if( c == EOF )
            {
                bug( "fread_word: returned EOF." );
                *pword = '\0';
                return word;
            }
            *pword = c;
            if( cEnd == ' ' ? isspace( *pword ) : *pword == cEnd )
            {
                if( cEnd == ' ' )
                    ungetc( *pword, fp );
                *pword = '\0';
                return word;
            }
        }
    
        bug( "Fread_word: word too long." );
        *status = 1;
        return NULL;
    }
    And also fread_letter:
    Code:
    // Read a letter from a file.
    int fread_letter( FILE *fp )
    {
        int c;
    
        do
        {
            if( feof( fp ) )
            {
                bug( "fread_letter: EOF encountered on read.\n\r" );
                if( fBootDb )
                    exit( 1 );
                return '#';
            }
            c = getc( fp );
        }
        while( isspace( c ) );
    
        return c;
    }
    There is quite a lot of other additional code for reading other data types as well but I have checked these and I believe they all check for EOF characters.

  4. #4
    Registered User
    Join Date
    Sep 2004
    Posts
    13
    I have just tried a test using a corrupt file I have saved off last time the program was terminated abnormally during a write.

    Firstly I tried to start the program with the corrupt file and it hangs running at 100% CPU till I kill it again.

    I then loaded the file into vi, and made no changes other than to save the file and exit.

    After saving the file I tried to start the program again and this time it successfully errored saying that the file is corrupt before stopping normally.

  5. #5
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    And where's the code for fread_to_eol()?
    If you understand what you're doing, you're not learning anything.

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    What you're proposing doesn't even make sense. If vi can find EOF, then it's obviously there. If it didnt, then it would also crash. Therefore, your file must in fact contain EOF.

    Quzah.
    Hope is the first step on the road to disappointment.

  7. #7
    Registered User
    Join Date
    Sep 2004
    Posts
    13
    The code for fread_to_eol:
    Code:
    void fread_to_eol( FILE *fp )
    {
        int c;
    
        do
        {
            if( feof( fp ) )
            {
                bug( "fread_to_eol: EOF encountered on read.\n\r" );
                if( fBootDb )
                    exit( 1 );
                return;
            }
            c = getc( fp );
        }
        while( c != '\n' && c != '\r' && c != EOF );
    
        do
        {
            if( feof( fp ) )
            {
                bug( "fread_to_eol: EOF encountered on read.\n\r" );
                if( fBootDb )
                    exit( 1 );
                return;
            }
            c = getc( fp );
        }
        while( c == '\n' || c == '\r' );
    
        ungetc( c, fp );
        return;
    }

  8. #8
    Registered User
    Join Date
    Sep 2004
    Posts
    13
    Quote Originally Posted by quzah
    What you're proposing doesn't even make sense. If vi can find EOF, then it's obviously there. If it didnt, then it would also crash. Therefore, your file must in fact contain EOF.

    Quzah.
    I know, this is why I am confused the only thing I could think of was that vi must have code to handle files that do not end on '\0'.
    Is it possible that vi checks the length of the file given by the operating system and appends its own '\0' if it is missing from the file? Then when I save the file back out of vi the '\0' is saved with it?

  9. #9
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    '\0' is not EOF. EOF is nothing that can be stored in a single character. '\0' is a null character, which is perfectly valid in any binary file.

    Try something like this:
    Code:
    #include <stdio.h>
    
    int main( void )
    {
        int c;
        FILE *fp = fopen( yourfilename, "r" );
    
        if( fp )
        {
            while( (c = fgetc( fp )) != EOF )
            {
                printf("Read %c, %d\n", c, c );
            }
    
            fclose( fp );
            printf("EOF reached, file now closed.\n");
        }
        return 0;
    }
    Run your file through that.

    Quzah.
    Hope is the first step on the road to disappointment.

  10. #10
    Registered User
    Join Date
    Sep 2004
    Posts
    13
    Thanks for the help Quzah as always your advise is spot on.

    I have compiled and run the program and it does correctly detect the EOF.

    Guess it is time to try running my code through gdb to see if I can work out how the EOF marker is slipping through.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Check for EOF when using fgets
    By daghenningsorbo in forum C Programming
    Replies: 6
    Last Post: 05-16-2007, 06:48 PM
  2. Check application visibility
    By 3saul in forum Linux Programming
    Replies: 2
    Last Post: 02-13-2006, 05:13 PM
  3. EOF messing up my input stream?
    By Decrypt in forum C++ Programming
    Replies: 4
    Last Post: 09-30-2005, 03:00 PM
  4. files won't stop being read!!!
    By jverkoey in forum C++ Programming
    Replies: 15
    Last Post: 04-10-2003, 05:28 AM
  5. Check for EOF
    By Natase in forum C Programming
    Replies: 6
    Last Post: 09-20-2001, 11:42 AM