• Welcome to Valhalla Legends Archive.
 

Question With FStream

Started by Dyndrilliac, May 07, 2004, 02:32 PM

Previous topic - Next topic

Dyndrilliac

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?
Quote from: Edsger W. DijkstraIt is practically impossible to teach good programming to students that have had a prior exposure to BASIC; as potential programmers they are mentally mutilated beyond hope of regeneration.

Mephisto

#1
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.

Maddox

#2
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
}
asdf.

Eibro

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_;
};
Eibro of Yeti Lovers.

Maddox


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.
asdf.

Mephisto

#5
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.

Maddox

#6
Maybe you should look at the class then? That line removes all the bracket characters in the line.
asdf.

Mephisto

#7
...I see what you mean now.

Eibro

#8
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.
Eibro of Yeti Lovers.

Maddox

#9
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.
asdf.

Moonshine

Yeah... like maddox said.

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