1 /* massXpert - the true massist's program.
2    --------------------------------------
3    Copyright(C) 2006,2007 Filippo Rusconi
4 
5    http://www.massxpert.org/massXpert
6 
7    This file is part of the massXpert project.
8 
9    The massxpert project is the successor to the "GNU polyxmass"
10    project that is an official GNU project package(see
11    www.gnu.org). The massXpert project is not endorsed by the GNU
12    project, although it is released ---in its entirety--- under the
13    GNU General Public License. A huge part of the code in massXpert
14    is actually a C++ rewrite of code in GNU polyxmass. As such
15    massXpert was started at the Centre National de la Recherche
16    Scientifique(FRANCE), that granted me the formal authorization to
17    publish it under this Free Software License.
18 
19    This software is free software; you can redistribute it and/or
20    modify it under the terms of the GNU  General Public
21    License version 3, as published by the Free Software Foundation.
22 
23 
24    This software is distributed in the hope that it will be useful,
25    but WITHOUT ANY WARRANTY; without even the implied warranty of
26    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27    General Public License for more details.
28 
29    You should have received a copy of the GNU General Public License
30    along with this software; if not, write to the
31 
32    Free Software Foundation, Inc.,
33 
34    51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
35 */
36 
37 
38 /////////////////////// Qt includes
39 #include<QFile>
40 #include<QDir>
41 #include<QDebug>
42 
43 
44 /////////////////////// Local includes
45 #include "polChemDefCatParser.hpp"
46 #include "configSettings.hpp"
47 
48 
49 namespace massXpert
50 {
51 
PolChemDefCatParser()52   PolChemDefCatParser::PolChemDefCatParser()
53   {
54     mp_configSettings = 0;
55     m_pendingMode = 0;
56     m_configSysUser = 0;
57 
58     return ;
59   }
60 
61 
~PolChemDefCatParser()62   PolChemDefCatParser::~PolChemDefCatParser()
63   {
64     return;
65   }
66 
67 
68   void
setFilePath(const QString & filePath)69   PolChemDefCatParser::setFilePath(const QString &filePath)
70   {
71     m_filePath = filePath;
72   }
73 
74 
75   const QString &
getFilePath()76   PolChemDefCatParser::getFilePath()
77   {
78     return m_filePath;
79   }
80 
81 
82   void
setPendingMode(int pendingMode)83   PolChemDefCatParser::setPendingMode(int pendingMode)
84   {
85     m_pendingMode = pendingMode;
86   }
87 
88 
89   int
getPendingMode()90   PolChemDefCatParser::getPendingMode()
91   {
92     return m_pendingMode;
93   }
94 
95 
96   void
setConfigSysUser(int configSysUser)97   PolChemDefCatParser::setConfigSysUser(int configSysUser)
98   {
99     m_configSysUser = configSysUser;
100   }
101 
102 
103   int
getConfigSysUser()104   PolChemDefCatParser::getConfigSysUser()
105   {
106     return m_configSysUser;
107   }
108 
109 
110   int
parseFiles(const ConfigSettings & configSettings,QList<PolChemDefSpec * > * polChemDefSpecList)111   PolChemDefCatParser::parseFiles(const ConfigSettings &configSettings,
112 				   QList<PolChemDefSpec *>
113 				   *polChemDefSpecList)
114   {
115     mp_configSettings = &configSettings;
116 
117     QDir dir;
118 
119     int count = 0;
120     int totCount = 0;
121 
122     // Polymer chemistry definition catalogue files are located in
123     // pol-chem-defs directories that are located in turn in either
124     // system-wide configuration places, like
125     // /etc/massxpert/pol-chem-defs, for example on UNIX-like systems,
126     // and/or in private user locations, like
127     // $HOME/.massxpert/pol-chem-defs.
128 
129     Q_ASSERT(polChemDefSpecList);
130 
131     // Depending on m_configSysUser, we are going to get all the files
132     // that are polymer chemistry def catalogues in the different
133     // locations and parse these files one after the other.
134 
135     if (m_configSysUser & POLCHEMDEF_CAT_PARSE_SYSTEM_CONFIG)
136       {
137 	// We have to parse all the catalogue files in the system
138 	// configuration directory.
139 
140 	dir.setPath(configSettings.systemPolChemDefCatDir());
141 
142 	if(dir.exists())
143 	  {
144 	    // All the polchem definition catalogues must have the
145 	    // "pol-chem-defs-cat" filename suffix. So we filter the list of
146 	    // files in the directory according to that wildcard expression.
147 
148 	    QStringList filters;
149 	    filters << "*pol-chem-defs-cat";
150 	    dir.setNameFilters(filters);
151 
152 	    dir.setFilter(QDir::Files | QDir::NoSymLinks);
153 
154 	    QFileInfoList list = dir.entryInfoList();
155 
156 	    for (int iter = 0; iter < list.size(); ++iter)
157 	      {
158 		QFileInfo fileInfo = list.at(iter);
159 
160 		m_filePath = fileInfo.absoluteFilePath();
161 		count = parse(polChemDefSpecList,
162 			       POLCHEMDEF_CAT_PARSE_SYSTEM_CONFIG);
163 
164 		if(count == -1)
165 		  return -1;
166 		else
167 		  totCount += count;
168 	      }
169 	  }
170       }
171 
172     if (m_configSysUser & POLCHEMDEF_CAT_PARSE_USER_CONFIG)
173       {
174 	// We have to parse all the catalogue files in the user
175 	// configuration directory.
176 
177 	dir.setPath(configSettings.userPolChemDefCatDir());
178 
179 	if(dir.exists())
180 	  {
181 	    // All the atom definition catalogues must have the
182 	    // "atom-defs-cat" filename suffix. So we filter the list of
183 	    // files in the directory according to that wildcard expression.
184 
185 	    QStringList filters;
186 	    filters << "*pol-chem-defs-cat";
187 	    dir.setNameFilters(filters);
188 
189 	    dir.setFilter(QDir::Files | QDir::NoSymLinks);
190 
191 	    QFileInfoList list = dir.entryInfoList();
192 
193 	    for (int iter = 0; iter < list.size(); ++iter)
194 	      {
195 		QFileInfo fileInfo = list.at(iter);
196 
197 		m_filePath = fileInfo.absoluteFilePath();
198 		count = parse(polChemDefSpecList,
199 			       POLCHEMDEF_CAT_PARSE_USER_CONFIG);
200 
201 		if(count == -1)
202 		  return -1;
203 		else
204 		  totCount += count;
205 	      }
206 	  }
207       }
208 
209     return totCount;
210   }
211 
212 
213   int
parse(QList<PolChemDefSpec * > * polChemDefSpecList,int forSystemOrUser)214   PolChemDefCatParser::parse(QList<PolChemDefSpec *>
215 			      *polChemDefSpecList,
216 			      int forSystemOrUser)
217   {
218     qint64 lineLength;
219 
220     QString line;
221 
222     char buffer [1024];
223 
224     int equalSignIdx = 0;
225     int count = 0;
226 
227     PolChemDefSpec *polChemDefSpec = 0;
228 
229     // We are given a QList in which to store all the
230     // PolChemDefSpec* instances that we create by parsing the
231     // catalogue files.
232     //
233     // Each line in the catalogue(s) that we may have to parse gives the
234     // name of a polymer chemistry definition, like "protein", and the
235     // full pathname of the file in which that definition is stored and
236     // the full pathname to the directory where all its corresponding
237     // stuff is stored.  Example:
238     // protein=/some/dir/protein/protein.xml
239     //
240     // All we have to do is parse each line and for each valid one
241     // create a PolChemDefSpec item that we append/prepend to the
242     // QList passed as parameter.
243 
244     Q_ASSERT(polChemDefSpecList);
245 
246     QFile file(m_filePath);
247 
248     if (! file.open(QFile::ReadOnly))
249       return -1;
250 
251     //qDebug() << "Begin file:" << m_filePath.toAscii();
252 
253 
254     // Get the first line of the file. Next we enter in to a
255     // while loop.
256 
257     lineLength = file.readLine(buffer, sizeof(buffer));
258 
259     while(lineLength != -1)
260       {
261 	// The line is now in buffer, and we want to convert
262 	// it to Unicode by setting it in a QString.
263 	line = buffer;
264 
265 	// Remove all the spaces from the borders: Whitespace means any
266 	// character for which QChar::isSpace() returns true. This
267 	// includes the ASCII characters '\t', '\n', '\v', '\f', '\r',
268 	// and ' '.
269 
270 	line = line.trimmed();
271 
272 	// The line that is in line should contain something like:
273 
274 	// protein=protein/protein.xml(relative path)
275 
276 	// or:
277 
278 	// protein=/some/dir/protein/protein.xml(absolute path)
279 	//
280 	// Note, however that lines beginning with either ' '(space) or
281 	// '\n'(newline) or '#' are comments.
282 
283 	if(line.isEmpty() || line.startsWith('#', Qt::CaseInsensitive))
284 	  {
285 	    lineLength = file.readLine(buffer, sizeof(buffer));
286 	    continue;
287 	  }
288 
289 	// Now some other checks.
290 	equalSignIdx = line.indexOf('=', 0, Qt::CaseInsensitive);
291 
292 	if(equalSignIdx == -1 || line.count('=', Qt::CaseInsensitive) > 1)
293 	  return -1;
294 
295 	// Ok at this point, we might have a nicely parseable line, it
296 	// makes sens to allocate a new AtomDefSpec object.
297 	polChemDefSpec = new(PolChemDefSpec);
298 
299 	polChemDefSpec->setName(line.left(equalSignIdx));
300 
301 	// Of course we have to make sure that we are getting
302 	// a file path corresponding to something we actually
303 	// can use.
304 
305 	QString polChemDefFile = line.right(line.length()
306 					     - equalSignIdx - 1);
307 
308 	QFileInfo fileInfo(polChemDefFile);
309 
310 	if(fileInfo.isRelative())
311 	  {
312 	    // The polymer chemistry definition file is not an
313 	    // absolute filePath. We have to change it into an
314 	    // absolute filePath by prepending the directory path
315 	    // where it is located.
316 
317 	    if (forSystemOrUser == POLCHEMDEF_CAT_PARSE_SYSTEM_CONFIG)
318 	      {
319 		QFile file(mp_configSettings->systemPolChemDefCatDir() +
320 			    QDir::separator() + polChemDefFile);
321 
322 		if(!file.exists())
323 		  {
324 		    delete polChemDefSpec;
325 		    return -1;
326 		  }
327 
328 		polChemDefSpec->setFilePath(file.fileName());
329 	      }
330 	    else if (forSystemOrUser == POLCHEMDEF_CAT_PARSE_USER_CONFIG)
331 	      {
332 		QFile file(mp_configSettings->userPolChemDefCatDir() +
333 			    QDir::separator() + polChemDefFile);
334 
335 		if(!file.exists())
336 		  {
337 		    delete polChemDefSpec;
338 		    return -1;
339 		  }
340 
341 		polChemDefSpec->setFilePath(file.fileName());
342 	      }
343 	    else
344 	      qFatal("%s@%d: Failed to parse polymer chemistry definition "
345 		      "catalogues.", __FILE__, __LINE__);
346 	  }
347 	else
348 	  {
349 	    if (!fileInfo.exists())
350 	      {
351 		delete polChemDefSpec;
352 		return -1;
353 	      }
354 
355 	    polChemDefSpec->setFilePath(polChemDefFile);
356 	  }
357 
358 
359 	// OK, the file exists, and thus we can set the newly allocated
360 	// polChemDefSpec object to the QList passed as parameter.
361 
362 	if(m_pendingMode == POLCHEMDEF_CAT_PARSE_APPEND_CONFIG)
363 	  polChemDefSpecList->append(polChemDefSpec);
364 	else
365 	  polChemDefSpecList->prepend(polChemDefSpec);
366 
367 	++count;
368 
369 	//qDebug() << "Parsed line: " << line.toAscii();
370 
371 	lineLength = file.readLine(buffer, sizeof(buffer));
372       }
373     // while(lineLength != -1)
374 
375     file.close();
376 
377     //qDebug() << "Endfile:" << m_filePath.toAscii();
378 
379     return count;
380   }
381 
382 } // namespace massXpert
383