xref: /minix3/external/bsd/atf/dist/tools/parser.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc //
2*0a6a1f1dSLionel Sambuc // Automated Testing Framework (atf)
3*0a6a1f1dSLionel Sambuc //
4*0a6a1f1dSLionel Sambuc // Copyright (c) 2007 The NetBSD Foundation, Inc.
5*0a6a1f1dSLionel Sambuc // All rights reserved.
6*0a6a1f1dSLionel Sambuc //
7*0a6a1f1dSLionel Sambuc // Redistribution and use in source and binary forms, with or without
8*0a6a1f1dSLionel Sambuc // modification, are permitted provided that the following conditions
9*0a6a1f1dSLionel Sambuc // are met:
10*0a6a1f1dSLionel Sambuc // 1. Redistributions of source code must retain the above copyright
11*0a6a1f1dSLionel Sambuc //    notice, this list of conditions and the following disclaimer.
12*0a6a1f1dSLionel Sambuc // 2. Redistributions in binary form must reproduce the above copyright
13*0a6a1f1dSLionel Sambuc //    notice, this list of conditions and the following disclaimer in the
14*0a6a1f1dSLionel Sambuc //    documentation and/or other materials provided with the distribution.
15*0a6a1f1dSLionel Sambuc //
16*0a6a1f1dSLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17*0a6a1f1dSLionel Sambuc // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18*0a6a1f1dSLionel Sambuc // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19*0a6a1f1dSLionel Sambuc // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*0a6a1f1dSLionel Sambuc // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21*0a6a1f1dSLionel Sambuc // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*0a6a1f1dSLionel Sambuc // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23*0a6a1f1dSLionel Sambuc // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*0a6a1f1dSLionel Sambuc // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*0a6a1f1dSLionel Sambuc // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26*0a6a1f1dSLionel Sambuc // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27*0a6a1f1dSLionel Sambuc // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*0a6a1f1dSLionel Sambuc //
29*0a6a1f1dSLionel Sambuc 
30*0a6a1f1dSLionel Sambuc #include <cassert>
31*0a6a1f1dSLionel Sambuc #include <sstream>
32*0a6a1f1dSLionel Sambuc 
33*0a6a1f1dSLionel Sambuc #include "parser.hpp"
34*0a6a1f1dSLionel Sambuc #include "text.hpp"
35*0a6a1f1dSLionel Sambuc 
36*0a6a1f1dSLionel Sambuc namespace impl = tools::parser;
37*0a6a1f1dSLionel Sambuc #define IMPL_NAME "tools::parser"
38*0a6a1f1dSLionel Sambuc 
39*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
40*0a6a1f1dSLionel Sambuc // The "parse_error" class.
41*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
42*0a6a1f1dSLionel Sambuc 
parse_error(size_t line,std::string msg)43*0a6a1f1dSLionel Sambuc impl::parse_error::parse_error(size_t line, std::string msg) :
44*0a6a1f1dSLionel Sambuc     std::runtime_error(msg),
45*0a6a1f1dSLionel Sambuc     std::pair< size_t, std::string >(line, msg)
46*0a6a1f1dSLionel Sambuc {
47*0a6a1f1dSLionel Sambuc }
48*0a6a1f1dSLionel Sambuc 
~parse_error(void)49*0a6a1f1dSLionel Sambuc impl::parse_error::~parse_error(void)
50*0a6a1f1dSLionel Sambuc     throw()
51*0a6a1f1dSLionel Sambuc {
52*0a6a1f1dSLionel Sambuc }
53*0a6a1f1dSLionel Sambuc 
54*0a6a1f1dSLionel Sambuc const char*
what(void) const55*0a6a1f1dSLionel Sambuc impl::parse_error::what(void)
56*0a6a1f1dSLionel Sambuc     const throw()
57*0a6a1f1dSLionel Sambuc {
58*0a6a1f1dSLionel Sambuc     try {
59*0a6a1f1dSLionel Sambuc         std::ostringstream oss;
60*0a6a1f1dSLionel Sambuc         oss << "LONELY PARSE ERROR: " << first << ": " << second;
61*0a6a1f1dSLionel Sambuc         m_msg = oss.str();
62*0a6a1f1dSLionel Sambuc         return m_msg.c_str();
63*0a6a1f1dSLionel Sambuc     } catch (...) {
64*0a6a1f1dSLionel Sambuc         return "Could not format message for parsing error.";
65*0a6a1f1dSLionel Sambuc     }
66*0a6a1f1dSLionel Sambuc }
67*0a6a1f1dSLionel Sambuc 
operator std::string(void) const68*0a6a1f1dSLionel Sambuc impl::parse_error::operator std::string(void)
69*0a6a1f1dSLionel Sambuc     const
70*0a6a1f1dSLionel Sambuc {
71*0a6a1f1dSLionel Sambuc     return tools::text::to_string(first) + ": " + second;
72*0a6a1f1dSLionel Sambuc }
73*0a6a1f1dSLionel Sambuc 
74*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
75*0a6a1f1dSLionel Sambuc // The "parse_errors" class.
76*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
77*0a6a1f1dSLionel Sambuc 
parse_errors(void)78*0a6a1f1dSLionel Sambuc impl::parse_errors::parse_errors(void) :
79*0a6a1f1dSLionel Sambuc     std::runtime_error("No parsing errors yet")
80*0a6a1f1dSLionel Sambuc {
81*0a6a1f1dSLionel Sambuc     m_msg.clear();
82*0a6a1f1dSLionel Sambuc }
83*0a6a1f1dSLionel Sambuc 
~parse_errors(void)84*0a6a1f1dSLionel Sambuc impl::parse_errors::~parse_errors(void)
85*0a6a1f1dSLionel Sambuc     throw()
86*0a6a1f1dSLionel Sambuc {
87*0a6a1f1dSLionel Sambuc }
88*0a6a1f1dSLionel Sambuc 
89*0a6a1f1dSLionel Sambuc const char*
what(void) const90*0a6a1f1dSLionel Sambuc impl::parse_errors::what(void)
91*0a6a1f1dSLionel Sambuc     const throw()
92*0a6a1f1dSLionel Sambuc {
93*0a6a1f1dSLionel Sambuc     try {
94*0a6a1f1dSLionel Sambuc         m_msg = tools::text::join(*this, "\n");
95*0a6a1f1dSLionel Sambuc         return m_msg.c_str();
96*0a6a1f1dSLionel Sambuc     } catch (...) {
97*0a6a1f1dSLionel Sambuc         return "Could not format messages for parsing errors.";
98*0a6a1f1dSLionel Sambuc     }
99*0a6a1f1dSLionel Sambuc }
100*0a6a1f1dSLionel Sambuc 
101*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
102*0a6a1f1dSLionel Sambuc // The "format_error" class.
103*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
104*0a6a1f1dSLionel Sambuc 
format_error(const std::string & w)105*0a6a1f1dSLionel Sambuc impl::format_error::format_error(const std::string& w) :
106*0a6a1f1dSLionel Sambuc     std::runtime_error(w.c_str())
107*0a6a1f1dSLionel Sambuc {
108*0a6a1f1dSLionel Sambuc }
109*0a6a1f1dSLionel Sambuc 
110*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
111*0a6a1f1dSLionel Sambuc // The "token" class.
112*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
113*0a6a1f1dSLionel Sambuc 
token(void)114*0a6a1f1dSLionel Sambuc impl::token::token(void) :
115*0a6a1f1dSLionel Sambuc     m_inited(false)
116*0a6a1f1dSLionel Sambuc {
117*0a6a1f1dSLionel Sambuc }
118*0a6a1f1dSLionel Sambuc 
token(size_t p_line,const token_type & p_type,const std::string & p_text)119*0a6a1f1dSLionel Sambuc impl::token::token(size_t p_line,
120*0a6a1f1dSLionel Sambuc                    const token_type& p_type,
121*0a6a1f1dSLionel Sambuc                    const std::string& p_text) :
122*0a6a1f1dSLionel Sambuc     m_inited(true),
123*0a6a1f1dSLionel Sambuc     m_line(p_line),
124*0a6a1f1dSLionel Sambuc     m_type(p_type),
125*0a6a1f1dSLionel Sambuc     m_text(p_text)
126*0a6a1f1dSLionel Sambuc {
127*0a6a1f1dSLionel Sambuc }
128*0a6a1f1dSLionel Sambuc 
129*0a6a1f1dSLionel Sambuc size_t
lineno(void) const130*0a6a1f1dSLionel Sambuc impl::token::lineno(void)
131*0a6a1f1dSLionel Sambuc     const
132*0a6a1f1dSLionel Sambuc {
133*0a6a1f1dSLionel Sambuc     return m_line;
134*0a6a1f1dSLionel Sambuc }
135*0a6a1f1dSLionel Sambuc 
136*0a6a1f1dSLionel Sambuc const impl::token_type&
type(void) const137*0a6a1f1dSLionel Sambuc impl::token::type(void)
138*0a6a1f1dSLionel Sambuc     const
139*0a6a1f1dSLionel Sambuc {
140*0a6a1f1dSLionel Sambuc     return m_type;
141*0a6a1f1dSLionel Sambuc }
142*0a6a1f1dSLionel Sambuc 
143*0a6a1f1dSLionel Sambuc const std::string&
text(void) const144*0a6a1f1dSLionel Sambuc impl::token::text(void)
145*0a6a1f1dSLionel Sambuc     const
146*0a6a1f1dSLionel Sambuc {
147*0a6a1f1dSLionel Sambuc     return m_text;
148*0a6a1f1dSLionel Sambuc }
149*0a6a1f1dSLionel Sambuc 
operator bool(void) const150*0a6a1f1dSLionel Sambuc impl::token::operator bool(void)
151*0a6a1f1dSLionel Sambuc     const
152*0a6a1f1dSLionel Sambuc {
153*0a6a1f1dSLionel Sambuc     return m_inited;
154*0a6a1f1dSLionel Sambuc }
155*0a6a1f1dSLionel Sambuc 
156*0a6a1f1dSLionel Sambuc bool
operator !(void) const157*0a6a1f1dSLionel Sambuc impl::token::operator!(void)
158*0a6a1f1dSLionel Sambuc     const
159*0a6a1f1dSLionel Sambuc {
160*0a6a1f1dSLionel Sambuc     return !m_inited;
161*0a6a1f1dSLionel Sambuc }
162*0a6a1f1dSLionel Sambuc 
163*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
164*0a6a1f1dSLionel Sambuc // The "header_entry" class.
165*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
166*0a6a1f1dSLionel Sambuc 
header_entry(void)167*0a6a1f1dSLionel Sambuc impl::header_entry::header_entry(void)
168*0a6a1f1dSLionel Sambuc {
169*0a6a1f1dSLionel Sambuc }
170*0a6a1f1dSLionel Sambuc 
header_entry(const std::string & n,const std::string & v,attrs_map as)171*0a6a1f1dSLionel Sambuc impl::header_entry::header_entry(const std::string& n, const std::string& v,
172*0a6a1f1dSLionel Sambuc                                  attrs_map as) :
173*0a6a1f1dSLionel Sambuc     m_name(n),
174*0a6a1f1dSLionel Sambuc     m_value(v),
175*0a6a1f1dSLionel Sambuc     m_attrs(as)
176*0a6a1f1dSLionel Sambuc {
177*0a6a1f1dSLionel Sambuc }
178*0a6a1f1dSLionel Sambuc 
179*0a6a1f1dSLionel Sambuc const std::string&
name(void) const180*0a6a1f1dSLionel Sambuc impl::header_entry::name(void) const
181*0a6a1f1dSLionel Sambuc {
182*0a6a1f1dSLionel Sambuc     return m_name;
183*0a6a1f1dSLionel Sambuc }
184*0a6a1f1dSLionel Sambuc 
185*0a6a1f1dSLionel Sambuc const std::string&
value(void) const186*0a6a1f1dSLionel Sambuc impl::header_entry::value(void) const
187*0a6a1f1dSLionel Sambuc {
188*0a6a1f1dSLionel Sambuc     return m_value;
189*0a6a1f1dSLionel Sambuc }
190*0a6a1f1dSLionel Sambuc 
191*0a6a1f1dSLionel Sambuc const impl::attrs_map&
attrs(void) const192*0a6a1f1dSLionel Sambuc impl::header_entry::attrs(void) const
193*0a6a1f1dSLionel Sambuc {
194*0a6a1f1dSLionel Sambuc     return m_attrs;
195*0a6a1f1dSLionel Sambuc }
196*0a6a1f1dSLionel Sambuc 
197*0a6a1f1dSLionel Sambuc bool
has_attr(const std::string & n) const198*0a6a1f1dSLionel Sambuc impl::header_entry::has_attr(const std::string& n) const
199*0a6a1f1dSLionel Sambuc {
200*0a6a1f1dSLionel Sambuc     return m_attrs.find(n) != m_attrs.end();
201*0a6a1f1dSLionel Sambuc }
202*0a6a1f1dSLionel Sambuc 
203*0a6a1f1dSLionel Sambuc const std::string&
get_attr(const std::string & n) const204*0a6a1f1dSLionel Sambuc impl::header_entry::get_attr(const std::string& n) const
205*0a6a1f1dSLionel Sambuc {
206*0a6a1f1dSLionel Sambuc     attrs_map::const_iterator iter = m_attrs.find(n);
207*0a6a1f1dSLionel Sambuc     assert(iter != m_attrs.end());
208*0a6a1f1dSLionel Sambuc     return (*iter).second;
209*0a6a1f1dSLionel Sambuc }
210*0a6a1f1dSLionel Sambuc 
211*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
212*0a6a1f1dSLionel Sambuc // The header tokenizer.
213*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
214*0a6a1f1dSLionel Sambuc 
215*0a6a1f1dSLionel Sambuc namespace header {
216*0a6a1f1dSLionel Sambuc 
217*0a6a1f1dSLionel Sambuc static const impl::token_type eof_type = 0;
218*0a6a1f1dSLionel Sambuc static const impl::token_type nl_type = 1;
219*0a6a1f1dSLionel Sambuc static const impl::token_type text_type = 2;
220*0a6a1f1dSLionel Sambuc static const impl::token_type colon_type = 3;
221*0a6a1f1dSLionel Sambuc static const impl::token_type semicolon_type = 4;
222*0a6a1f1dSLionel Sambuc static const impl::token_type dblquote_type = 5;
223*0a6a1f1dSLionel Sambuc static const impl::token_type equal_type = 6;
224*0a6a1f1dSLionel Sambuc 
225*0a6a1f1dSLionel Sambuc class tokenizer : public impl::tokenizer< std::istream > {
226*0a6a1f1dSLionel Sambuc public:
tokenizer(std::istream & is,size_t curline)227*0a6a1f1dSLionel Sambuc     tokenizer(std::istream& is, size_t curline) :
228*0a6a1f1dSLionel Sambuc         impl::tokenizer< std::istream >
229*0a6a1f1dSLionel Sambuc             (is, true, eof_type, nl_type, text_type, curline)
230*0a6a1f1dSLionel Sambuc     {
231*0a6a1f1dSLionel Sambuc         add_delim(';', semicolon_type);
232*0a6a1f1dSLionel Sambuc         add_delim(':', colon_type);
233*0a6a1f1dSLionel Sambuc         add_delim('=', equal_type);
234*0a6a1f1dSLionel Sambuc         add_quote('"', dblquote_type);
235*0a6a1f1dSLionel Sambuc     }
236*0a6a1f1dSLionel Sambuc };
237*0a6a1f1dSLionel Sambuc 
238*0a6a1f1dSLionel Sambuc static
239*0a6a1f1dSLionel Sambuc impl::parser< header::tokenizer >&
read(impl::parser<header::tokenizer> & p,impl::header_entry & he)240*0a6a1f1dSLionel Sambuc read(impl::parser< header::tokenizer >& p, impl::header_entry& he)
241*0a6a1f1dSLionel Sambuc {
242*0a6a1f1dSLionel Sambuc     using namespace header;
243*0a6a1f1dSLionel Sambuc 
244*0a6a1f1dSLionel Sambuc     impl::token t = p.expect(text_type, nl_type, "a header name");
245*0a6a1f1dSLionel Sambuc     if (t.type() == nl_type) {
246*0a6a1f1dSLionel Sambuc         he = impl::header_entry();
247*0a6a1f1dSLionel Sambuc         return p;
248*0a6a1f1dSLionel Sambuc     }
249*0a6a1f1dSLionel Sambuc     std::string hdr_name = t.text();
250*0a6a1f1dSLionel Sambuc 
251*0a6a1f1dSLionel Sambuc     t = p.expect(colon_type, "`:'");
252*0a6a1f1dSLionel Sambuc 
253*0a6a1f1dSLionel Sambuc     t = p.expect(text_type, "a textual value");
254*0a6a1f1dSLionel Sambuc     std::string hdr_value = t.text();
255*0a6a1f1dSLionel Sambuc 
256*0a6a1f1dSLionel Sambuc     impl::attrs_map attrs;
257*0a6a1f1dSLionel Sambuc 
258*0a6a1f1dSLionel Sambuc     for (;;) {
259*0a6a1f1dSLionel Sambuc         t = p.expect(eof_type, semicolon_type, nl_type,
260*0a6a1f1dSLionel Sambuc                      "eof, `;' or new line");
261*0a6a1f1dSLionel Sambuc         if (t.type() == eof_type || t.type() == nl_type)
262*0a6a1f1dSLionel Sambuc             break;
263*0a6a1f1dSLionel Sambuc 
264*0a6a1f1dSLionel Sambuc         t = p.expect(text_type, "an attribute name");
265*0a6a1f1dSLionel Sambuc         std::string attr_name = t.text();
266*0a6a1f1dSLionel Sambuc 
267*0a6a1f1dSLionel Sambuc         t = p.expect(equal_type, "`='");
268*0a6a1f1dSLionel Sambuc 
269*0a6a1f1dSLionel Sambuc         t = p.expect(text_type, "word or quoted string");
270*0a6a1f1dSLionel Sambuc         std::string attr_value = t.text();
271*0a6a1f1dSLionel Sambuc         attrs[attr_name] = attr_value;
272*0a6a1f1dSLionel Sambuc     }
273*0a6a1f1dSLionel Sambuc 
274*0a6a1f1dSLionel Sambuc     he = impl::header_entry(hdr_name, hdr_value, attrs);
275*0a6a1f1dSLionel Sambuc 
276*0a6a1f1dSLionel Sambuc     return p;
277*0a6a1f1dSLionel Sambuc }
278*0a6a1f1dSLionel Sambuc 
279*0a6a1f1dSLionel Sambuc static
280*0a6a1f1dSLionel Sambuc std::ostream&
write(std::ostream & os,const impl::header_entry & he)281*0a6a1f1dSLionel Sambuc write(std::ostream& os, const impl::header_entry& he)
282*0a6a1f1dSLionel Sambuc {
283*0a6a1f1dSLionel Sambuc     std::string line = he.name() + ": " + he.value();
284*0a6a1f1dSLionel Sambuc     impl::attrs_map as = he.attrs();
285*0a6a1f1dSLionel Sambuc     for (impl::attrs_map::const_iterator iter = as.begin(); iter != as.end();
286*0a6a1f1dSLionel Sambuc          iter++) {
287*0a6a1f1dSLionel Sambuc         assert((*iter).second.find('\"') == std::string::npos);
288*0a6a1f1dSLionel Sambuc         line += "; " + (*iter).first + "=\"" + (*iter).second + "\"";
289*0a6a1f1dSLionel Sambuc     }
290*0a6a1f1dSLionel Sambuc 
291*0a6a1f1dSLionel Sambuc     os << line << "\n";
292*0a6a1f1dSLionel Sambuc 
293*0a6a1f1dSLionel Sambuc     return os;
294*0a6a1f1dSLionel Sambuc }
295*0a6a1f1dSLionel Sambuc 
296*0a6a1f1dSLionel Sambuc } // namespace header
297*0a6a1f1dSLionel Sambuc 
298*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
299*0a6a1f1dSLionel Sambuc // Free functions.
300*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
301*0a6a1f1dSLionel Sambuc 
302*0a6a1f1dSLionel Sambuc std::pair< size_t, impl::headers_map >
read_headers(std::istream & is,size_t curline)303*0a6a1f1dSLionel Sambuc impl::read_headers(std::istream& is, size_t curline)
304*0a6a1f1dSLionel Sambuc {
305*0a6a1f1dSLionel Sambuc     using impl::format_error;
306*0a6a1f1dSLionel Sambuc 
307*0a6a1f1dSLionel Sambuc     headers_map hm;
308*0a6a1f1dSLionel Sambuc 
309*0a6a1f1dSLionel Sambuc     //
310*0a6a1f1dSLionel Sambuc     // Grammar
311*0a6a1f1dSLionel Sambuc     //
312*0a6a1f1dSLionel Sambuc     // header = entry+ nl
313*0a6a1f1dSLionel Sambuc     // entry = line nl
314*0a6a1f1dSLionel Sambuc     // line = text colon text
315*0a6a1f1dSLionel Sambuc     //        (semicolon (text equal (text | dblquote string dblquote)))*
316*0a6a1f1dSLionel Sambuc     // string = quoted_string
317*0a6a1f1dSLionel Sambuc     //
318*0a6a1f1dSLionel Sambuc 
319*0a6a1f1dSLionel Sambuc     header::tokenizer tkz(is, curline);
320*0a6a1f1dSLionel Sambuc     impl::parser< header::tokenizer > p(tkz);
321*0a6a1f1dSLionel Sambuc 
322*0a6a1f1dSLionel Sambuc     bool first = true;
323*0a6a1f1dSLionel Sambuc     for (;;) {
324*0a6a1f1dSLionel Sambuc         try {
325*0a6a1f1dSLionel Sambuc             header_entry he;
326*0a6a1f1dSLionel Sambuc             if (!header::read(p, he).good() || he.name().empty())
327*0a6a1f1dSLionel Sambuc                 break;
328*0a6a1f1dSLionel Sambuc 
329*0a6a1f1dSLionel Sambuc             if (first && he.name() != "Content-Type")
330*0a6a1f1dSLionel Sambuc                 throw format_error("Could not determine content type");
331*0a6a1f1dSLionel Sambuc             else
332*0a6a1f1dSLionel Sambuc                 first = false;
333*0a6a1f1dSLionel Sambuc 
334*0a6a1f1dSLionel Sambuc             hm[he.name()] = he;
335*0a6a1f1dSLionel Sambuc         } catch (const impl::parse_error& pe) {
336*0a6a1f1dSLionel Sambuc             p.add_error(pe);
337*0a6a1f1dSLionel Sambuc             p.reset(header::nl_type);
338*0a6a1f1dSLionel Sambuc         }
339*0a6a1f1dSLionel Sambuc     }
340*0a6a1f1dSLionel Sambuc 
341*0a6a1f1dSLionel Sambuc     if (!is.good())
342*0a6a1f1dSLionel Sambuc         throw format_error("Unexpected end of stream");
343*0a6a1f1dSLionel Sambuc 
344*0a6a1f1dSLionel Sambuc     return std::pair< size_t, headers_map >(tkz.lineno(), hm);
345*0a6a1f1dSLionel Sambuc }
346*0a6a1f1dSLionel Sambuc 
347*0a6a1f1dSLionel Sambuc void
write_headers(const impl::headers_map & hm,std::ostream & os)348*0a6a1f1dSLionel Sambuc impl::write_headers(const impl::headers_map& hm, std::ostream& os)
349*0a6a1f1dSLionel Sambuc {
350*0a6a1f1dSLionel Sambuc     assert(!hm.empty());
351*0a6a1f1dSLionel Sambuc     headers_map::const_iterator ct = hm.find("Content-Type");
352*0a6a1f1dSLionel Sambuc     assert(ct != hm.end());
353*0a6a1f1dSLionel Sambuc     header::write(os, (*ct).second);
354*0a6a1f1dSLionel Sambuc     for (headers_map::const_iterator iter = hm.begin(); iter != hm.end();
355*0a6a1f1dSLionel Sambuc          iter++) {
356*0a6a1f1dSLionel Sambuc         if ((*iter).first != "Content-Type")
357*0a6a1f1dSLionel Sambuc             header::write(os, (*iter).second);
358*0a6a1f1dSLionel Sambuc     }
359*0a6a1f1dSLionel Sambuc     os << "\n";
360*0a6a1f1dSLionel Sambuc }
361*0a6a1f1dSLionel Sambuc 
362*0a6a1f1dSLionel Sambuc void
validate_content_type(const impl::headers_map & hm,const std::string & fmt,int version)363*0a6a1f1dSLionel Sambuc impl::validate_content_type(const impl::headers_map& hm, const std::string& fmt,
364*0a6a1f1dSLionel Sambuc                             int version)
365*0a6a1f1dSLionel Sambuc {
366*0a6a1f1dSLionel Sambuc     using impl::format_error;
367*0a6a1f1dSLionel Sambuc 
368*0a6a1f1dSLionel Sambuc     headers_map::const_iterator iter = hm.find("Content-Type");
369*0a6a1f1dSLionel Sambuc     if (iter == hm.end())
370*0a6a1f1dSLionel Sambuc         throw format_error("Could not determine content type");
371*0a6a1f1dSLionel Sambuc 
372*0a6a1f1dSLionel Sambuc     const header_entry& he = (*iter).second;
373*0a6a1f1dSLionel Sambuc     if (he.value() != fmt)
374*0a6a1f1dSLionel Sambuc         throw format_error("Mismatched content type: expected `" + fmt +
375*0a6a1f1dSLionel Sambuc                            "' but got `" + he.value() + "'");
376*0a6a1f1dSLionel Sambuc 
377*0a6a1f1dSLionel Sambuc     if (!he.has_attr("version"))
378*0a6a1f1dSLionel Sambuc         throw format_error("Could not determine version");
379*0a6a1f1dSLionel Sambuc     const std::string& vstr = tools::text::to_string(version);
380*0a6a1f1dSLionel Sambuc     if (he.get_attr("version") != vstr)
381*0a6a1f1dSLionel Sambuc         throw format_error("Mismatched version: expected `" +
382*0a6a1f1dSLionel Sambuc                            vstr + "' but got `" +
383*0a6a1f1dSLionel Sambuc                            he.get_attr("version") + "'");
384*0a6a1f1dSLionel Sambuc }
385