Add Dirk Luetjen's ssphys libraries and command-line tool
[vss2svn.git] / ssphys / SSLib / IniFile.cpp
blobb0ca230e0e6bd3147c53f316ed3ca6f156d720d9
1 #include "StdAfx.h"
2 #include "inifile.h"
4 using namespace std;
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")
24 //{
25 // Trim(str, ChrsToTrim, 2);
26 //}
28 //inline void TrimLeft(std::string& str, const std::string & ChrsToTrim = " \t\n\r")
29 //{
30 // Trim(str, ChrsToTrim, 1);
31 //}
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
63 } else {
64 r.Commented = s[0]; // Save the comment character
65 s.erase(s.begin()); // Remove the comment for further processing
66 Trim(s);
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
79 CurrentSection = s;
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
88 UCase (r.Key, true);
89 r.Value = s.substr(s.find('=')+1); // Set the Value to everything after the = sign
91 Trim (r.Key);
92 Trim (r.Value);
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
100 return true;
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
114 else
115 outFile << content[i].Commented << content[i].Key
116 << "=" << content[i].Value << endl; // Else format a key/value
119 outFile.close(); // Close the file
120 return true;
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
143 return "";
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(),
188 content.end(),
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(),
203 content.end(),
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(),
220 content.end(),
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(),
259 content.end(),
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(),
268 content.end(),
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(),
304 content.end(),
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(),
324 content.end(),
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(),
378 content.end(),
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(),
441 content.end(),
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