LSSTApplications  19.0.0-14-gb0260a2+d60062ef16,20.0.0+1540ce6389,20.0.0+7c6b12c2f9,20.0.0+ae956f52c5,20.0.0+be870186d9,20.0.0+e2e26847c2,20.0.0-1-g10df615+7683e4f082,20.0.0-1-g253301a+7c6b12c2f9,20.0.0-1-g2b7511a+46a6078777,20.0.0-1-g3dda6ea+606b36f8c0,20.0.0-1-g4d801e7+901ee84527,20.0.0-1-g5b95a8c+a5fa15ec54,20.0.0-1-gb058bd0+46a6078777,20.0.0-1-gb88604f+acecce4127,20.0.0-1-gc96f8cb+61a4a056b1,20.0.0-1-gedffbd8+4f0e391d5e,20.0.0-10-g0891cd99+aadc987f3e,20.0.0-10-g9a20bd332+576ca7b471,20.0.0-17-gcdbda88+ed0d4927ab,20.0.0-2-g4dae9ad+61a4a056b1,20.0.0-2-g61b8584+85c46248f3,20.0.0-2-gb780d76+f45b7d88f4,20.0.0-2-gf072044+7c6b12c2f9,20.0.0-21-g9bbb7f7+61a4a056b1,20.0.0-22-gc512666+9eba1c4719,20.0.0-23-g8900aa8+68630f7098,20.0.0-3-g1653f94+85c46248f3,20.0.0-3-g4cc78c6+63636aeed8,20.0.0-3-g750bffe+e05f822de9,20.0.0-3-gbd60e8c+ff10c6d78d,20.0.0-32-g15a0e07c+ff1c9f120b,20.0.0-4-g97dc21a+68630f7098,20.0.0-4-gfea843c+f45b7d88f4,20.0.0-5-g357b56b+f45b7d88f4,20.0.0-6-g9a5b7a1+2c4171520d,20.0.0-61-g4de25fb+e4dd172200,20.0.0-7-gcda7bf1+85e953d7e4,w.2020.43
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  */
80 PAFParser::PAFParser(Policy& policy)
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
std::strtol
T strtol(T... args)
lsst.pex::policy::PolicyParser
an abstract class for parsing serialized Policy data and loading it into a Policy object.
Definition: PolicyParser.h:46
std::smatch::suffix
T suffix(T... args)
std::list::push_front
T push_front(T... args)
std::list::pop_front
T pop_front(T... args)
lsst.pex::policy::paf::PAFParser::parse
virtual int parse(std::istream &is)
parse the data found on the given stream
std::list::size
T size(T... args)
std::istream::rdstate
T rdstate(T... args)
std::regex_match
T regex_match(T... args)
lsst.pex::policy::Policy
a container for holding hierarchical configuration data in memory.
Definition: Policy.h:167
lsst::afw::geom.transform.transformContinued.name
string name
Definition: transformContinued.py:32
lsst.pex::policy::PolicyParser::_strict
bool _strict
Definition: PolicyParser.h:96
std::list::front
T front(T... args)
parserexceptions.h
definition of Policy parsing exceptions
UrnPolicyFile.h
the definition of the UrnPolicyFile class
std::string::at
T at(T... args)
std::string::erase
T erase(T... args)
lsst::afw.display.ds9.line
def line(points, frame=None, origin=afwImage.PARENT, symbs=False, ctype=None, size=0.5)
Definition: ds9.py:105
std::regex
PolicyFile.h
definition of the PolicyFile class
std::string::append
T append(T... args)
lsst
A base class for image defects.
Definition: imageAlgorithm.dox:1
std::regex_search
T regex_search(T... args)
LSST_EXCEPT
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
lsst.pex::policy::PolicyParser::_pol
Policy & _pol
Definition: PolicyParser.h:95
std::string::substr
T substr(T... args)
lsst.pex::policy::Policy::Ptr
std::shared_ptr< Policy > Ptr
Definition: Policy.h:169
std::istream::fail
T fail(T... args)
std::getline
T getline(T... args)
std
STL namespace.
lsst.pex::policy::Policy::FilePtr
std::shared_ptr< PolicyFile > FilePtr
Definition: Policy.h:173
std::smatch::length
T length(T... args)
std::strtod
T strtod(T... args)
std::count
T count(T... args)
transform
table::Key< int > transform
Definition: TransformMap.cc:299
std::smatch::str
T str(T... args)
PAFParser.h
definition of the PAFParser class
std::smatch
element
double element[2]
Definition: BaseTable.cc:91
std::istream
STL class.
std::smatch::position
T position(T... args)
std::istream::eof
T eof(T... args)
lsst.pex::policy::paf::PAFParser::~PAFParser
virtual ~PAFParser()
delete this parser
lsst.pex::policy::paf::PAFParser::PAFParser
PAFParser(Policy &policy)
create a parser to load a Policy