Valhalla Legends Archive

Programming => General Programming => C/C++ Programming => Topic started by: Dyndrilliac on May 07, 2004, 02:32 PM

Title: Question With FStream
Post by: Dyndrilliac on May 07, 2004, 02:32 PM
I want to create a Read from INI type function using the header FStream.h.

I am familiar with the basics of FStream, IE:

ifstream b_file(FileName);
b_file>>str;
b_file.close();


Would put the contents of the target (FileName) into the string str.

How would I turn this into a read from INI function?
Title: Re:Question With FStream
Post by: Mephisto on May 07, 2004, 04:52 PM
This code is untested and may not work, but should compile.


This code will create a read INI file function and pass in a buffer by reference and the ifstream by value.  This should accomplish what you need, though passing in by value may be inefficient depending on what you're doing:

#include <fstream>
#include <string>
void ReadINIFile(std::ifstream &, std::string);
int main() {
   std::string buffer;
   std::ifstream fin("thefile.ini", std::ios::app);
   ReadINIFile(fin, buffer);
   return 0;
}
void ReadINIFile(std::ifstream fin, std::string buffer) {
   fin >> buffer;
   fin.close();
}



This code passes the ifstream object into the function by reference using references:

#include <fstream>
#include <string>
void ReadINIFile(std::ifstream &, std::string &);
int main() {
   std::string buffer;
   std::string &rBuffer = buffer;
   std::ifstream fin("thefile.ini", std::ios::app);
   std::ifstream &rFin = fin;
   ReadINIFile(rFin, rBuffer);
   return 0;
}
void ReadINIFile(std::ifstream &rFin, std::string &rBuffer) {
   rFin >> rBuffer;
   rFin.close();
}


Looping will also be necessary if you want to read in more than one line.
I would personally recommend using the stdio.h file I/O, but it's more of a preference and what you like to use.
Title: Re:Question With FStream
Post by: Maddox on May 07, 2004, 04:56 PM
Quote from: Dyndrilliac on May 07, 2004, 02:32 PM
I want to create a Read from INI type function using the header FStream.h.

I am familiar with the basics of FStream, IE:

ifstream b_file(FileName);
b_file>>str;
b_file.close();


Would put the contents of the target (FileName) into the string str.

How would I turn this into a read from INI function?

You will need to loop each line, checking to see if the text in brackets matches your appname then then and if it does, check the proceeding lines for your key name.


// this should loop through each line
std::string Line;

while(!std::getline(b_file, Line, '\n').eof())
{
// ... check string here
}
Title: Re:Question With FStream
Post by: Eibro on May 07, 2004, 05:03 PM
I wrote a nice class for this a long while back. Might be of some use.
class IniFile {
public:
   typedef std::pair< std::string, std::string > ini_entry;
   typedef std::map< std::string, std::string > ini_section;
   typedef std::map< std::string, ini_section > ini_file;
   typedef size_t size_type;

protected:
   static bool isSectionTrim( char in ) {
      return in == '[' || in == ']';
   }

public:
   IniFile() {};
   explicit IniFile( const std::string& file ) { load( file ); }

   bool load( const std::string& file ) {

      std::ifstream fin( file.c_str() );

      if ( !fin.is_open() ) return false;

      std::string in;
      std::string currentSectionName; // current inisection name
      while ( std::getline( fin, in ) ) {
         if ( in.size() < 2 || in[0] == '#' ) // skip comments and empty lines
            continue;

         if ( in[0] == '[' ) { // inisection
            // Trim unwanted characters
            in.erase( std::remove_if( in.begin(), in.end(), isSectionTrim ), in.end() );
            currentSectionName = in;
            continue;
         }

         // parse key and value
         // "key = value\n"
         std::string::size_type delimit = in.find( '=' );
         std::string key( in.begin(), in.begin() + delimit );
         std::string val( in.begin() + delimit + 1, in.end() );

         // trim leading/trailing spaces
         while ( isspace( key[ key.size() - 1] ) ) key.erase( key.size() - 1 );
         while ( isspace( val[0] ) ) val.erase( 0 );

         iniFile_[currentSectionName][key] = val;
      }

      fin.close();
      return true;
   }

   bool save( const std::string& file ) const {

      std::ofstream fout( file.c_str() );

      if ( !fout.is_open() ) return false;

      // loop sections
      for ( ini_file::const_iterator iter = iniFile_.begin();
         iter != iniFile_.end(); ++iter ) {

            fout << '[' << iter->first << "]\n";
            // loop entries
            for ( ini_section::const_iterator sect = iter->second.begin();
               sect != iter->second.end(); ++sect ) {

                  fout << sect->first << " = " << sect->second << '\n';
               }

               fout << std::endl;
         }

         fout.close();
         return true;
   }

   ini_section& operator[] ( const std::string& str ) {
      return iniFile_[str];
   }

   ini_section& section( const std::string& str ) {
      return iniFile_[str];
   }

   size_type entries( const std::string& sect ) const {
      for ( ini_file::const_iterator iter = iniFile_.begin();
         iter != iniFile_.end(); ++iter )
         if ( iter->first == sect )
            return iter->second.size();

      return 0;
   }

   size_type entries() const {
      size_type count = 0;
      // loop sections
      for ( ini_file::const_iterator iter = iniFile_.begin();
         iter != iniFile_.end(); ++iter )
         count += iter->second.size();

      return count;
   }

protected:
   ini_file iniFile_;
};
Title: Re:Question With FStream
Post by: Maddox on May 07, 2004, 08:38 PM

in.erase( std::remove_if( in.begin(), in.end(), isSectionTrim ), in.end() );


If you have brackets inside the brackets, you won't be able to read your data.
Title: Re:Question With FStream
Post by: Mephisto on May 07, 2004, 08:44 PM
What are you talking about?  Correct me if I am wrong, but...

...I haven't looked at the class, but by the looks of it, there are no brackets there.  Additionally, all that is going on in that line of code is a function call with a pass of multiple functions as arguments which presumably return a value of the type which matches the parameter list which is actually what is being passed into the function.
Title: Re:Question With FStream
Post by: Maddox on May 07, 2004, 08:57 PM
Maybe you should look at the class then? That line removes all the bracket characters in the line.
Title: Re:Question With FStream
Post by: Mephisto on May 07, 2004, 09:20 PM
...I see what you mean now.
Title: Re:Question With FStream
Post by: Eibro on May 07, 2004, 11:24 PM
Quote from: Maddox on May 07, 2004, 08:38 PM

in.erase( std::remove_if( in.begin(), in.end(), isSectionTrim ), in.end() );


If you have brackets inside the brackets, you won't be able to read your data.
What are you talking about? It strips all brackets, yes. Who names sections [[[section]]] anyway? I don't see this as being a problem.
Title: Re:Question With FStream
Post by: Maddox on May 08, 2004, 12:33 AM
What about dynamically created sections where the name of the appkey is not going to be known? If it stores usernames, for example, and someone's name is Foo[bar] then you're going to have a problem reading the data for that person.
Title: Re:Question With FStream
Post by: Moonshine on May 08, 2004, 03:30 AM
Yeah... like maddox said.

It looks like you're just taking out the [ ] and putting them back in during save() anyways.