Settings File Reader

A forum to store posts deemed exceptionally wise and useful
Post Reply
torleif
Posts: 188
Joined: Mon Jun 30, 2008 4:53 am

Settings File Reader

Post by torleif »

Creating an Irrlicht device and dropping it again to get the file manager is a bit messy, so I wrote my own file settings reader. It has many features, such as white space trimming and comments

You can download it here with an example ZIP/ 20KB

Alternatively, here is the code:

Code: Select all

/** settings.h Torleif West 17/dec/2007 
 *
 * Loads settings from file, then map them for quick access. 
 * Allows comments in the settings file and trims wasted white space. 
 *
 */


#include <map>		// map of properties
#include <string>	// for std::string
#include <fstream>	// opening file
#include <ostream>	// saving file


#ifndef SETTINGS_H_
#define SETTINGS_H_


class Settings{
	/**

		Class stores strings in a map, with a value for each. 
		This allows quick access to the data 

	*/
      private:
            // Map of two strings
            std::map<std::string, std::string> data;

			// Use numbers char values as UNIX has different new line char
			static const char CHAR_LINE1 = 59;	// windows endline
			static const char CHAR_LINE2 = 10;	// UNIX endline
			static const char CHAR_SPACE = 32;	// ' ' char
			static const char CHAR_ENDFILE = -1;// EOF
			static const char CHAR_EQUALS = 61;	// = char
			static const char CHAR_COMMENT = 35;// # char
			static const char NUMBER_POINT = 46;// ASCII value for .
			static const char NUMBER_NINE = 57;	// ASCII value for 9
			static const char NUMBER_ZERO = 48;	// ASCII value for 0

			// file name of this settings file (used if saved)
			std::string settingsFile;
      public:
             
			// --- Loads the settings file ---
			// \param filename the string file name to load
            Settings(std::string filename) { 
				settingsFile = filename;

				std::ifstream ifs (filename.c_str(), std::ifstream::in);

				bool swch = true;
				bool stopReading = false;
				char c;
				std::string mproperty = "";
				std::string value = "";

				while (ifs.good()) {
					c = (char) ifs.get();
					//printf("%d ", int(c)); // debug
					if(c == CHAR_EQUALS) {
						swch = false;
					}
					if(c == CHAR_COMMENT) {
						stopReading = true;
					}
					// ignore white space
					if(c != CHAR_EQUALS && !stopReading) {
						std::string tmpchar;
						tmpchar = c;
						if(swch) {
							mproperty.append(tmpchar);
						} else {
							value.append(tmpchar);
						}
					}
					// read to the end of the line
					if(c == CHAR_LINE1 || c == CHAR_LINE2 || c == CHAR_ENDFILE) {
						if(!swch) {
							//printf("Inserting :%s=%s\n", 
							//   trim(mproperty).c_str(), trim(value).c_str());
							data.insert ( std::pair<std::string,
								std::string>(trim(mproperty),trim(value)) );
						}
						mproperty = "";
						value = "";
						swch = true;
						stopReading = false;
					}
				}
				ifs.close();
            }
            
            // --- Deconstructor ---
	        ~Settings(){ 
				data.clear(); 
			}
			
			// --- Removes white space ---
			// \param targ string of to trim
			// \returns string with no white space at start or end
			std::string trim(const std::string &targ) {
				std::string retstr;
				int startStr = 0;
				int endStr = targ.size();

				if(targ.size() == 0) return targ;

				for(int i = 0; i < (int)targ.size(); i++) {
					char c = targ.at(i);
					if(c != CHAR_LINE1 && c != CHAR_LINE2 &&
						c != CHAR_ENDFILE && c != CHAR_SPACE ) {
						startStr = i;
						break;
					}
				}
				for(int i = (int)targ.size()-1; i > 0; i--) {
					char c = targ.at(i);
					if(c != CHAR_LINE1 && c != CHAR_LINE2 && 
						c != CHAR_ENDFILE && c != CHAR_SPACE ) {
						endStr = i;
						break;
					}
				}
				// rebuild string
				for(int i = startStr; i <= endStr; i++) {
					std::string tmpchar;
					tmpchar = targ.at(i);
					retstr.append(tmpchar);
				}
				return retstr;
			}

