00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef MECHSYS_FILEPARSER_H
00023 #define MECHSYS_FILEPARSER_H
00024
00025 #include <fstream>
00026 #include <sstream>
00027 #include <algorithm>
00028 #include <map>
00029
00030 #ifdef HAVE_CONFIG_H
00031 #include "config.h"
00032 #else
00033 #ifndef REAL
00034 #define REAL double
00035 #endif
00036 #endif
00037
00038 #include "util/array.h"
00039 #include "util/string.h"
00040 #include "util/lineparser.h"
00041 #include "util/exception.h"
00042
00043 class FileParser
00044 {
00045 public:
00046
00047 FileParser(String const & Filename) : _comm_char('#'), _filename(Filename) { _open(_filename); }
00048
00049 ~FileParser() { _file.close(); }
00050
00051 struct Tags
00052 {
00053 String L1;
00054 String L2;
00055 String Comment;
00056 bool Required;
00057 String Default;
00058 };
00059 typedef std::map< String,Array<REAL> > Table;
00060 typedef std::map< String,String > StructVals;
00061
00062 int CurrentLineNumber ();
00063 String GetCurrentLine ();
00064 bool TryGetCurrentLine (String & line);
00065 void Advance ();
00066 void JumpCommentsOrBlanks ();
00067 template<typename Type>
00068 void ReadFirstWord (Type & Val);
00069 bool IsEOF () { return _is_EOF; }
00070 void Reset () { _file.close(); _open(_filename); }
00071 template<typename Type>
00072 void ReadNextValue (Type & Val) { JumpCommentsOrBlanks(); ReadFirstWord(Val); Advance(); }
00073 template<typename Type>
00074 void FindKeyAndFillArray (String const & StrKey, Array<Type> & A);
00075 void SetCommChar (char CommChar) { _comm_char = CommChar; }
00076 void StructFile (Tags const * tags, int num_tags, StructVals & values);
00077 void ReadTable (Table & t);
00078
00079 static bool CheckForFile(String const & Filename)
00080 {
00081
00082 std::ifstream file(Filename.GetSTL().c_str(),std::ios::in);
00083 if (file.fail()) { return false; }
00084 else { file.close(); return true; }
00085 }
00086 static String GetBackupFilename(String const & originalFN)
00087 {
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 if (FileParser::CheckForFile(originalFN))
00099 {
00100 if ( originalFN[ originalFN.size()-1 ] == '~' )
00101 return originalFN;
00102 else
00103 {
00104 String tmp_fn = originalFN;
00105 tmp_fn.append(_T("~"));
00106 return tmp_fn;
00107 }
00108 }
00109 else
00110 return originalFN;
00111 }
00112 private:
00113
00114 char _comm_char;
00115 bool _is_EOF;
00116 String _filename;
00117 std::ifstream _file;
00118 String _str_current_line;
00119 int _current_line_num;
00120
00121 void _open(String const & Filename);
00122 };
00123
00124
00126
00127
00128 inline int FileParser::CurrentLineNumber()
00129 {
00130 if (_is_EOF)
00131 throw new Fatal(_("FileParser::GetCurrentLine: Can not return current line number because EOF. Filename = < %s >"), _filename.c_str());
00132 return _current_line_num;
00133 }
00134
00135 inline String FileParser::GetCurrentLine()
00136 {
00137 if (_is_EOF)
00138 throw new Fatal(_("FileParser::GetCurrentLine: Can not return current line number because EOF. Filename = < %s >"), _filename.c_str());
00139 return _str_current_line;
00140 }
00141
00142 inline bool FileParser::TryGetCurrentLine(String & line)
00143 {
00144 if (_is_EOF) return false;
00145 else
00146 {
00147 line = _str_current_line;
00148 return true;
00149 }
00150 }
00151
00152 inline void FileParser::Advance()
00153 {
00154
00155 if (_is_EOF)
00156 throw new Fatal(_("FileParser::Advance: Can not advance because EOF"));
00157
00158
00159 std::string buf;
00160 if (!std::getline(_file, buf)) _is_EOF = true;
00161 else
00162 {
00163 _str_current_line = buf;
00164 _current_line_num++;
00165 }
00166 }
00167
00168 inline void FileParser::JumpCommentsOrBlanks()
00169 {
00170 do
00171 {
00172 std::istringstream iss(_str_current_line.GetSTL());
00173 String word;
00174 if (iss>>word)
00175 {
00176 if (word[0]==_comm_char)
00177 {
00178 if (!TryGetCurrentLine(_str_current_line)) break;
00179 Advance();
00180 }
00181 else
00182 break;
00183 }
00184 else
00185 {
00186 if (!TryGetCurrentLine(_str_current_line)) break;
00187 Advance();
00188 }
00189 } while (true);
00190 }
00191
00192 template<typename Type>
00193 inline void FileParser::ReadFirstWord(Type & Val)
00194 {
00195 std::istringstream iss(_str_current_line.GetSTL());
00196 if (!(iss >> Val))
00197 throw new Fatal(_("FileParser::ReadFirstWord: Invalid data value. _current_line_num = %d"), _current_line_num);
00198 }
00199
00200 inline void FileParser::_open(String const & Filename)
00201 {
00202
00203 _is_EOF = false;
00204
00205
00206 _file.open(Filename.GetSTL().c_str(), std::ios::in);
00207 if (_file.fail())
00208 throw new Warning(_("FileParser::Constructor: Could not open file < %s >"), Filename.c_str());
00209
00210
00211 std::string buf;
00212 if (!std::getline(_file, buf))
00213 throw new Warning(_("FileParser::Constructor: Could not read first line of file < %s >"), Filename.c_str());
00214 _str_current_line = buf;
00215 _current_line_num = 1;
00216 }
00217
00218 template<typename Type>
00219 inline void FileParser::FindKeyAndFillArray(String const & StrKey, Array<Type> & A)
00220 {
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235 bool is_key_found = false;
00236 do
00237 {
00238
00239 if (_is_EOF)
00240 throw new Fatal(_("FileParser::FindKeyAndFillArray: Could not find StrKey = < %s > inside file < %s >"), StrKey.c_str(), _filename.c_str());
00241
00242
00243 JumpCommentsOrBlanks();
00244 LineParser LP(GetCurrentLine());
00245 String str_key;
00246 LP >> str_key;
00247 if (str_key==StrKey)
00248 {
00249 Type value;
00250 while (LP>>value)
00251 {
00252 A.push_back(value);
00253 }
00254 is_key_found = true;
00255 }
00256 else
00257 Advance();
00258 } while (!is_key_found);
00259 }
00260
00261 inline void FileParser::StructFile(Tags const * tags, int num_tags, StructVals & values)
00262 {
00263
00264 if (IsEOF()) throw new Fatal(_("FileParser::StructFile: Could not read file < %s >. Probably file was already read."), _filename.c_str());
00265
00266
00267 values.clear();
00268 for (int i=0; i<num_tags; ++i)
00269 {
00270 String fullkey(tags[i].L1); fullkey.append(_T(".")); fullkey.append(tags[i].L2);
00271 values[fullkey] = "";
00272 }
00273
00274
00275 while (!IsEOF())
00276 {
00277 JumpCommentsOrBlanks();
00278 String line;
00279 if (!TryGetCurrentLine(line)) break;
00280 LineParser LP(line);
00281 Advance();
00282 String key; LP>>key;
00283 String subkey; LP>>subkey;
00284 String fullkey(key); fullkey.append(_T(".")); fullkey.append(subkey);
00285 bool found = false;
00286 for (int i=0; i<num_tags; ++i)
00287 {
00288 if (key==tags[i].L1 && subkey==tags[i].L2)
00289 {
00290 String val;
00291 while (LP>>val)
00292 {
00293 if (val[0]==_comm_char) break;
00294 else
00295 {
00296 if (values[fullkey].size()>0) values[fullkey].append(_T(" "));
00297 values[fullkey].append(val);
00298 }
00299 }
00300 found = true;
00301 break;
00302 }
00303 }
00304 if (!found)
00305 throw new Fatal(_("FileParser::StructFile: File < %s >: Pair < %s %s > is not valid."), _filename.c_str(), key.c_str(), subkey.c_str());
00306 }
00307
00308
00309 for (int i=0; i<num_tags; ++i)
00310 {
00311 String fullkey(tags[i].L1); fullkey.append(_T(".")); fullkey.append(tags[i].L2);
00312
00313
00314 if (tags[i].Required && values[fullkey]=="")
00315 throw new Fatal(_("FileParser::StructFile: The pair < %s %s > must be provided by file < %s >"), tags[i].L1.c_str(), tags[i].L2.c_str(), _filename.c_str());
00316
00317
00318 if (!tags[i].Required && tags[i].Default!=_T("") && values[fullkey]==_T(""))
00319 values[fullkey] = tags[i].Default;
00320 }
00321
00322 }
00323
00324 inline void FileParser::ReadTable(Table & T)
00325 {
00326
00327 if (IsEOF()) throw new Fatal(_("FileParser::ReadTable: Could not read file < %s >. Probably file was already read."), _filename.c_str());
00328
00329
00330 Array<String> header;
00331 LineParser LP(GetCurrentLine());
00332 String key;
00333 while (LP>>key) header.push_back(key);
00334 if (header.size()<1) throw new Fatal(_("FileParser::ReadTable: File format invalid < %s >. Header must have at least one tag (one column)"), _filename.c_str());
00335
00336
00337 T.clear();
00338 Array<REAL> a_null;
00339 for (size_t i=0; i<header.size(); ++i)
00340 T[header[i]] = a_null;
00341
00342
00343 size_t num_lines=0;
00344 while (!IsEOF())
00345 {
00346
00347 Advance();
00348 String line;
00349 if (!TryGetCurrentLine(line)) break;
00350 LP.Reset(line);
00351 size_t i_col=0; REAL col_val;
00352 while (LP>>col_val)
00353 {
00354 if (i_col>header.size()-1)
00355 throw new Fatal(_("FileParser::ReadTable: File < %s >: Too many values: Number of columns (%d) must be equal to the number (%d) of header tags"), _filename.c_str(), i_col+1, header.size());
00356 T[header[i_col]].push_back(col_val);
00357 i_col++;
00358 }
00359 if (i_col!=header.size())
00360 throw new Fatal(_("FileParser::ReadTable: File < %s >: Not enough values: Number of columns (%d) must be equal to the number (%d) of header tags"), _filename.c_str(), i_col, header.size());
00361 num_lines++;
00362 }
00363
00364
00365 Table::const_iterator it = T.begin();
00366 while (it!=T.end())
00367 {
00368 if (it->second.size()!=num_lines)
00369 throw new Fatal(_("FileParser::ReadTable: INTERNAL ERROR: There is an inconsistency with the number of lines of each column (%d != %d)"), it->second.size(), num_lines);
00370 it++;
00371 }
00372
00373 }
00374
00375 #endif //MECHSYS_FILEPARSER
00376
00377