Salome HOME
Improve build procedure
[tools/simanio.git] / src / SimanIO_Configuration.cxx
1 // Copyright (C) 2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "SimanIO_Configuration.hxx"
21
22 #include <stdlib.h>
23
24 // maximum length of the line in the parsed conf file
25 const int MAX_BUFFER_SIZE=10000;
26
27 using namespace std;
28
29 SimanIO_Configuration::SimanIO_Configuration()
30 {
31 }
32
33 ///! Returns true is the given symbol is white space
34 static bool IsWhite(const char theSym) {
35   return theSym == ' ' || theSym == '\t';
36 }
37
38 ///! Returns true if theLine starts with theCommand, returns in theVal rest part of the line in this case
39 static bool IsCommand(const char* theCommand, char* theLine, char*& theVal) {
40   string aLine(theLine);
41   char* aComPtr = (char*)theCommand;
42   theVal = theLine;
43   while(*aComPtr != 0 && *theVal != 0) {
44     if (IsWhite(*aComPtr)) { // skip white spaces in the command line
45       aComPtr++;
46       continue;
47     }
48     if (IsWhite(*theVal)) { // skip white spaces in the processed line
49       theVal++;
50       continue;
51     }
52      //cout<<"Compare symbols "<<tolower(*aComPtr)<<" and "<<tolower(*theVal)<<endl;
53     if (tolower(*aComPtr) != tolower(*theVal)) // symbols are not match (case is not significant)
54       break;
55     aComPtr++;
56     theVal++;
57   }
58   if (*aComPtr == 0) { // command has been found
59     while(*theVal != 0 && IsWhite(*theVal)) { // skip white spaces in the processed line
60       theVal++;
61     }
62     return true;
63   }
64   return false;
65 }
66
67 ///! Returns true if theText1 fully equal to theText2
68 static bool IsValue(const char* theText1, const char* theText2) {
69   int a;
70   for(a = 0; theText1[a] != 0 && theText2[a] != 0; a++)
71     if (theText1[a] != theText2[a]) return false;
72   return theText1[a] == 0 && theText2[a] == 0;
73 }
74
75 ///! Converts string to the integer value, or returns the default vaule if failed
76 static int toInt(const char* theStr, int theDefault) {
77   int aResult;
78   try {
79     aResult = atol(theStr);
80   } catch(...) {
81     aResult = theDefault;
82   }
83   return aResult;
84 }
85
86 // unification of the error handling in the Parse method
87 #define PARSE_ERROR(condition, message) if (condition) {cerr<<message<<endl; return false;}
88
89 bool SimanIO_Configuration::Parse(const char* theConfFileName)
90 {
91   ifstream f(theConfFileName);
92   myF = &f;
93   PARSE_ERROR(!f.good(), "Can not read conf file "<<theConfFileName)
94   char aBuffer[MAX_BUFFER_SIZE];
95   myBuffer = aBuffer; // buffer for one line reading
96   myReuseLine = false; // to read current line from the file
97   char* aVal; // value in line, that is located after the identifier of the command
98   while(!f.eof()) {
99     ReadLine();
100     if (IsCommand("Study ID :", myBuffer, aVal)) {
101       // skip study ID: this info is known in Link
102     } else if (IsCommand("Scenario ID :", myBuffer, aVal)) {
103       // skip scenario ID: this info is known in Link
104     } else if (IsCommand("User ID :", myBuffer, aVal)) {
105       // skip user ID: this info is known in Link
106     } else if (IsCommand("Activity", myBuffer, aVal)) {
107       if (!ParseActivity(aVal)) return false;
108     } else {
109       PARSE_ERROR(true, "Invalid line of conf file: '"<<myBuffer<<"'");
110     }
111   }
112   return true;
113 }
114
115 bool SimanIO_Configuration::ParseActivity(char* aName)
116 {
117   SimanIO_Activity aNewActivity;
118   aNewActivity.SetName(aName);
119   int activityID = -1; // to be imported later
120   char* aVal; // value in line, that is located after the identifier of the command
121   while(!myF->eof()) {
122     ReadLine();
123     if (IsCommand("Activity ID :", myBuffer, aVal)) {
124       PARSE_ERROR(activityID != -1, "Duplicated activity identifier '"<<myBuffer<<"'");
125       activityID = toInt(aVal, -1);
126       PARSE_ERROR(activityID < 1, "Invalid activity identifier '"<<aVal<<"'");
127     } else if (IsCommand("Module :", myBuffer, aVal) || IsCommand("SALOME Module :", myBuffer, aVal)) { // read only if module not yet imported before
128       char* aVal2;
129       PARSE_ERROR(aNewActivity.Module()[0] != 0, "Duplicated module name in '"<<myBuffer<<"'")
130       PARSE_ERROR(aVal[0] == 0, "Invalid module name in '"<<myBuffer<<"'")
131       aNewActivity.SetModule(aVal);
132     } else if (IsCommand("Document :", myBuffer, aVal)) {
133       if (!ParseDocument(aVal, aNewActivity)) return false;
134     } else { // unknown command will be processed in higher level method
135       myReuseLine = true;
136       break;
137     }
138   }
139   PARSE_ERROR(activityID == -1, "Activity '"<<aNewActivity.Name()<<"' ID is not defined");
140   PARSE_ERROR(aNewActivity.Module()[0] == 0, "Module of the activity '"<<aNewActivity.Name()<<"' is not defined");
141   if (!IsValue("null", aNewActivity.Module())) // skip activities with module name "null"
142     AddActivity(aNewActivity, activityID);
143   return true;
144 }
145
146 bool SimanIO_Configuration::ParseDocument(char* aName, SimanIO_Activity& theActivity)
147 {
148   SimanIO_Document aNewDocument;
149   aNewDocument.SetName(aName);
150   int aDocID = -1; // to be imported later
151   char* aVal; // value in line, that is located after the identifier of the command
152   while(!myF->eof()) {
153     ReadLine();
154     if (IsCommand("Document ID :", myBuffer, aVal)) {
155       PARSE_ERROR(aDocID != -1, "Duplicated document identifier '"<<myBuffer<<"'");
156       aDocID = toInt(aVal, -1);
157       PARSE_ERROR(aDocID < 1, "Invalid document identifier '"<<aVal<<"'");
158     } else if (IsCommand("Source file:", myBuffer, aVal) || IsCommand("Result file:", myBuffer, aVal)) {
159       if (!ParseFile(aNewDocument)) return false;
160     } else { // unknown command will be processed in higher level method
161       myReuseLine = true;
162       break;
163     }
164   }
165   PARSE_ERROR(aDocID == -1, "Document '"<<aNewDocument.Name()<<"' ID is not defined");
166   theActivity.AddDocument(aDocID, aNewDocument);
167   return true;
168 }
169
170 bool SimanIO_Configuration::ParseFile(SimanIO_Document& theDocument)
171 {
172   SimanIO_File aNewFile;
173   aNewFile.id = -1;
174   int aDocID = -1; // to be imported later
175   char* aVal; // value in line, that is located after the identifier of the command
176   
177   // current line contains one of the next two commands
178   if (IsCommand("Result file :", myBuffer, aVal)) {
179     aNewFile.result = true;
180     aNewFile.url = aVal;
181   } else if (IsCommand("Source file :", myBuffer, aVal)) {
182     aNewFile.result = false;
183     aNewFile.url = aVal;
184   }
185   PARSE_ERROR(aNewFile.url.empty(), "File '"<<myBuffer<<"' has invalid URL");
186   while(!myF->eof()) {
187     ReadLine();
188     if (IsCommand("Automatic processing :", myBuffer, aVal)) {
189       char* aVal2;
190       if (IsCommand("file-download", aVal, aVal2)) aNewFile.proc = FILE_DOWNLOAD;
191       else if (IsCommand("file-import", aVal, aVal2)) aNewFile.proc = FILE_IMPORT;
192       else PARSE_ERROR(true, "Invalid automatic processing value '"<<aVal<<"'");
193     } else if (IsCommand("State :", myBuffer, aVal)) {
194       char* aVal2;
195       if (IsCommand("file-actual", aVal, aVal2)) aNewFile.state = FILE_ACTUAL;
196       else if (IsCommand("file-outdated", aVal, aVal2)) aNewFile.state = FILE_OUTDATED;
197       else PARSE_ERROR(true, "Invalid state value '"<<aVal<<"'");
198     } else if (IsCommand("File ID :", myBuffer, aVal)) {
199       PARSE_ERROR(aNewFile.id != -1, "Duplicated file identifier '"<<myBuffer<<"'");
200       aNewFile.id = toInt(aVal, -1);
201       PARSE_ERROR(aNewFile.id < 0, "Invalid file identifier '"<<aVal<<"'");
202     } else { // unknown command will be processed in higher level method
203       myReuseLine = true;
204       break;
205     }
206   }
207   PARSE_ERROR(aNewFile.id < 0, "File '"<<aNewFile.url<<"' ID is not defined");
208   theDocument.AddFile(aNewFile);
209   return true;
210 }
211
212 int SimanIO_Configuration::AddActivity(const SimanIO_Activity& theActivity, const int theId)
213 {
214   int anId = theId;
215   if (theId < 0) { // generate the maximum unique Id
216     if (myActivities.empty()) anId = 1; // the first
217     else {
218       anId = myActivities.rbegin()->first + 1; // take the maximum Id plus one (in map integers are ordered)
219     }
220   }
221   myActivities[anId] = theActivity;
222 }
223
224 SimanIO_Activity& SimanIO_Configuration::GetOrCreateActivity(const int theId)
225 {
226   if (myActivities.find(theId) == myActivities.end()) {
227     myActivities[theId] = SimanIO_Activity();
228   }
229   return myActivities[theId];
230 }
231
232 void SimanIO_Configuration::ReadLine() {
233   if (myReuseLine) { // reuse current line
234     myReuseLine = false;
235     return;
236   }
237   do {
238     myF->getline(myBuffer, MAX_BUFFER_SIZE - 1);
239   } while(!myF->eof() && myBuffer[0] == 0); // continue if there is empty line
240 }
241
242 /////////////////////////////////// iterator methods ///////////////////////////
243
244 SimanIO_Configuration::ActivitiesIterator::ActivitiesIterator(SimanIO_Configuration& theConf)
245 {
246   myIter = theConf.myActivities.begin();
247   myEnd = theConf.myActivities.end();
248 }
249
250 void SimanIO_Configuration::ActivitiesIterator::Next()
251 {
252   myIter++;
253 }
254
255 bool SimanIO_Configuration::ActivitiesIterator::More()
256 {
257   return myIter != myEnd;
258 }
259
260 const int SimanIO_Configuration::ActivitiesIterator::ActivityId()
261 {
262   return myIter->first;
263 }
264
265 SimanIO_Activity& SimanIO_Configuration::ActivitiesIterator::Activity()
266 {
267   return myIter->second;
268 }