6 CIniFile::CIniFile(void) // Default constructor
10 CIniFile::~CIniFile(void)
14 // A function to trim whitespace from both sides of a given string
15 void Trim(std::string
& str
, const std::string
& ChrsToTrim
= " \t\n\r", int TrimDir
= 0)
17 size_t startIndex
= str
.find_first_not_of(ChrsToTrim
);
18 if (startIndex
== std::string::npos
){str
.erase(); return;}
19 if (TrimDir
< 2) str
= str
.substr(startIndex
, str
.size()-startIndex
);
20 if (TrimDir
!=1) str
= str
.substr(0, str
.find_last_not_of(ChrsToTrim
) + 1);
23 //inline void TrimRight(std::string& str, const std::string & ChrsToTrim = " \t\n\r")
25 // Trim(str, ChrsToTrim, 2);
28 //inline void TrimLeft(std::string& str, const std::string & ChrsToTrim = " \t\n\r")
30 // Trim(str, ChrsToTrim, 1);
33 // A function to transform a string to uppercase if neccessary
34 void UCase(string
& str
, bool ucase
)
36 if(ucase
) transform(str
.begin(), str
.end(), str
.begin(), toupper
);
39 bool CIniFile::Load(string FileName
, vector
<IniRecord
>& content
)
41 string s
; // Holds the current line from the ini file
42 string CurrentSection
; // Holds the current section name
44 ifstream
inFile (FileName
.c_str()); // Create an input filestream
45 if (!inFile
.is_open()) return false; // If the input file doesn't open, then return
46 content
.clear(); // Clear the content vector
48 string comments
= ""; // A string to store comments in
50 while(!std::getline(inFile
, s
).eof()) // Read until the end of the file
52 Trim(s
); // Trim whitespace from the ends
53 if(!s
.empty()) // Make sure its not a blank line
55 IniRecord r
; // Define a new record
57 if((s
[0]=='#')||(s
[0]==';')) // Is this a commented line?
59 if ((s
.find('[')==string::npos
)&& // If there is no [ or =
60 (s
.find('=')==string::npos
)) // Then it's a comment
62 comments
+= s
+ '\n'; // Add the comment to the current comments string
64 r
.Commented
= s
[0]; // Save the comment character
65 s
.erase(s
.begin()); // Remove the comment for further processing
67 }// Remove any more whitespace
68 } else r
.Commented
= ' '; // else mark it as not being a comment
70 if(s
.find('[')!=string::npos
) // Is this line a section?
72 s
.erase(s
.begin()); // Erase the leading bracket
73 s
.erase(s
.find(']')); // Erase the trailing bracket
74 r
.Comments
= comments
; // Add the comments string (if any)
75 comments
= ""; // Clear the comments for re-use
76 r
.Section
= s
; // Set the Section value
77 r
.Key
= ""; // Set the Key value
78 r
.Value
= ""; // Set the Value value
82 if(s
.find('=')!=string::npos
) // Is this line a Key/Value?
84 r
.Comments
= comments
; // Add the comments string (if any)
85 comments
= ""; // Clear the comments for re-use
86 r
.Section
= CurrentSection
; // Set the section to the current Section
87 r
.Key
= s
.substr(0,s
.find('=')); // Set the Key value to everything before the = sign
89 r
.Value
= s
.substr(s
.find('=')+1); // Set the Value to everything after the = sign
94 if(comments
== "") // Don't add a record yet if its a comment line
95 content
.push_back(r
); // Add the record to content
99 inFile
.close(); // Close the file
103 bool CIniFile::Save(string FileName
, vector
<IniRecord
>& content
)
105 ofstream
outFile (FileName
.c_str()); // Create an output filestream
106 if (!outFile
.is_open()) return false; // If the output file doesn't open, then return
108 for (int i
=0;i
<(int)content
.size();i
++) // Loop through each vector
110 outFile
<< content
[i
].Comments
; // Write out the comments
111 if(content
[i
].Key
== "") // Is this a section?
112 outFile
<< content
[i
].Commented
<< "["
113 << content
[i
].Section
<< "]" << endl
; // Then format the section
115 outFile
<< content
[i
].Commented
<< content
[i
].Key
116 << "=" << content
[i
].Value
<< endl
; // Else format a key/value
119 outFile
.close(); // Close the file
123 string
CIniFile::Content(string FileName
)
125 string s
=""; // Hold our return string
126 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
128 if (Load(FileName
, content
)) // Make sure the file loads
130 for (int i
=0;i
<(int)content
.size();i
++) // Loop through the content
132 if(content
[i
].Comments
!= "") s
+= content
[i
].Comments
; // Add the comments
133 if(content
[i
].Commented
!= ' ') s
+= content
[i
].Commented
; // If this is commented, then add it
134 if((content
[i
].Key
== "")) // Is this a section?
135 s
+= '[' + content
[i
].Section
+ ']'; // Add the section
136 else s
+= content
[i
].Key
+ '=' + content
[i
].Value
; // Or the Key value to the return srting
138 if (i
!= content
.size()) s
+= '\n'; // If this is not the last line, add a CrLf
140 return s
; // Return the contents
146 vector
<string
> CIniFile::GetSectionNames(string FileName
)
148 vector
<string
> data
; // Holds the return data
149 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
151 if (Load(FileName
, content
)) // Make sure the file is loaded
153 for (int i
=0;i
<(int)content
.size();i
++) // Loop through the content
155 if(content
[i
].Key
=="") // If there is no key value, then its a section
156 data
.push_back(content
[i
].Section
); // Add the section to the return data
160 return data
; // Return the data
163 vector
<CIniFile::IniRecord
> CIniFile::GetSection(string SectionName
, string FileName
)
165 vector
<IniRecord
> data
; // Holds the return data
166 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
168 if (Load(FileName
, content
)) // Make sure the file is loaded
170 for (int i
=0;i
<(int)content
.size();i
++) // Loop through the content
172 if((content
[i
].Section
== SectionName
) && // If this is the section name we want
173 (content
[i
].Key
!= "")) // but not the section name itself
174 data
.push_back(content
[i
]); // Add the record to the return data
178 return data
; // Return the data
181 bool CIniFile::RecordExists(string KeyName
, string SectionName
, string FileName
)
183 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
184 if (Load(FileName
, content
)) // Make sure the file is loaded
186 UCase (KeyName
, true);
187 vector
<IniRecord
>::iterator iter
= std::find_if(content
.begin(),
189 CIniFile::RecordSectionKeyIs(SectionName
,KeyName
)); // Locate the Section/Key
191 if (iter
== content
.end()) return false; // The Section/Key was not found
193 return true; // The Section/Key was found
196 bool CIniFile::SectionExists(string SectionName
, string FileName
)
198 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
200 if (Load(FileName
, content
)) // Make sure the file is loaded
202 vector
<IniRecord
>::iterator iter
= std::find_if(content
.begin(),
204 CIniFile::RecordSectionIs(SectionName
)); // Locate the Section
206 if (iter
== content
.end()) return false; // The Section was not found
208 return true; // The Section was found
211 vector
<CIniFile::IniRecord
> CIniFile::GetRecord(string KeyName
, string SectionName
, string FileName
)
213 vector
<IniRecord
> data
; // Holds the return data
214 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
216 if (Load(FileName
, content
)) // Make sure the file is loaded
218 UCase (KeyName
, true);
219 vector
<IniRecord
>::iterator iter
= std::find_if(content
.begin(),
221 CIniFile::RecordSectionKeyIs(SectionName
,KeyName
)); // Locate the IniRecord
223 if (iter
== content
.end()) return data
; // The IniRecord was not found
225 data
.push_back (*iter
); // The IniRecord was found
227 return data
; // Return the IniRecord
230 string
CIniFile::GetValue(string KeyName
, string SectionName
, string FileName
)
232 vector
<IniRecord
> content
= GetRecord(KeyName
,SectionName
, FileName
); // Get the IniRecord
234 if(!content
.empty()) // Make sure there is a value to return
235 return content
[0].Value
; // And return the value
237 return ""; // No value was found
240 bool CIniFile::SetValue(string KeyName
, string Value
, string SectionName
, string FileName
)
242 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
244 if (Load(FileName
, content
)) // Make sure the file is loaded
246 UCase (KeyName
, true);
247 if(!SectionExists(SectionName
,FileName
)) // If the Section doesn't exist
249 IniRecord
s ("",' ',SectionName
,"",""); // Define a new section
250 IniRecord
r ("",' ',SectionName
,KeyName
,Value
); // Define a new record
251 content
.push_back(s
); // Add the section
252 content
.push_back(r
); // Add the record
253 return Save(FileName
,content
); // Save
256 if(!RecordExists(KeyName
,SectionName
,FileName
)) // If the Key doesn't exist
258 vector
<IniRecord
>::iterator iter
= std::find_if(content
.begin(),
260 CIniFile::RecordSectionIs(SectionName
)); // Locate the Section
261 iter
++; // Advance just past the section
262 IniRecord
r ("",' ',SectionName
,KeyName
,Value
); // Define a new record
263 content
.insert(iter
,r
); // Add the record
264 return Save(FileName
,content
); // Save
267 vector
<IniRecord
>::iterator iter
= std::find_if(content
.begin(),
269 CIniFile::RecordSectionKeyIs(SectionName
,KeyName
)); // Locate the IniRecord
271 iter
->Value
= Value
; // Insert the correct value
272 return Save(FileName
,content
); // Save
275 return false; // In the event the file does not load
278 bool CIniFile::RenameSection(string OldSectionName
, string NewSectionName
, string FileName
)
280 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
282 if (Load(FileName
, content
)) // Make sure the file is loaded
284 for(vector
<IniRecord
>::iterator iter
= content
.begin();
285 iter
< content
.end(); iter
++) // Loop through the records
287 if(iter
->Section
== OldSectionName
) // Is this the OldSectionName?
288 iter
->Section
= NewSectionName
; // Now its the NewSectionName
290 return Save(FileName
,content
); // Save
293 return false; // In the event the file does not load
296 bool CIniFile::CommentRecord(CommentChar cc
, string KeyName
,string SectionName
,string FileName
)
298 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
300 if (Load(FileName
, content
)) // Make sure the file is loaded
302 UCase (KeyName
, true);
303 vector
<IniRecord
>::iterator iter
= std::find_if(content
.begin(),
305 CIniFile::RecordSectionKeyIs(SectionName
,KeyName
)); // Locate the Section/Key
307 if (iter
== content
.end()) return false; // The Section/Key was not found
309 iter
->Commented
= cc
; // Change the Comment value
310 return Save(FileName
,content
); // Save
313 return false; // In the event the file does not load
316 bool CIniFile::UnCommentRecord(string KeyName
,string SectionName
,string FileName
)
318 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
320 if (Load(FileName
, content
)) // Make sure the file is loaded
322 UCase (KeyName
, true);
323 vector
<IniRecord
>::iterator iter
= std::find_if(content
.begin(),
325 CIniFile::RecordSectionKeyIs(SectionName
,KeyName
)); // Locate the Section/Key
327 if (iter
== content
.end()) return false; // The Section/Key was not found
329 iter
->Commented
= ' '; // Remove the Comment value
330 return Save(FileName
,content
); // Save
333 return false; // In the event the file does not load
336 bool CIniFile::CommentSection(char CommentChar
, string SectionName
, string FileName
)
338 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
340 if (Load(FileName
, content
)) // Make sure the file is loaded
342 for(vector
<IniRecord
>::iterator iter
= content
.begin(); iter
< content
.end(); iter
++)
344 if(iter
->Section
== SectionName
) // Is this the right section?
345 iter
->Commented
= CommentChar
; // Change the comment value
347 return Save(FileName
,content
); // Save
350 return false; // In the event the file does not load
353 bool CIniFile::UnCommentSection(string SectionName
, string FileName
)
355 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
357 if (Load(FileName
, content
)) // Make sure the file is loaded
359 for(vector
<IniRecord
>::iterator iter
= content
.begin(); iter
< content
.end(); iter
++)
361 if(iter
->Section
== SectionName
) // Is this the right section?
362 iter
->Commented
= ' '; // Remove the comment value
364 return Save(FileName
,content
); // Save
367 return false; // In the event the file does not load
370 bool CIniFile::DeleteRecord(string KeyName
, string SectionName
, string FileName
)
372 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
374 if (Load(FileName
, content
)) // Make sure the file is loaded
376 UCase (KeyName
, true);
377 vector
<IniRecord
>::iterator iter
= std::find_if(content
.begin(),
379 CIniFile::RecordSectionKeyIs(SectionName
,KeyName
)); // Locate the Section/Key
381 if (iter
== content
.end()) return false; // The Section/Key was not found
383 content
.erase(iter
); // Remove the IniRecord
384 return Save(FileName
,content
); // Save
388 return false; // In the event the file does not load
391 bool CIniFile::DeleteSection(string SectionName
, string FileName
)
393 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
395 if (Load(FileName
, content
)) // Make sure the file is loaded
397 for(int i
=(int)content
.size()-1;i
>-1;i
--) // Iterate backwards through the content
399 if(content
[i
].Section
== SectionName
) // Is this related to the Section?
400 content
.erase (content
.begin()+i
); // Then erase it
403 return Save(FileName
,content
); // Save
405 return false; // In the event the file does not load
408 bool CIniFile::SetSectionComments(string Comments
, string SectionName
, string FileName
)
410 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
412 if (Load(FileName
, content
)) // Make sure the file is loaded
414 for(vector
<IniRecord
>::iterator iter
= content
.begin(); iter
< content
.end(); iter
++) // Loop through the records
416 if((iter
->Section
== SectionName
) && // Is this the Section?
417 (iter
->Key
== "")) // And not a record
419 if (Comments
.size() >= 2) // Is there a comment?
421 if (Comments
.substr(Comments
.size()-2) != "\n") // Does the string end in a newline?
422 Comments
+= "\n"; // If not, add one
424 iter
->Comments
= Comments
; // Set the comments
426 return Save(FileName
,content
); // Save
430 return false; // In the event the file does not load
433 bool CIniFile::SetRecordComments(string Comments
, string KeyName
, string SectionName
, string FileName
)
435 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
437 if (Load(FileName
, content
)) // Make sure the file is loaded
439 UCase (KeyName
, true);
440 vector
<IniRecord
>::iterator iter
= std::find_if(content
.begin(),
442 CIniFile::RecordSectionKeyIs(SectionName
,KeyName
)); // Locate the Section/Key
444 if (iter
== content
.end()) return false; // The Section/Key was not found
446 if (Comments
.size() >= 2) // Is there a comment?
448 if (Comments
.substr(Comments
.size()-2) != "\n") // Does the string end in a newline?
449 Comments
+= "\n"; // If not, add one
451 iter
->Comments
= Comments
; // Set the comments
452 return Save(FileName
,content
); // Save
456 return false; // In the event the file does not load
459 vector
<CIniFile::IniRecord
> CIniFile::GetSections(string FileName
)
461 vector
<IniRecord
> data
; // Holds the return data
462 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
464 if (Load(FileName
, content
)) // Make sure the file is loaded
466 for (int i
=0;i
<(int)content
.size();i
++) // Loop through the content
468 if(content
[i
].Key
== "") // If this is a section
469 data
.push_back(content
[i
]); // Add the record to the return data
473 return data
; // Return the data
476 bool CIniFile::Sort(string FileName
, bool Descending
)
478 vector
<CIniFile::IniRecord
> content
; // Used to hold the sorted content
479 vector
<CIniFile::IniRecord
> sections
= GetSections(FileName
); // Get a list of Sections
481 if(!sections
.empty()) // Is there anything to process?
484 if(Descending
) // Descending or Ascending?
485 std::sort(sections
.begin(), sections
.end(), DescendingSectionSort());
486 else // Sort the Sections
487 std::sort(sections
.begin(), sections
.end(), AscendingSectionSort());
489 for(vector
<IniRecord
>::iterator iter
= sections
.begin(); iter
< sections
.end(); iter
++) // For each Section
491 content
.push_back(*iter
); // Add the sorted Section to the content
493 vector
<CIniFile::IniRecord
> records
= GetSection(iter
->Section
,FileName
); // Get a list of Records for this section
495 if(Descending
) // Descending or Ascending?
496 std::sort(records
.begin(), records
.end(), DescendingRecordSort());
497 else // Sort the Records
498 std::sort(records
.begin(), records
.end(), AscendingRecordSort());
500 for(vector
<IniRecord
>::iterator it
= records
.begin(); it
< records
.end(); it
++) // For each IniRecord
501 content
.push_back(*it
); // Add the sorted IniRecord to the content
504 return Save(FileName
,content
); // Save
507 return false; // There were no sections
510 bool CIniFile::AddSection(string SectionName
, string FileName
)
512 vector
<IniRecord
> content
; // Holds the current record // Holds the current record
514 if (Load(FileName
, content
)) // Make sure the file is loaded
516 IniRecord
s ("",' ',SectionName
,"",""); // Define a new section
517 content
.push_back(s
); // Add the section
518 return Save(FileName
,content
); // Save
521 return false; // The file did not open
524 bool CIniFile::Create(string FileName
)
526 vector
<IniRecord
> content
; // Create empty content
527 return Save(FileName
,content
); // Save