			// --- Returns value in map ---
			// \param key the string key stored in the map
			// \param roret return value if no string found
			// \returns string in map, or noret if not found
            std::string getValue(std::string key, std::string noret){
            	std::map<std::string, std::string>::iterator it;
            	it = data.find(key);
            	if(it != data.end()){
            		return (*it).second;
            	}
            	return noret;
            }
            
            // --- Returns the size of the map---
			// \returns int how many items in data map
            int size(){
                return (int) data.size();
            }
            
            // --- Converts string to double ---
			// \param s the string to convert
			// \returns double floating point number of string 
            double strToDob(const std::string &s){
				double retvalue = 0.0;
				int digitPlacing = 0;	// place in str where you've read to
				int digitPoint = -1;	// place where the point is

				for(int i = 0; i < (int)s.size(); i++) {
					// convert char to number for double
					if(s.at(i) >= NUMBER_ZERO && s.at(i) <= NUMBER_NINE) {
						if(digitPoint == -1) {	//adding 
							retvalue *= 10;
							retvalue += s.at(i) - NUMBER_ZERO;
						} else {
							int add = 10;// find power of 10 to decimal place
							for(int m = 0; m < (digitPlacing-digitPoint); m++)
								add *= 10;
							retvalue+=(double)(s.at(i)-NUMBER_ZERO)/(double)add;
						}
						digitPlacing++;
					}
					// running into point
					if(s.at(i) == NUMBER_POINT && digitPoint == -1) {
						digitPoint = digitPlacing;
					}
				}
            	return retvalue;
            }


            // --- Saves a the value in file, and changes in map (slow atm) ---
			// \param saveStr the value in the map to change
			// \param newValue the value that will replace the old value 
			void saveParam(std::string saveStr, std::string newValue){
				// bail out on failure
				std::string oldValue = getValue(saveStr, "");
				std::string saveFile;

				// bail out if value dosn't exisit
				if(oldValue.compare("")==0){ return; }

				// save file in memory
				std::ifstream ifs (settingsFile.c_str(), std::ifstream::in);
				while (ifs.good()) {
					char c = ifs.get();
					if(c != CHAR_ENDFILE) {
						std::string tmpchar;
						tmpchar = c;
						saveFile.append(tmpchar);
					}
				}
				ifs.close();

				// go through each character, and find the string your replacing
				bool swch = true;
				bool stopReading = false;
				char c;
				std::string mproperty = "";
				std::string value = "";
				for(int i = 0; i < (int)saveFile.size(); i++) {
					c = saveFile.at(i);
					//printf("%d ", int(c)); // debug
					if(c == CHAR_EQUALS) {
						swch = false;
					}
					if(c == CHAR_COMMENT) {
						stopReading = true;
					}
					// ignore white space
					if(c != CHAR_EQUALS && !stopReading) {
						std::string tmpchar;
						tmpchar = c;
						if(swch) {
							mproperty.append(tmpchar);
						} else {
							// found the value, save and bail.
							if(trim(mproperty).compare(saveStr)==0) {
								saveFile.replace(i+1, oldValue.size(), newValue);

								// save the new value in the map
								data.erase (saveStr);
								data.insert(std::pair<std::string, std::string>
                                              (saveStr, newValue));
						
								// and finally in the map
								std::ofstream savFil(settingsFile.c_str(), 
                                              std::ofstream::trunc);
								savFil << saveFile;
								savFil.close();

								return;
							}
							value.append(tmpchar);
						}
					}
					// read to the end of the line
					if(c == CHAR_LINE1 || c == CHAR_LINE2 || c == CHAR_ENDFILE) {
						mproperty = "";
						value = "";
						swch = true;
						stopReading = false;
					}
				}
            }

};
#endif

Please feel free to suggest improvements/ changes to it
Bodzio
Posts: 15
Joined: Mon Nov 10, 2008 8:53 am

Post by Bodzio »

Is it only reader or it can write the config file too?
Sylence
Posts: 725
Joined: Sat Mar 03, 2007 9:01 pm
Location: Germany
Contact:

Post by Sylence »

By looking one minute at the code you would have seen the saveParam method. So I'd say yes it can
Software documentation is like sex. If it's good you want more. If it's bad it's better than nothing.
Post Reply