From ea648e70a989cca190cd7403fe892fd2dcc290b4 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 5 May 2024 20:37:14 +0200 Subject: Adding upstream version 1:9.11.5.P4+dfsg. Signed-off-by: Daniel Baumann --- unit/atf-src/tools/parser.hpp | 607 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 607 insertions(+) create mode 100644 unit/atf-src/tools/parser.hpp (limited to 'unit/atf-src/tools/parser.hpp') diff --git a/unit/atf-src/tools/parser.hpp b/unit/atf-src/tools/parser.hpp new file mode 100644 index 0000000..eb00cb4 --- /dev/null +++ b/unit/atf-src/tools/parser.hpp @@ -0,0 +1,607 @@ +// +// Automated Testing Framework (atf) +// +// Copyright (c) 2007 The NetBSD Foundation, Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND +// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#if !defined(TOOLS_PARSER_HPP) +#define TOOLS_PARSER_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace tools { +namespace parser { + +// ------------------------------------------------------------------------ +// The "parse_error" class. +// ------------------------------------------------------------------------ + +class parse_error : public std::runtime_error, + public std::pair< size_t, std::string > { + mutable std::string m_msg; + +public: + parse_error(size_t, std::string); + ~parse_error(void) throw(); + + const char* what(void) const throw(); + + operator std::string(void) const; +}; + +// ------------------------------------------------------------------------ +// The "parse_errors" class. +// ------------------------------------------------------------------------ + +class parse_errors : public std::runtime_error, + public std::vector< parse_error > { + std::vector< parse_error > m_errors; + mutable std::string m_msg; + +public: + parse_errors(void); + ~parse_errors(void) throw(); + + const char* what(void) const throw(); +}; + +// ------------------------------------------------------------------------ +// The "format_error" class. +// ------------------------------------------------------------------------ + +class format_error : public std::runtime_error { +public: + format_error(const std::string&); +}; + +// ------------------------------------------------------------------------ +// The "token" class. +// ------------------------------------------------------------------------ + +typedef int token_type; + +//! +//! \brief Representation of a read token. +//! +//! A pair that contains the information of a token read from a stream. +//! It contains the token's type and its associated data, if any. +//! +struct token { + bool m_inited; + size_t m_line; + token_type m_type; + std::string m_text; + +public: + token(void); + token(size_t, const token_type&, const std::string& = ""); + + size_t lineno(void) const; + const token_type& type(void) const; + const std::string& text(void) const; + + operator bool(void) const; + bool operator!(void) const; +}; + +// ------------------------------------------------------------------------ +// The "tokenizer" class. +// ------------------------------------------------------------------------ + +//! +//! \brief A stream tokenizer. +//! +//! This template implements an extremely simple, line-oriented stream +//! tokenizer. It is only able to recognize one character-long delimiters, +//! random-length keywords, skip whitespace and, anything that does not +//! match these rules is supposed to be a word. +//! +//! Parameter IS: The input stream's type. +//! +template< class IS > +class tokenizer { + IS& m_is; + size_t m_lineno; + token m_la; + + bool m_skipws; + token_type m_eof_type, m_nl_type, m_text_type; + + std::map< char, token_type > m_delims_map; + std::string m_delims_str; + + char m_quotech; + token_type m_quotetype; + + std::map< std::string, token_type > m_keywords_map; + + token_type alloc_type(void); + + template< class TKZ > + friend + class parser; + +public: + tokenizer(IS&, bool, const token_type&, const token_type&, + const token_type&, size_t = 1); + + size_t lineno(void) const; + + void add_delim(char, const token_type&); + void add_keyword(const std::string&, const token_type&); + void add_quote(char, const token_type&); + + token next(void); + std::string rest_of_line(void); +}; + +template< class IS > +tokenizer< IS >::tokenizer(IS& p_is, + bool p_skipws, + const token_type& p_eof_type, + const token_type& p_nl_type, + const token_type& p_text_type, + size_t p_lineno) : + m_is(p_is), + m_lineno(p_lineno), + m_skipws(p_skipws), + m_eof_type(p_eof_type), + m_nl_type(p_nl_type), + m_text_type(p_text_type), + m_quotech(-1) +{ +} + +template< class IS > +size_t +tokenizer< IS >::lineno(void) + const +{ + return m_lineno; +} + +template< class IS > +void +tokenizer< IS >::add_delim(char delim, const token_type& type) +{ + m_delims_map[delim] = type; + m_delims_str += delim; +} + +template< class IS > +void +tokenizer< IS >::add_keyword(const std::string& keyword, + const token_type& type) +{ + m_keywords_map[keyword] = type; +} + +template< class IS > +void +tokenizer< IS >::add_quote(char ch, const token_type& type) +{ + m_quotech = ch; + m_quotetype = type; +} + +template< class IS > +token +tokenizer< IS >::next(void) +{ + if (m_la) { + token t = m_la; + m_la = token(); + if (t.type() == m_nl_type) + m_lineno++; + return t; + } + + char ch; + std::string text; + + bool done = false, quoted = false; + token t(m_lineno, m_eof_type, "<>"); + while (!done && m_is.get(ch).good()) { + if (ch == m_quotech) { + if (text.empty()) { + bool escaped = false; + while (!done && m_is.get(ch).good()) { + if (!escaped) { + if (ch == '\\') + escaped = true; + else if (ch == '\n') { + m_la = token(m_lineno, m_nl_type, "<>"); + throw parse_error(t.lineno(), + "Missing double quotes before " + "end of line"); + } else if (ch == m_quotech) + done = true; + else + text += ch; + } else { + text += ch; + escaped = false; + } + } + if (!m_is.good()) + throw parse_error(t.lineno(), + "Missing double quotes before " + "end of file"); + t = token(m_lineno, m_text_type, text); + quoted = true; + } else { + m_is.putback(ch); + done = true; + } + } else { + typename std::map< char, token_type >::const_iterator idelim; + idelim = m_delims_map.find(ch); + if (idelim != m_delims_map.end()) { + done = true; + if (text.empty()) + t = token(m_lineno, (*idelim).second, + std::string("") + ch); + else + m_is.putback(ch); + } else if (ch == '\n') { + done = true; + if (text.empty()) + t = token(m_lineno, m_nl_type, "<>"); + else + m_is.putback(ch); + } else if (m_skipws && (ch == ' ' || ch == '\t')) { + if (!text.empty()) + done = true; + } else + text += ch; + } + } + + if (!quoted && !text.empty()) { + typename std::map< std::string, token_type >::const_iterator ikw; + ikw = m_keywords_map.find(text); + if (ikw != m_keywords_map.end()) + t = token(m_lineno, (*ikw).second, text); + else + t = token(m_lineno, m_text_type, text); + } + + if (t.type() == m_nl_type) + m_lineno++; + + return t; +} + +template< class IS > +std::string +tokenizer< IS >::rest_of_line(void) +{ + std::string str; + while (m_is.good() && m_is.peek() != '\n') + str += m_is.get(); + return str; +} + +// ------------------------------------------------------------------------ +// The "parser" class. +// ------------------------------------------------------------------------ + +template< class TKZ > +class parser { + TKZ& m_tkz; + token m_last; + parse_errors m_errors; + bool m_thrown; + +public: + parser(TKZ& tkz); + ~parser(void); + + bool good(void) const; + void add_error(const parse_error&); + bool has_errors(void) const; + + token next(void); + std::string rest_of_line(void); + token reset(const token_type&); + + token + expect(const token_type&, + const std::string&); + + token + expect(const token_type&, + const token_type&, + const std::string&); + + token + expect(const token_type&, + const token_type&, + const token_type&, + const std::string&); + + token + expect(const token_type&, + const token_type&, + const token_type&, + const token_type&, + const std::string&); + + token + expect(const token_type&, + const token_type&, + const token_type&, + const token_type&, + const token_type&, + const token_type&, + const token_type&, + const std::string&); + + token + expect(const token_type&, + const token_type&, + const token_type&, + const token_type&, + const token_type&, + const token_type&, + const token_type&, + const token_type&, + const std::string&); +}; + +template< class TKZ > +parser< TKZ >::parser(TKZ& tkz) : + m_tkz(tkz), + m_thrown(false) +{ +} + +template< class TKZ > +parser< TKZ >::~parser(void) +{ + if (!m_errors.empty() && !m_thrown) + throw m_errors; +} + +template< class TKZ > +bool +parser< TKZ >::good(void) + const +{ + return m_tkz.m_is.good(); +} + +template< class TKZ > +void +parser< TKZ >::add_error(const parse_error& pe) +{ + m_errors.push_back(pe); +} + +template< class TKZ > +bool +parser< TKZ >::has_errors(void) + const +{ + return !m_errors.empty(); +} + +template< class TKZ > +token +parser< TKZ >::next(void) +{ + token t = m_tkz.next(); + + m_last = t; + + if (t.type() == m_tkz.m_eof_type) { + if (!m_errors.empty()) { + m_thrown = true; + throw m_errors; + } + } + + return t; +} + +template< class TKZ > +std::string +parser< TKZ >::rest_of_line(void) +{ + return m_tkz.rest_of_line(); +} + +template< class TKZ > +token +parser< TKZ >::reset(const token_type& stop) +{ + token t = m_last; + + while (t.type() != m_tkz.m_eof_type && t.type() != stop) + t = next(); + + return t; +} + +template< class TKZ > +token +parser< TKZ >::expect(const token_type& t1, + const std::string& textual) +{ + token t = next(); + + if (t.type() != t1) + throw parse_error(t.lineno(), + "Unexpected token `" + t.text() + + "'; expected " + textual); + + return t; +} + +template< class TKZ > +token +parser< TKZ >::expect(const token_type& t1, + const token_type& t2, + const std::string& textual) +{ + token t = next(); + + if (t.type() != t1 && t.type() != t2) + throw parse_error(t.lineno(), + "Unexpected token `" + t.text() + + "'; expected " + textual); + + return t; +} + +template< class TKZ > +token +parser< TKZ >::expect(const token_type& t1, + const token_type& t2, + const token_type& t3, + const std::string& textual) +{ + token t = next(); + + if (t.type() != t1 && t.type() != t2 && t.type() != t3) + throw parse_error(t.lineno(), + "Unexpected token `" + t.text() + + "'; expected " + textual); + + return t; +} + +template< class TKZ > +token +parser< TKZ >::expect(const token_type& t1, + const token_type& t2, + const token_type& t3, + const token_type& t4, + const std::string& textual) +{ + token t = next(); + + if (t.type() != t1 && t.type() != t2 && t.type() != t3 && + t.type() != t4) + throw parse_error(t.lineno(), + "Unexpected token `" + t.text() + + "'; expected " + textual); + + return t; +} + +template< class TKZ > +token +parser< TKZ >::expect(const token_type& t1, + const token_type& t2, + const token_type& t3, + const token_type& t4, + const token_type& t5, + const token_type& t6, + const token_type& t7, + const std::string& textual) +{ + token t = next(); + + if (t.type() != t1 && t.type() != t2 && t.type() != t3 && + t.type() != t4 && t.type() != t5 && t.type() != t6 && + t.type() != t7) + throw parse_error(t.lineno(), + "Unexpected token `" + t.text() + + "'; expected " + textual); + + return t; +} + +template< class TKZ > +token +parser< TKZ >::expect(const token_type& t1, + const token_type& t2, + const token_type& t3, + const token_type& t4, + const token_type& t5, + const token_type& t6, + const token_type& t7, + const token_type& t8, + const std::string& textual) +{ + token t = next(); + + if (t.type() != t1 && t.type() != t2 && t.type() != t3 && + t.type() != t4 && t.type() != t5 && t.type() != t6 && + t.type() != t7 && t.type() != t8) + throw parse_error(t.lineno(), + "Unexpected token `" + t.text() + + "'; expected " + textual); + + return t; +} + +#define ATF_PARSER_CALLBACK(parser, func) \ + do { \ + if (!(parser).has_errors()) \ + func; \ + } while (false) + +// ------------------------------------------------------------------------ +// Header parsing. +// ------------------------------------------------------------------------ + +typedef std::map< std::string, std::string > attrs_map; + +class header_entry { + std::string m_name; + std::string m_value; + attrs_map m_attrs; + +public: + header_entry(void); + header_entry(const std::string&, const std::string&, + attrs_map = attrs_map()); + + const std::string& name(void) const; + const std::string& value(void) const; + const attrs_map& attrs(void) const; + bool has_attr(const std::string&) const; + const std::string& get_attr(const std::string&) const; +}; + +typedef std::map< std::string, header_entry > headers_map; + +std::pair< size_t, headers_map > read_headers(std::istream&, size_t); +void write_headers(const headers_map&, std::ostream&); +void validate_content_type(const headers_map&, const std::string&, int); + +} // namespace parser +} // namespace tools + +#endif // !defined(TOOLS_PARSER_HPP) -- cgit v1.2.3