Thread: IniEditor C/C++

  1. #1
    printf("Hello Cboard\n"); codeprada's Avatar
    Join Date
    Jan 2011
    Location
    In a little room at the back of your brain
    Posts
    68

    Arrow IniEditor C/C++

    Is there a class file or built in functions to handle ini/inf files? I had made one but it's kind of slow when it comes to reading large files ( 2MB+ ).

  2. #2
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Quote Originally Posted by codeprada View Post
    Is there a class file or built in functions to handle ini/inf files? I had made one but it's kind of slow when it comes to reading large files ( 2MB+ ).
    No. Nothing built in to handle ini''s.

    If you post the code for yours here, I'm sure some of us can find ways to optimize it. 2 million bytes isn't a lot in the grand scheme of things, if there's like 10 characters per line, that's only 200,000 entries. There should be no issue getting through that...though I do have to ask, what the hell is using an ini that large?

    Since most systems are multi-core/proc, depending on what this is going into, you might want to think about threading it, and starting a second thread half way down the list or something...but chance are there's room for optimization in yours.

  3. #3
    printf("Hello Cboard\n"); codeprada's Avatar
    Join Date
    Jan 2011
    Location
    In a little room at the back of your brain
    Posts
    68
    It's not complete but here goes

    IniEditor.h
    Code:
    #ifndef INIEDITOR_H
    #define INIEDITOR_H
    
    #include <vector>
    #include <fstream>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <cstdlib>
    
    using namespace std;
    
    class Section
    {
    public:
    	Section(string name);
    	//Section(char name[]);
    	void addOption(string key, string value);
    	void removeOption(string key);
    	//void updateValue(string key, string value);
    	string getSectionName();
    	void display();
    	std::vector<string> getOptions();
    	string getValue(string option);
    	bool exists(string option);
    
    private:
    	string secName;
    	std::vector<string> key;
    	std::vector<string> value;
    	int getOptionPosition(string option);
    	string fix(string str);
    };
    
    class IniEditor
    {
    public:
    	IniEditor();
    	IniEditor(string filename);
    	~IniEditor();
    	bool load(string filename);
    	string toString();
    	void displaySections();
    	void display(string sectionname);
    	void removeOption(string sectionname, string key);
    	void save();
    	bool hasSection(string sectionname);
    	bool hasOption(string sectionname, string option);
    	//void removeSection(string sectionname);
    	//void addSection(string sectionname);
    	
    private:
    	string filename;
    	std::vector<Section> sections;
    	bool contains(char c[], char character, int size);
    	string IniEditor::parseSectionHeader(char c[], int size);
    	string IniEditor::parseSectionHeader(std::string &c);
    	vector<string> IniEditor::StringSplit(string str, string delim);
    	string getSectionHeaderFormatted(string sectionname);
    	int getSectionPosition(string sectionname);
    	int Get_Size(string path);
    	
    };
    
    #endif

    IniEditor.cpp
    Code:
    #include "IniEditor.h"
    #include <Windows.h>
    
    IniEditor::IniEditor()
    {
    	this->filename = "";
    }
    
    IniEditor::IniEditor(string filename)
    {
    	this->filename = filename;
    	load(filename);
    }
    
    IniEditor::~IniEditor()
    {
    
    }
    
    bool IniEditor::load(string filename)
    {
    	this->filename = filename;
    	ifstream ini;
    	ini.open(filename, std::ios::in);
    	char buffer[1024];
    	
    	string parse;
    
    	if(ini)
    	{
    		while (!ini.eof())
    		{
    			for (int i = 0; i < 1024; i++)
    				buffer[i] = ' ';
    
    			ini.getline(buffer, 1024, '\n');
    			if (this->contains(buffer, '[', 1024) && this->contains(buffer, ']', 1024))
    			{
    				sections.push_back(Section(parseSectionHeader(buffer, 1024)));
    			}
    			else
    			{
    				if (buffer[1] != ' ' && buffer[0] != '\n' && buffer[0] != ';')
    				{
    					parse = buffer;
    					vector<string> temp;
    					temp = StringSplit(parse, "=");
    					sections[sections.size() - 1].addOption(temp[0], temp[1]);
    				}
    				
    			}
    		}
    		ini.close();
    	 }
    	return true;
    	
    }
    
    bool IniEditor::contains(char c[], char character, int size)
    {
    	for (int i = 0; i < size; i++)
    	{
    		if (c[i] == character)
    			return true;
    	}
    	return false;
    }
    
    string IniEditor::parseSectionHeader(std::string &c)
    {
    	char * s = (char *)(malloc(sizeof(char) * c.length()));
    	strcpy(s, c.c_str());
    	return(parseSectionHeader(s, sizeof(s)));
    }
    
    string IniEditor::parseSectionHeader(char c[], int size)
    {
    	string temp = "";
    	bool start = false, done = false;
    
    	for (int i = 0; i < size && !done; i++)
    	{
    		if (start == true)
    		{
    			if (c[i] != ']')
    			{
    				temp += c[i];
    			}
    			else
    			{
    				temp += c[i];
    				done = true;
    			}
    		}
    		else if(c[i] == '[')
    		{
    			start = true;
    			temp += c[i];
    		}
    			
    	}
    
    	return temp;
    }
    
    string IniEditor::toString()
    {
    	return this->filename;
    }
    
    vector<string> IniEditor::StringSplit(string str, string delim)
    {
    	vector<string> results;
    	int cutAt;
    
    	while( (cutAt = str.find_first_of(delim)) != str.npos )
    	{
    		if(cutAt > 0)
    		{
    			results.push_back(str.substr(0,cutAt));
    		}
    		str = str.substr(cutAt+1);
    	}
    
    	if(str.length() > 0)
    	{
    		results.push_back(str);
    	}
    
    	return results;
    }
    
    void IniEditor::removeOption(string sectionname, string key)
    {
    	sectionname = getSectionHeaderFormatted(sectionname);
    
    	int pos = getSectionPosition(sectionname);
    
    	if (pos >= 0)
    		sections[getSectionPosition(sectionname)].removeOption(key);
    }
    
    void IniEditor::displaySections()
    {
    	for (int i = 0; i < sections.size(); i++)
    	{
    		cout << sections[i].getSectionName() << endl;
    		sections[i].display();
    		cout << "\n\n";
    	}
    }
    
    void IniEditor::display(string sectionname)
    {
    	sectionname = getSectionHeaderFormatted(sectionname);
    	int pos = getSectionPosition(sectionname);
    
    	if (pos >= 0)
    		sections[pos].display();	
    }
    
    int IniEditor::getSectionPosition(string sectionname)
    {
    	int i = 0;
    
    	for (; i < sections.size(); i++)
    	{
    		if (strcmp(sections[i].getSectionName().c_str(), sectionname.c_str()) == 0)
    		{
    			return i;
    		}
    	}
    
    	i = -1;
    	return i;
    }
    
    string IniEditor::getSectionHeaderFormatted(string sectionname)
    {
    	if (sectionname.at(0) != '[')
    	{
    		sectionname = "[" + sectionname + "]";
    	}
    	return sectionname;
    }
    
    void IniEditor::save()
    {
    	ofstream ini;
    	ini.open(this->filename);
    	
    	if (ini)
    	{
    		for (int count = 0; count < sections.size(); count++)
    		{
    			ini << sections[count].getSectionName() << endl;
    
    			std::vector<string> options = sections[count].getOptions();
    
    			for (int i = 0; i < options.size(); i++)
    			{
    				ini << options[i] << " = " << sections[count].getValue(options[i]) << endl;
    			}
    
    			ini << endl;
    		}
    
    		ini.close();
    
    	}
    
    }
    
    bool IniEditor::hasSection(string sectionname)
    {
    	if (getSectionPosition(getSectionHeaderFormatted(sectionname)) >= 0)
    		return true;
    	return false;
    }
    
    bool IniEditor::hasOption(string sectionname, string option)
    {
    	int pos = getSectionPosition(getSectionHeaderFormatted(sectionname));
    	if (pos >= 0)
    		return (sections[pos].exists(option));
    	return false;
    }
    
    int IniEditor::Get_Size( string path )
    {
    	FILE *pFile = NULL;
    	fopen_s( &pFile, path.c_str(), "rb" );
    	fseek( pFile, 0, SEEK_END );
    	int Size = ftell( pFile );
    	fclose( pFile );
    	return Size;
    }
    
    /**************************************************************************************/
    
    
    Section::Section(string name)
    {
    	secName = name;
    }
    
    void Section::addOption(string key, string value)
    {
    	this->key.push_back(key);
    	this->value.push_back(value);
    }
    
    string Section::getSectionName()
    {
    	return secName;
    }
    
    void Section::removeOption(string key)
    {
    	int pos = find(this->key.begin(), this->key.end(), key) - this->key.begin() - 1;
    	std::vector<string>::iterator i = this->key.begin() + pos;
    	this->key.erase(i);
    	i = this->value.begin() + pos;
    	this->value.erase(i); 
    }
    
    std::vector<string> Section::getOptions()
    {
    	return this->key;
    }
    
    string Section::getValue(string option)
    {
    	bool found = false;
    
    	int i;
    
    	for (i = 0; i < this->key.size() && !found; i++)
    	{
    		if (strcmp(this->key[i].c_str(), option.c_str()) == 0)
    		{
    			found = true;
    		}
    	}
    
    	if (found)
    		return this->value[i - 1];
    	else
    		return NULL;
    }
    
    void Section::display()
    {
    	std::vector<string>::iterator ik = this->key.begin();
    	std::vector<string>::iterator iv = this->value.begin();
    
    	for (; ik != this->key.end(); ik++)
    	{
    		 cout << *ik << " = " << *iv << endl;
    		 iv++;
    	}
    }
    
    bool Section::exists(string option)
    {
    	for (int i = 0; i < this->key.size(); i++)
    	{
    		if (strcmp(this->key[i].c_str(), option.c_str()) == 0)
    			return true;
    		cout << this->key[i] << " ===== " << option << endl;
    	}
    
    	return false;
    }
    
    string Section::fix(string str)
    {
    	return "";
    }

  4. #4
    Registered User
    Join Date
    Aug 2010
    Location
    Rochester, NY
    Posts
    196
    Okay, TBH I've been putting this post off since you've posted it due to its length.

    So I got bored about 1/4 through it, but I got the idea.

    Are you trying to handle EVERYTHING, or just the basic
    [header]
    something="string"
    something_else=number

    If it's just the latter, I'd recommend (and btw, instead of char arrays, use strings, this is C++ (or at least that's what people keep telling me when I use char arrays O.o)) simply tokenizing on the equals sign, trimming trailing/leading white space, and dump the thing into a map like you're doing.

    I'm pretty sure you're over-complicating the hell out of this.

    I think the problem may lie in the fact that you have 15,000 functions and everything calls everything, that's a lot of parsing for each line. I'm pretty sure you need to refactor a bit, decide how much of the INI std you're going to follow, and implement it in C if you're constantly parsing 2MB + ini files..

  5. #5
    Registered User carrotcake1029's Avatar
    Join Date
    Apr 2008
    Posts
    404
    Does your OS not provide any way of reading ini files? Also, are you against using a pre-written library. A simple google search will show many classes people have written to read ini files.

    No need to reinvent the wheel.

  6. #6
    printf("Hello Cboard\n"); codeprada's Avatar
    Join Date
    Jan 2011
    Location
    In a little room at the back of your brain
    Posts
    68
    Quote Originally Posted by carrotcake1029 View Post
    Does your OS not provide any way of reading ini files? Also, are you against using a pre-written library. A simple google search will show many classes people have written to read ini files.

    No need to reinvent the wheel.
    i didnt' find any that's why i asked if there was any...i honestly dont' care about making one i just need it to make a certain app.

  7. #7
    printf("Hello Cboard\n"); codeprada's Avatar
    Join Date
    Jan 2011
    Location
    In a little room at the back of your brain
    Posts
    68
    Quote Originally Posted by Syndacate View Post
    Okay, TBH I've been putting this post off since you've posted it due to its length.

    So I got bored about 1/4 through it, but I got the idea.

    Are you trying to handle EVERYTHING, or just the basic
    [header]
    something="string"
    something_else=number

    If it's just the latter, I'd recommend (and btw, instead of char arrays, use strings, this is C++ (or at least that's what people keep telling me when I use char arrays O.o)) simply tokenizing on the equals sign, trimming trailing/leading white space, and dump the thing into a map like you're doing.

    I'm pretty sure you're over-complicating the hell out of this.

    I think the problem may lie in the fact that you have 15,000 functions and everything calls everything, that's a lot of parsing for each line. I'm pretty sure you need to refactor a bit, decide how much of the INI std you're going to follow, and implement it in C if you're constantly parsing 2MB + ini files..
    you think this is anything....there's a java version of this and it works pretty well with alot more functions than this. but it uses maps and i couldn't find any tutorials teaching me to use such in C\C++.

  8. #8
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Typing "C++ ini parser" into Google got me several libraries in the first five results. You'd have to check licensing restrictions I guess.

    Maps in C++ are called "maps". Typing "C++ map" into Google got me 9.55 million results, of which I did not read them all.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by codeprada
    you think this is anything....there's a java version of this and it works pretty well with alot more functions than this.
    As carrotcake1029 and tabstop have stated, this is more or less a solved problem, especially if you are willing to look outside of the standard library. If you have access to Boost, you could use Boost.ProgramOptions with the configuration file parser.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Tags for this Thread