Thread: wierd fstream problems...

  1. #1
    Work in Progress..... Jaken Veina's Avatar
    Join Date
    Mar 2005
    Location
    Missouri. Go Imos Pizza!
    Posts
    256

    wierd fstream problems...

    What I'm trying to do should be pretty self-explanatory from the code. Unfortunately, the code is extensive. Thanks in advance to anyone who's willing to give it a look.

    jake.settings.cpp
    Code:
    /******************************************************************************/
    /*   The Settings Class, by Jake Meiergerd
    /*    ~ C++ Implementation
    /*     AUTHOR:     Jake Meiergerd
    /*     VERSION:    1.0.0.1
    /*
    /*    FILE:  jake.settings.h
    /*       ~ Settings Class Implementation File
    /*       ~ A Member of the jake library.
    /*
    /*   A useful class that encapsulates storing data (settings) between executions
    /*     of a program. The class stores the data in a file within the same
    /*     directory as the program (by default), and provides intermediate
    /*     functions for reading from and writing to the file. 
    /*   The format is fairly simple, from the coder's perspective. Each setting
    /*     stored has a name which only need by worried about by the coder,
    /*     specified by a string, and a block of straight, raw data, whose size
    /*     needs to be specificly argued by the coder. Once the setting block is in
    /*     place within the file, the coder can tell the Settings Object to go to
    /*     the beginning of a particular setting and can then begin reading and
    /*     writing upon the file. 
    /******************************************************************************/
    
    #ifdef __cplusplus
    
    // Module Header File
    #include "jake.settings.h"
    
    Settings::Settings(string filename)
     {
      cout << "CHECKPOINT: Constructing Settings object...\n";
    
      // We first open the file in output mode only, to ensure that it exists. Also,
      // Append mode needs ot be specified, otherwise the old contents of the file
      // will be erased.
      cout << "CHECKPOINT: Testing open of settings file...\n";
      settings_file.open(filename.c_str(), ios_base::out | ios_base::app);
      if(settings_file.is_open())
       {
        cout << "CHECKPOINT:   Success.\n";
        settings_file.close();
       }
      else
        cout << "CHECKPOINT:   Failure.\n";
    
      // Open the file for real, in IN/OUT binary mode
      cout << "CHECKPOINT: Opening settings file...\n";
      settings_file.open(filename.c_str(),
                         ios_base::in | ios_base::out | ios_base::binary);
      if(settings_file.is_open())
        cout << "CHECKPOINT:   Success.\n";
      else
        cout << "CHECKPOINT:   Failure.\n";
     }
    
    Settings::Settings(char* filename)
     {
      cout << "CHECKPOINT: Constructing Settings object...\n";
    
      // We first open the file in output mode only, to ensure that it exists. Also,
      // Append mode needs ot be specified, otherwise the old contents of the file
      // will be erased.
      cout << "CHECKPOINT: Testing open of settings file...\n";
      settings_file.open(filename, ios_base::out | ios_base::app);
      if(settings_file.is_open())
       {
        cout << "CHECKPOINT:   Success.\n";
        settings_file.close();
       }
      else
        cout << "CHECKPOINT:   Failure.\n";
    
      // Open the file for real, in IN/OUT binary mode
      cout << "CHECKPOINT: Opening settings file...\n";
      settings_file.open(filename,
                         ios_base::in | ios_base::out | ios_base::binary);
      if(settings_file.is_open())
        cout << "CHECKPOINT:   Success.\n";
      else
        cout << "CHECKPOINT:   Failure.\n";
     }
    
    Settings::~Settings(void)
     {
      cout << "CHECKPOINT: Destroying Settings object...\n";
    
      // Make sure the file is open, then close it.
      cout << "CHECKPOINT: Closing settings file...\n";
      if(settings_file.is_open())
        settings_file.close();
      if(!settings_file.is_open())
        cout << "CHECKPOINT:   Success.\n";
      else
        cout << "CHECKPOINT:   Failure.\n";
     }
    
    bool Settings::GotoSetting(string setting_name)
     {
      cout << "CHECKPOINT: Executing GotoSetting()...\n";
    
      // Make sure the file is open...
      if(!settings_file.is_open())
       {
        cout << "CHECKPOINT: ERROR: File not open. Exiting.\n";
        return false;
       }
    
      // Go to the beginning of the file.
      cout << "CHECKPOINT: Moving to beginning of file...\n";
      settings_file.seekg(0);
      if(!settings_file.fail())
        cout << "CHECKPOINT:   Success.\n";
      else
        cout << "CHECKPOINT:   Failure.\n";
    
      // Start at the beginning of setting_name
      uint name_index = 0;
      // For logic progression purposes...
      bool matched_name = false;
      uint null_count = 0;
    
      cout << "CHECKPOINT: Entering Search loop...\n";
      while(1)
       {
        // As long as we don't reach the end of the file...
        settings_file.peek();
        if(settings_file.eof())
         {
          cout << "CHECKPOINT: End of file.\n";
          break;
         }
    
        // If we've already matched the entire name
        if(matched_name)
         {
           cout << "CHECKPOINT: Setting Name Matched.\n";
    
          // Record another Null-Terminator, if the next character is one.
          if(settings_file.get() == 0)
           {
            ++null_count;
            cout << "CHECKPOINT: Null-Terminator #" << null_count << ".\n";
           }
    
          // If we didn't get a Null-Terminator, we need to start over
          else
           {
            cout << "CHECKPOINT: No Null-Terminator. Resetting loop.\n";
            matched_name = false;
            null_count = 0;
           }
    
          // If we found two Null-Terminators after the name, we found it
          if(null_count == 2)
           {
            cout << "CHECKPOINT: Second Null-Terminator.\n";
            cout << "CHECKPOINT: Setting found!\n";
            // Synchronize the input position to the output position, which is the
            // beginning of the setting's data
            settings_file.seekp(settings_file.tellg());
            // Return Success
            return true;
           }
         }
        else
         {
          // If we matched a character within the name
          if(settings_file.get() == setting_name[name_index])
           {
            cout << "CHECKPOINT: setting_name[" << name_index << "] Matched.\n";
    
            // If it was the final character of the name, indicate that we've
            // matched the entire name
            if(name_index == (setting_name.size() - 1))
             {
              cout << "CHECKPOINT: Full Name Matched.\n";
              matched_name = true;
             }
    
            // If we haven't matched the entire name yet, go to the next character
            // of the name
            else
              ++name_index;
           }
    
          // If the current character didn't match, start over at the beginning of
          // setting_name.
          else
           {
            cout << "CHECKPOINT: No character match. Resetting loop.\n";
            name_index = 0;
           }
         }
       }
    
      // If we made it this far, that means the loop ran through the entire file,
      // and didn't find what we were looking for. So, return false
      cout << "CHECKPOINT: Failure to find Setting.\n";
      return false;
     }
    
    bool Settings::GotoSetting(char* setting_name)
     {
      // Make a C++ style-string out of the setting's name
      string string_setting_name = setting_name;
      // Pass the work off to the other version of GotoSetting()
      return GotoSetting(string_setting_name);
     }
    
    bool Settings::AddSetting(string setting_name, uint size)
     {
      cout << "CHECKPOINT: Executing AddSetting()...\n";
    
      // If the file isn't open, we can't do anything
      if(!settings_file.is_open())
       {
        cout << "CHECKPOINT: ERROR: File not open. Exiting.\n";
        return false;
       }
    
      // Make sure there isn't already a setting with the given name
      if(GotoSetting(setting_name))
       {
        cout << "CHECKPOINT: Setting " << setting_name << " already exists.\n";
        return false;
       }
    
      // Go to the end of the file
      cout << "CHECKPOINT: Going to end of file...\n";
      settings_file.seekp(0, ios_base::end);
      if(!settings_file.fail())
        cout << "CHECKPOINT:   Success.\n";
      else
        cout << "CHECKPOINT:   Failure.\n";
    
      cout << "CHECKPOINT: Checking file positions...\n";
      cout << "CHECKPOINT:   Put pointer = " << settings_file.tellp() << "\n";
      cout << "CHECKPOINT:   Get pointer = " << settings_file.tellg() << "\n";
      if(!settings_file.fail())
        cout << "CHECKPOINT:   Success.\n";
      else
        cout << "CHECKPOINT:   Failure.\n";
    
      // Add the prefixer, which is the setting's name, followed by two
      // Null-Terminators.
      cout << "CHECKPOINT: Adding prefixer for setting " << setting_name << "...\n";
      settings_file << setting_name << (byte)0 << (byte)0;
      if(!settings_file.fail())
        cout << "CHECKPOINT:   Success.\n";
      else
        cout << "CHECKPOINT:   Failure.\n";
    
      // Remember this position, because the coder expects this function to leave
      // the file at the beginning of the setting's data block
      cout << "CHECKPOINT: Retrieving file position...\n";
      uint position = settings_file.tellp();
      if(!settings_file.fail())
        cout << "CHECKPOINT:   Success.\n";
      else
        cout << "CHECKPOINT:   Failure.\n";
    
      // Add [size] number of bytes to the file, making space for the setting's
      //   data.
      cout << "CHECKPOINT: Adding empty filespace...\n";
      for(uint i = 0; i < size; ++i)
        settings_file << (byte)0;
      if(!settings_file.fail())
        cout << "CHECKPOINT:   Success.\n";
      else
        cout << "CHECKPOINT:   Failure.\n";
    
      // Set the file's position to the one we stored, the beginning of the
      // setting's data.
      cout << "CHECKPOINT: Setting File positions...\n";
      settings_file.seekp(position);
      settings_file.seekg(position);
      if(!settings_file.fail())
        cout << "CHECKPOINT:   Success.\n";
      else
        cout << "CHECKPOINT:   Failure.\n";
    
      // We made it here, so the setting was added.
      return true;
     }
    
    bool Settings::AddSetting(char* setting_name, uint size)
     {
      // Make a C++ style-string out of the setting's name
      string string_setting_name = setting_name;
      // Pass the work off to the other version of AddSetting()
      return AddSetting(string_setting_name, size);
     }
    
    #endif
    jake.settings.h
    Code:
    /******************************************************************************/
    /*   The Settings Class, by Jake Meiergerd
    /*    ~ C++ Implementation
    /*     AUTHOR:     Jake Meiergerd
    /*     VERSION:    1.0.0.1
    /*
    /*    FILE:  jake.settings.h
    /*       ~ Settings Class Header File
    /*       ~ A Member of the jake library.
    /*
    /*   A useful class that encapsulates storing data (settings) between executions
    /*     of a program. The class stores the data in a file within the same
    /*     directory as the program (by default), and provides intermediate
    /*     functions for reading from and writing to the file. 
    /*   The format is fairly simple, from the coder's perspective. Each setting
    /*     stored has a name which only need by worried about by the coder,
    /*     specified by a string, and a block of straight, raw data, whose size
    /*     needs to be specificly argued by the coder. Once the setting block is in
    /*     place within the file, the coder can tell the Settings Object to go to
    /*     the beginning of a particular setting and can then begin reading and
    /*     writing upon the file. 
    /******************************************************************************/
    
    #ifndef JAKE_SETTINGS_H
    #define JAKE_SETTINGS_H
    #ifdef __cplusplus
    
    // Global header for the library
    #include "jake.lib.h"
    
    /**************************************/
    /********* Class Declaration **********/
    /**************************************/
    
    class Settings
     {
      public:
        //  FUNCTION:   Settings() - Class Constructor
        //  ARGUMENTS:  filename: The name of the file in which the settings data
        //                        will be stored.
        //  PRE:        None
        //  POST:       The class is initialized for the given filename, and the
        //              file is created, if it didn't already exist.
        //  BRIEF:  Initializes the Settings module for a given filename.
        Settings(string filename);
        Settings(char* filename);
    
        //  FUNCTION:   ~Settings() - Class Destructor
        //  PRE:        None
        //  POST:       The class object is ready to be deleted.
        //  BRIEF:  Basically, it just closes the fstream object.
        ~Settings(void);
    
        //  FUNCTION:   GotoSetting()
        //  ARGUMENTS:  setting_name: The name of the setting to search for
        //  RETURN:     true:  The function was successful.
        //              false: The setting could not be found: i.e. there is no
        //                       setting named setting_name in the file, or the file
        //                       wasn't open.
        //  PRE:        None
        //  POST:       The current position of the settings file is the beginning
        //                of the data block of the specified setting
        //  BRIEF:  This function searches the settings file for a setting named
        //          setting_name and sets the current position of the file, for both
        //          reading and writing, to the beginning of the data block for that
        //          setting.
        bool GotoSetting(string setting_name);
        bool GotoSetting(char* setting_name);
    
        //  FUNCTION:   AddSetting()
        //  ARGUMENTS:  setting_name: The name of the setting you wish to add
        //                      size: The number of bytes required for the setting's 
        //                              data
        //  RETURN:     true:  The function was successful
        //              false: The function failed: i.e. the settings file was not
        //                       opened, or it already contains a setting with the
        //                       given name.
        //  PRE:        None
        //  POST:       The settings file now contains a block of space for the new
        //                setting, and the current position within the file, for
        //                both reading and writing, is the beginning of the new
        //                setting's data block.
        //  BRIEF:  This function will add a block of space to the settings file to 
        //          store data for the setting with the given name. This new block will
        //          be prefixed with the setting's name and a double Null-Terminator
        //          so it can be found by GotoSetting.
        bool AddSetting(string setting_name, uint size);
        bool AddSetting(char* setting_name, uint size);
    
      private:
        //  VAR:    settings_file
        //  BRIEF:  file in which the setting data is stored.
        fstream settings_file;
     };
    
    #endif
    #endif
    test.cpp
    Code:
    #include "jake.lib.h"
    
    int main(void)
     {
      cout << " ~ Testing the jake library, main Modules ~\n\n";
    
      // Test the Settings Module
      class Settings ProgramSettings("test_file.set");
    
      ProgramSettings.AddSetting("TEST_SETTING", 16);
    //  ProgramSettings.AddSetting("TEST_SETTING_2", 32);
    
      // End of Tests
      cout << "\n\n";
      cout << "Program Complete\n\n";
      return 0;
     }
    All necessary #includes and namespace stuff are taken care of in "jake.lib.h". Program compiles and runs, and gives the following output, whether the file "test_file.set" exists previously or not.

    Code:
    -bash-3.2$ test.exe
     ~ Testing the jake library, main Modules ~
    
    CHECKPOINT: Constructing Settings object...
    CHECKPOINT: Testing open of settings file...
    CHECKPOINT:   Success.
    CHECKPOINT: Opening settings file...
    CHECKPOINT:   Success.
    CHECKPOINT: Executing AddSetting()...
    CHECKPOINT: Executing GotoSetting()...
    CHECKPOINT: Moving to beginning of file...
    CHECKPOINT:   Success.
    CHECKPOINT: Entering Search loop...
    CHECKPOINT: End of file.
    CHECKPOINT: Failure to find Setting.
    CHECKPOINT: Going to end of file...
    CHECKPOINT:   Success.
    CHECKPOINT: Checking file positions...
    CHECKPOINT:   Put pointer = 0
    CHECKPOINT:   Get pointer = 0
    CHECKPOINT:   Success.
    CHECKPOINT: Adding prefixer for setting TEST_SETTING...
    CHECKPOINT:   Failure.
    CHECKPOINT: Retrieving file position...
    CHECKPOINT:   Failure.
    CHECKPOINT: Adding empty filespace...
    CHECKPOINT:   Failure.
    CHECKPOINT: Setting File positions...
    CHECKPOINT:   Failure.
    
    
    Program Complete
    
    CHECKPOINT: Destroying Settings object...
    CHECKPOINT: Closing settings file...
    CHECKPOINT:   Success.
    Code:
    void function(void)
     {
      function();
     }

  2. #2
    Registered User MacNilly's Avatar
    Join Date
    Oct 2005
    Location
    CA, USA
    Posts
    466
    I seem to recall that if you encounter EOF, you must call reset() method on the file object to read or write anymore. Just a guess, but this could be the problem. In your GotoSetting method, try adding a settings_file.reset() AFTER you hit EOF.

    Like I said, just a guess since everything else looks correct.

  3. #3
    Work in Progress..... Jaken Veina's Avatar
    Join Date
    Mar 2005
    Location
    Missouri. Go Imos Pizza!
    Posts
    256
    settings_file.clear(), actually, is what did it. I wish C++ file IO was more like C. I would have been done with this with about 10 hours less work. Thanks.
    Code:
    void function(void)
     {
      function();
     }

  4. #4
    Work in Progress..... Jaken Veina's Avatar
    Join Date
    Mar 2005
    Location
    Missouri. Go Imos Pizza!
    Posts
    256
    settings_file.clear(), actually, is what did it. I wish C++ file IO was more like C. I would have been done with this with about 10 hours less work. Thanks.
    Code:
    void function(void)
     {
      function();
     }

  5. #5
    Registered User MacNilly's Avatar
    Join Date
    Oct 2005
    Location
    CA, USA
    Posts
    466

    Opps

    Yeah, I meant clear. But that is the nature of fstream and is one of those "gotchas" in C++. One has to wonder why encountering EOF is treated as an "error" condition.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. No clue how to make a code to solve problems!
    By ctnzn in forum C Programming
    Replies: 8
    Last Post: 10-16-2008, 02:59 AM
  2. C Pointers Problems
    By mhelal in forum C Programming
    Replies: 8
    Last Post: 01-10-2007, 06:35 AM
  3. String Manipulation problems -_-
    By Astra in forum C Programming
    Replies: 5
    Last Post: 12-13-2006, 05:48 PM
  4. fstream problems
    By brianptodd in forum C++ Programming
    Replies: 2
    Last Post: 10-21-2002, 09:44 AM
  5. stl fstream error (yes... file problems again)
    By ygfperson in forum C++ Programming
    Replies: 7
    Last Post: 07-13-2002, 10:47 PM