LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
LSSTDataManagementBasePackage
PAFParser.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * Copyright 2008, 2009, 2010 LSST Corporation.
4  *
5  * This product includes software developed by the
6  * LSST Project (http://www.lsst.org/).
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the LSST License Statement and
19  * the GNU General Public License along with this program. If not,
20  * see <http://www.lsstcorp.org/LegalNotices/>.
21  */
22 
33 #include <stdexcept>
34 
35 namespace lsst {
36 namespace pex {
37 namespace policy {
38 namespace paf {
39 
40 //@cond
41 
42 using namespace std;
45 using boost::regex;
46 using boost::match_results;
47 using boost::regex_search;
48 using boost::regex_match;
49 using boost::smatch;
50 
51 const regex PAFParser::COMMENT_LINE("^\\s*#");
52 const regex PAFParser::EMPTY_LINE("^(\\s*)$");
53 const regex PAFParser::SPACE_SRCH("^(\\s+)");
54 const regex PAFParser::PARAM_SRCH("^(\\s*)(\\w[\\w\\d\\.]*)\\s*:\\s*");
55 const regex PAFParser::NAME_MTCH("\\w[\\w\\d]*(\\.\\w[\\w\\d])*");
56 const regex PAFParser::OPEN_SRCH("^\\{\\s*");
57 const regex PAFParser::CLOSE_SRCH("^\\s*\\}\\s*");
58 const regex PAFParser::DOUBLE_VALUE
59  ("^([\\+\\-]?((((\\d+\\.\\d*)|(\\d*\\.\\d+))([eE][\\-\\+]?\\d{1,3})?)"
60  "|(\\d+[eE][\\-\\+]?\\d{1,3})))\\s*");
61 const regex PAFParser::INT_VALUE("^([+-]?\\d+)\\s*");
62 const regex PAFParser::ATRUE_VALUE("^([tT]rue)\\s*");
63 const regex PAFParser::AFALSE_VALUE("^([fF]alse)\\s*");
64 const regex PAFParser::QQSTRING_VALUE("^\"([^\"]*)\"\\s*");
65 const regex PAFParser::QSTRING_VALUE("^'([^']*)'\\s*");
66 const regex PAFParser::QQSTRING_START("^\"([^\"]*\\S)\\s*");
67 const regex PAFParser::QSTRING_START("^'([^']*\\S)\\s*");
68 const regex PAFParser::QQSTRING_EMPTYSTART("^\"\\s*$");
69 const regex PAFParser::QSTRING_EMPTYSTART("^'\\s*$");
70 const regex PAFParser::QQSTRING_END("^\\s*([^\"]*)\"\\s*");
71 const regex PAFParser::QSTRING_END("^\\s*([^']*)'\\s*");
72 const regex PAFParser::BARE_STRING_LINE("^\\s*(\\S(.*\\S)?)\\s*");
73 const regex PAFParser::BARE_STRING("^\\s*([^#\\}\\s]([^#\\}]*[^#\\}\\s])?)\\s*[#}]?");
74 const regex PAFParser::URN_VALUE("^@(urn\\:|@)");
75 const regex PAFParser::FILE_VALUE("^@");
76 
77 /*
78  * create a parser to load a Policy
79  */
81  : PolicyParser(policy), _buffer(), _lineno(0), _depth(0)
82 { }
83 PAFParser::PAFParser(Policy& policy, bool strict)
84  : PolicyParser(policy, strict), _buffer(), _lineno(0), _depth(0)
85 { }
86 
87 /*
88  * delete this parser
89  */
91 
92 /*
93  * parse the data found on the given stream
94  * @param strm the stream to read PAF-encoded data from
95  * @return int the number of values primitive values parsed.
96  */
97 int PAFParser::parse(istream& is) {
98  int count = _parseIntoPolicy(is, _pol);
99  // log count
100 
101  return count;
102 }
103 
104 ios::iostate PAFParser::_nextLine(istream& is, string& line) {
105  if (_buffer.size() > 0) {
106  line = _buffer.front();
107  _buffer.pop_front();
108  }
109  else {
110  line = "";
111  getline(is, line);
112  if (is.fail()) return is.rdstate();
113  if (is.eof() and line.length() == 0) return ios::eofbit;
114  }
115  _lineno++;
116  return ios::iostate(0);
117 }
118 
119 void PAFParser::_pushBackLine(const string& line) {
120  _buffer.push_front(line);
121  _lineno--;
122 }
123 
124 int PAFParser::_parseIntoPolicy(istream& is, Policy& policy) {
125 
126  string line, name, value;
127  smatch matched;
128  int count = 0;
129 
130  while (!_nextLine(is, line)) {
131  if (regex_search(line, COMMENT_LINE))
132  continue;
133 
134  if (regex_search(line, matched, CLOSE_SRCH)) {
135  _depth--;
136  if (_depth < 0) {
137  string msg = "extra '}' character encountered.";
138  if (_strict) throw LSST_EXCEPT(FormatSyntaxError, msg, _lineno);
139  // log message
140  }
141 
142  _pushBackLine(matched.suffix());
143  return count;
144  }
145  else if (regex_search(line, matched, PARAM_SRCH)) {
146 
147  name = matched.str(2);
148  if (! regex_search(name, NAME_MTCH)) {
149  string msg = "Not a legal names designation: ";
150  msg.append(name);
151  if (_strict)
152  throw LSST_EXCEPT(FormatSyntaxError, msg, _lineno);
153  // log warning
154  continue;
155  }
156 
157  value = matched.suffix();
158  count += _addValue(name, value, policy, is);
159  }
160  else if (! regex_search(line, matched, EMPTY_LINE)) {
161  string msg = "Bad parameter name format: " + line;
162  if (_strict)
163  throw LSST_EXCEPT(FormatSyntaxError, msg, _lineno);
164  // log warning
165  continue;
166  }
167  }
168  if (! is.eof() && is.fail()) throw LSST_EXCEPT(ParserError, "read error", _lineno);
169 
170  return count;
171 }
172 
173 int PAFParser::_addValue(const string& propname, string& value,
174  Policy& policy, istream& is)
175 {
176  string element, msg;
177  smatch matched;
178  int count = 0;
179 
180  if (value.size() == 0 || regex_search(value, COMMENT_LINE))
181  // no value provide; ignore it.
182  return count;
183 
184  if (regex_search(value, matched, OPEN_SRCH)) {
185  _depth++;
186 
187  // make a sub-policy
188  Policy::Ptr subpolicy(new Policy());
189  policy.add(propname, subpolicy);
190 
191  // look for extra stuff on the line
192  value = matched.suffix();
193  if (value.size() > 0 && ! regex_search(value, COMMENT_LINE))
194  _pushBackLine(value);
195 
196  // fill in the sub-policy
197  count += _parseIntoPolicy(is, *subpolicy);
198  }
199  else if (regex_search(value, matched, DOUBLE_VALUE)) {
200  do {
201  element = matched.str(1);
202  value = matched.suffix();
203 
204  char *unparsed;
205  double d = strtod(element.c_str(), &unparsed);
206  if (unparsed && (*unparsed)) {
207  msg = "value contains unparsable non-numeric data: ";
208  msg.append(element);
209  if (_strict) throw LSST_EXCEPT(FormatSyntaxError, msg, _lineno);
210  break;
211  }
212 
213  policy.add(propname, d);
214  count++;
215  if (value.size() > 0) {
216  if (regex_search(value,COMMENT_LINE)) {
217  value.erase();
218  break;
219  }
220  else if (regex_search(value, CLOSE_SRCH)) {
221  _pushBackLine(value);
222  return count;
223  }
224  }
225  else
226  break;
227  } while (regex_search(value, matched, DOUBLE_VALUE));
228 
229  if (value.size() > 0) {
230  msg = "Expecting double value, found: ";
231  msg.append(value);
232  if (_strict) throw LSST_EXCEPT(FormatSyntaxError, msg, _lineno);
233  // log message
234  }
235  }
236  else if (regex_search(value, matched, INT_VALUE)) {
237  do {
238  element = matched.str(1);
239  value = matched.suffix();
240 
241  char *unparsed;
242  long lval = strtol(element.c_str(), &unparsed, 10);
243  if (unparsed && (*unparsed)) {
244  msg = "value contains unparsable non-integer data: ";
245  msg.append(element);
246  if (_strict) throw LSST_EXCEPT(FormatSyntaxError, msg, _lineno);
247  continue;
248  }
249 
250  int ival = int(lval);
251  if (lval-ival != 0) {
252  // longs are unsupported
253  msg = "unsupported long integer value found: ";
254  msg.append(value);
255  if (_strict) throw LSST_EXCEPT(UnsupportedSyntax, msg, _lineno);
256  // log a message
257  }
258 
259  policy.add(propname, ival);
260  count++;
261 
262  if (value.size() > 0) {
263  if (regex_search(value,COMMENT_LINE)) {
264  value.erase();
265  break;
266  }
267  else if (regex_search(value, CLOSE_SRCH)) {
268  _pushBackLine(value);
269  return count;
270  }
271  }
272  else
273  break;
274  } while (regex_search(value, matched, INT_VALUE));
275 
276  if (value.size() > 0) {
277  msg = "Expecting integer value, found: ";
278  msg.append(value);
279  if (_strict) throw LSST_EXCEPT(FormatSyntaxError, msg, _lineno);
280  // log message
281  }
282  }
283  else if (regex_search(value, matched, ATRUE_VALUE) ||
284  regex_search(value, matched, AFALSE_VALUE))
285  {
286  do {
287  element = matched.str(1);
288  value = matched.suffix();
289  if (element[0] == 't' || element[0] == 'T')
290  policy.add(propname, true);
291  else
292  policy.add(propname, false);
293  count++;
294 
295  if (value.size() > 0) {
296  if (regex_search(value,COMMENT_LINE)) {
297  value.erase();
298  break;
299  }
300  else if (regex_search(value, CLOSE_SRCH)) {
301  _pushBackLine(value);
302  return count;
303  }
304  }
305  else
306  break;
307  } while (regex_search(value, matched, ATRUE_VALUE) ||
308  regex_search(value, matched, AFALSE_VALUE));
309 
310  if (value.size() > 0) {
311  msg = "Expecting boolean value, found: ";
312  msg.append(value);
313  if (_strict)
314  throw LSST_EXCEPT(FormatSyntaxError, msg, _lineno);
315  // log message
316  }
317  }
318  else if (value.at(0) == '\'' || value.at(0) == '"') {
319  // we are starting a string
320  do {
321  if (regex_search(value, matched, QQSTRING_VALUE) ||
322  regex_search(value, matched, QSTRING_VALUE))
323  {
324  element = matched.str(1);
325  value = matched.suffix();
326 
327  policy.add(propname, element);
328  count++;
329 
330  if (value.size() > 0 && regex_search(value, COMMENT_LINE))
331  value.erase();
332  }
333  else if (regex_search(value, matched, QQSTRING_EMPTYSTART) ||
334  regex_search(value, matched, QQSTRING_START) ) {
335  // start of multi-line string
336  element = (matched.size() > 1) ? matched.str(1) : "";
337  while (!_nextLine(is, value)) {
338  element.append(" ");
339  if (regex_search(value, matched, QQSTRING_END)) {
340  element.append(matched.str(1));
341  policy.add(propname, element);
342  count++;
343  value = matched.suffix();
344  break;
345  }
346  else if (regex_search(value, matched, BARE_STRING_LINE)) {
347  element.append(matched.str(1));
348  }
349  }
350  if (is.eof()) {
351  if (_strict) throw LSST_EXCEPT(EOFError, _lineno);
352  // log message
353  }
354  if (is.fail())
355  throw LSST_EXCEPT(ParserError, "read error", _lineno);
356  }
357  else if (regex_search(value, matched, QSTRING_EMPTYSTART) ||
358  regex_match(value, matched, QSTRING_START)) {
359  // start of multi-line string
360  element = (matched.size() > 1) ? matched.str(1) : "";
361  while (!_nextLine(is, value)) {
362  element.append(" ");
363  if (regex_search(value, matched, QSTRING_END)) {
364  element.append(matched.str(1));
365  policy.add(propname, element);
366  count++;
367  value = matched.suffix();
368  break;
369  }
370  else if (regex_match(value, matched, BARE_STRING_LINE)) {
371  element.append(matched.str(1));
372  }
373  }
374  if (is.eof()) {
375  if (_strict) throw LSST_EXCEPT(EOFError, _lineno);
376  // log message
377  }
378  if (is.fail())
379  throw LSST_EXCEPT(ParserError, "read error", _lineno);
380  }
381 
382  if (value.size() > 0) {
383  if (regex_search(value,COMMENT_LINE)) {
384  value.erase();
385  break;
386  }
387  else if (regex_search(value, CLOSE_SRCH)) {
388  _pushBackLine(value);
389  return count;
390  }
391  }
392  else
393  break;
394  } while (value.size() > 0 &&
395  (value.at(0) == '\'' || value.at(0) == '"'));
396 
397  if (value.size() > 0) {
398  msg = "Expecting quoted string value, found: ";
399  msg.append(value);
400  if (_strict) throw LSST_EXCEPT(FormatSyntaxError, msg, _lineno);
401  // log message
402  }
403  }
404  else if (regex_search(value, matched, BARE_STRING)) {
405  string trimmed = matched.str(1);
406  string lowered(trimmed);
407  transform(lowered.begin(), lowered.end(), lowered.begin(), ::tolower);
408  int resume = matched.position(1) + matched.length(1);
409  if (regex_search(lowered, matched, URN_VALUE)) {
410  policy.add(propname,
411  Policy::FilePtr(new UrnPolicyFile(trimmed)));
412  }
413  else if (regex_search(trimmed, matched, FILE_VALUE)) {
414  policy.add(propname,
415  Policy::FilePtr(new PolicyFile(matched.suffix().str())));
416  }
417  else {
418  policy.add(propname, trimmed);
419  }
420  count++;
421  value = value.substr(resume);
422  if (regex_search(value, matched, CLOSE_SRCH)) {
423  _pushBackLine(value);
424  }
425  }
426 
427  return count;
428 }
429 
430 //@endcond
431 
432 }}}} // end lsst::pex::policy::paf
static const boost::regex SPACE_SRCH
Definition: PAFParser.h:99
an abstract class for parsing serialized Policy data and loading it into a Policy object...
Definition: PolicyParser.h:47
definition of the PolicyFile class
table::Key< std::string > name
Definition: ApCorrMap.cc:71
static const boost::regex QQSTRING_END
Definition: PAFParser.h:114
definition of the PAFParser class
static const boost::regex PARAM_SRCH
Definition: PAFParser.h:100
boost::shared_ptr< PolicyFile > FilePtr
Definition: Policy.h:176
static const boost::regex QSTRING_END
Definition: PAFParser.h:115
A Policy file in the installation directory of an LSST product, referred to using a URN...
Definition: UrnPolicyFile.h:68
static const boost::regex AFALSE_VALUE
Definition: PAFParser.h:107
a container for holding hierarchical configuration data in memory.
Definition: Policy.h:169
boost::shared_ptr< Policy > Ptr
Definition: Policy.h:172
static const boost::regex BARE_STRING
Definition: PAFParser.h:117
definition of Policy parsing exceptions
std::ios::iostate _nextLine(std::istream &is, std::string &line)
static const boost::regex EMPTY_LINE
Definition: PAFParser.h:98
int _addValue(const std::string &propname, std::string &value, Policy &policy, std::istream &is)
static const boost::regex OPEN_SRCH
Definition: PAFParser.h:102
static const boost::regex QQSTRING_EMPTYSTART
Definition: PAFParser.h:112
static const boost::regex BARE_STRING_LINE
Definition: PAFParser.h:116
static const boost::regex DOUBLE_VALUE
Definition: PAFParser.h:104
virtual int parse(std::istream &is)
void _pushBackLine(const std::string &line)
static const boost::regex QQSTRING_VALUE
Definition: PAFParser.h:108
static const boost::regex NAME_MTCH
Definition: PAFParser.h:101
static const boost::regex FILE_VALUE
Definition: PAFParser.h:119
static const boost::regex COMMENT_LINE
Definition: PAFParser.h:97
static const boost::regex ATRUE_VALUE
Definition: PAFParser.h:106
static const boost::regex CLOSE_SRCH
Definition: PAFParser.h:103
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
static const boost::regex QSTRING_START
Definition: PAFParser.h:111
int _parseIntoPolicy(std::istream &is, Policy &policy)
static const boost::regex URN_VALUE
Definition: PAFParser.h:118
static const boost::regex QSTRING_VALUE
Definition: PAFParser.h:109
static const boost::regex QQSTRING_START
Definition: PAFParser.h:110
static const boost::regex QSTRING_EMPTYSTART
Definition: PAFParser.h:113
a representation of a file containing Policy parameter data.
Definition: PolicyFile.h:58
static const boost::regex INT_VALUE
Definition: PAFParser.h:105
void add(const std::string &name, const Ptr &value)
Definition: Policy.h:1075
the definition of the UrnPolicyFile class