2 // Automated Testing Framework (atf)
4 // Copyright (c) 2007 The NetBSD Foundation, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
10 // 1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // 2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 namespace impl
= tools::parser
;
37 #define IMPL_NAME "tools::parser"
39 // ------------------------------------------------------------------------
40 // The "parse_error" class.
41 // ------------------------------------------------------------------------
43 impl::parse_error::parse_error(size_t line
, std::string msg
) :
44 std::runtime_error(msg
),
45 std::pair
< size_t, std::string
>(line
, msg
)
49 impl::parse_error::~parse_error(void)
55 impl::parse_error::what(void)
59 std::ostringstream oss
;
60 oss
<< "LONELY PARSE ERROR: " << first
<< ": " << second
;
64 return "Could not format message for parsing error.";
68 impl::parse_error::operator std::string(void)
71 return tools::text::to_string(first
) + ": " + second
;
74 // ------------------------------------------------------------------------
75 // The "parse_errors" class.
76 // ------------------------------------------------------------------------
78 impl::parse_errors::parse_errors(void) :
79 std::runtime_error("No parsing errors yet")
84 impl::parse_errors::~parse_errors(void)
90 impl::parse_errors::what(void)
94 m_msg
= tools::text::join(*this, "\n");
97 return "Could not format messages for parsing errors.";
101 // ------------------------------------------------------------------------
102 // The "format_error" class.
103 // ------------------------------------------------------------------------
105 impl::format_error::format_error(const std::string
& w
) :
106 std::runtime_error(w
.c_str())
110 // ------------------------------------------------------------------------
111 // The "token" class.
112 // ------------------------------------------------------------------------
114 impl::token::token(void) :
119 impl::token::token(size_t p_line
,
120 const token_type
& p_type
,
121 const std::string
& p_text
) :
130 impl::token::lineno(void)
136 const impl::token_type
&
137 impl::token::type(void)
144 impl::token::text(void)
150 impl::token::operator bool(void)
157 impl::token::operator!(void)
163 // ------------------------------------------------------------------------
164 // The "header_entry" class.
165 // ------------------------------------------------------------------------
167 impl::header_entry::header_entry(void)
171 impl::header_entry::header_entry(const std::string
& n
, const std::string
& v
,
180 impl::header_entry::name(void) const
186 impl::header_entry::value(void) const
191 const impl::attrs_map
&
192 impl::header_entry::attrs(void) const
198 impl::header_entry::has_attr(const std::string
& n
) const
200 return m_attrs
.find(n
) != m_attrs
.end();
204 impl::header_entry::get_attr(const std::string
& n
) const
206 attrs_map::const_iterator iter
= m_attrs
.find(n
);
207 assert(iter
!= m_attrs
.end());
208 return (*iter
).second
;
211 // ------------------------------------------------------------------------
212 // The header tokenizer.
213 // ------------------------------------------------------------------------
217 static const impl::token_type eof_type
= 0;
218 static const impl::token_type nl_type
= 1;
219 static const impl::token_type text_type
= 2;
220 static const impl::token_type colon_type
= 3;
221 static const impl::token_type semicolon_type
= 4;
222 static const impl::token_type dblquote_type
= 5;
223 static const impl::token_type equal_type
= 6;
225 class tokenizer
: public impl::tokenizer
< std::istream
> {
227 tokenizer(std::istream
& is
, size_t curline
) :
228 impl::tokenizer
< std::istream
>
229 (is
, true, eof_type
, nl_type
, text_type
, curline
)
231 add_delim(';', semicolon_type
);
232 add_delim(':', colon_type
);
233 add_delim('=', equal_type
);
234 add_quote('"', dblquote_type
);
239 impl::parser
< header::tokenizer
>&
240 read(impl::parser
< header::tokenizer
>& p
, impl::header_entry
& he
)
242 using namespace header
;
244 impl::token t
= p
.expect(text_type
, nl_type
, "a header name");
245 if (t
.type() == nl_type
) {
246 he
= impl::header_entry();
249 std::string hdr_name
= t
.text();
251 t
= p
.expect(colon_type
, "`:'");
253 t
= p
.expect(text_type
, "a textual value");
254 std::string hdr_value
= t
.text();
256 impl::attrs_map attrs
;
259 t
= p
.expect(eof_type
, semicolon_type
, nl_type
,
260 "eof, `;' or new line");
261 if (t
.type() == eof_type
|| t
.type() == nl_type
)
264 t
= p
.expect(text_type
, "an attribute name");
265 std::string attr_name
= t
.text();
267 t
= p
.expect(equal_type
, "`='");
269 t
= p
.expect(text_type
, "word or quoted string");
270 std::string attr_value
= t
.text();
271 attrs
[attr_name
] = attr_value
;
274 he
= impl::header_entry(hdr_name
, hdr_value
, attrs
);
281 write(std::ostream
& os
, const impl::header_entry
& he
)
283 std::string line
= he
.name() + ": " + he
.value();
284 impl::attrs_map as
= he
.attrs();
285 for (impl::attrs_map::const_iterator iter
= as
.begin(); iter
!= as
.end();
287 assert((*iter
).second
.find('\"') == std::string::npos
);
288 line
+= "; " + (*iter
).first
+ "=\"" + (*iter
).second
+ "\"";
296 } // namespace header
298 // ------------------------------------------------------------------------
300 // ------------------------------------------------------------------------
302 std::pair
< size_t, impl::headers_map
>
303 impl::read_headers(std::istream
& is
, size_t curline
)
305 using impl::format_error
;
312 // header = entry+ nl
314 // line = text colon text
315 // (semicolon (text equal (text | dblquote string dblquote)))*
316 // string = quoted_string
319 header::tokenizer
tkz(is
, curline
);
320 impl::parser
< header::tokenizer
> p(tkz
);
326 if (!header::read(p
, he
).good() || he
.name().empty())
329 if (first
&& he
.name() != "Content-Type")
330 throw format_error("Could not determine content type");
335 } catch (const impl::parse_error
& pe
) {
337 p
.reset(header::nl_type
);
342 throw format_error("Unexpected end of stream");
344 return std::pair
< size_t, headers_map
>(tkz
.lineno(), hm
);
348 impl::write_headers(const impl::headers_map
& hm
, std::ostream
& os
)
351 headers_map::const_iterator ct
= hm
.find("Content-Type");
352 assert(ct
!= hm
.end());
353 header::write(os
, (*ct
).second
);
354 for (headers_map::const_iterator iter
= hm
.begin(); iter
!= hm
.end();
356 if ((*iter
).first
!= "Content-Type")
357 header::write(os
, (*iter
).second
);
363 impl::validate_content_type(const impl::headers_map
& hm
, const std::string
& fmt
,
366 using impl::format_error
;
368 headers_map::const_iterator iter
= hm
.find("Content-Type");
369 if (iter
== hm
.end())
370 throw format_error("Could not determine content type");
372 const header_entry
& he
= (*iter
).second
;
373 if (he
.value() != fmt
)
374 throw format_error("Mismatched content type: expected `" + fmt
+
375 "' but got `" + he
.value() + "'");
377 if (!he
.has_attr("version"))
378 throw format_error("Could not determine version");
379 const std::string
& vstr
= tools::text::to_string(version
);
380 if (he
.get_attr("version") != vstr
)
381 throw format_error("Mismatched version: expected `" +
382 vstr
+ "' but got `" +
383 he
.get_attr("version") + "'");