Created
July 7, 2012 20:34
-
-
Save vasi/3068010 to your computer and use it in GitHub Desktop.
lvmtext parsing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/spirit/include/qi.hpp> | |
#include <boost/spirit/include/phoenix_object.hpp> | |
#include <boost/spirit/include/phoenix_operator.hpp> | |
#include <boost/fusion/include/adapt_struct.hpp> | |
#include <boost/fusion/adapted/std_pair.hpp> | |
#include <boost/variant.hpp> | |
#include <iostream> | |
#include <sstream> | |
#include <fstream> | |
#include <vector> | |
#include <map> | |
namespace lvmfuse { | |
std::string slurp(char *file) { | |
std::ifstream input(file); | |
std::stringstream ss; | |
ss << input.rdbuf(); | |
return ss.str(); | |
} | |
typedef std::string lvmtext_string; | |
typedef unsigned long long lvmtext_int; | |
struct lvmtext_array; | |
struct lvmtext_section; | |
typedef boost::variant< | |
lvmtext_int, | |
lvmtext_string, | |
boost::recursive_wrapper<lvmtext_array>, | |
boost::recursive_wrapper<lvmtext_section> | |
> lvmtext_t; | |
struct lvmtext_array { | |
std::vector<lvmtext_t> items; | |
}; | |
struct lvmtext_section { | |
typedef std::map<lvmtext_string,lvmtext_t> items_type; | |
items_type items; | |
}; | |
typedef std::pair<lvmtext_string,lvmtext_t> lvmtext_keyval; | |
} // namespace | |
BOOST_FUSION_ADAPT_STRUCT( | |
lvmfuse::lvmtext_array, | |
(std::vector<lvmfuse::lvmtext_t>, items) | |
) | |
BOOST_FUSION_ADAPT_STRUCT( | |
lvmfuse::lvmtext_section, | |
(lvmfuse::lvmtext_section::items_type, items) | |
) | |
namespace lvmfuse { | |
namespace qi = boost::spirit::qi; | |
namespace phoenix = boost::phoenix; | |
template <typename Iter> | |
struct lvmtext_skipper : qi::grammar<Iter> { | |
lvmtext_skipper() : lvmtext_skipper::base_type(skip, "space") { | |
using qi::lit; | |
using qi::char_; | |
using qi::space; | |
using qi::eol; | |
comment = lit('#') > *(char_ - eol) > eol; | |
skip = space | comment; | |
} | |
qi::rule<Iter> comment; | |
qi::rule<Iter> skip; | |
}; | |
typedef lvmtext_section lvmtext_out; | |
template <typename Iter> | |
struct lvmtext_parser : qi::grammar<Iter, lvmtext_out(), | |
lvmtext_skipper<Iter> > { | |
lvmtext_parser() : lvmtext_parser::base_type(section, "lvm2 text") { | |
using qi::hold; | |
using qi::lexeme; | |
using qi::eps; | |
using qi::alnum; | |
using qi::lit; | |
using qi::space; | |
using qi::char_; | |
using namespace qi::labels; | |
using phoenix::val; | |
using phoenix::construct; | |
identifier %= lexeme[+(alnum | char_("-_.+"))]; | |
integer_r %= qi::ulong_long; | |
escape_seq %= lit('\\') > (char_('\\') | char_('"')); | |
string = lexeme[*(escape_seq | (char_ - '"'))]; | |
quoted_string %= lit('"') > string > lit('"'); | |
array %= lit('[') > -(expr % ',') > lit(']'); | |
keyval %= identifier >> lit('=') >> expr; | |
named_section %= identifier >> lit('{') > section > lit('}'); | |
section %= eps >> *(hold[keyval] | named_section); | |
expr %= integer_r | quoted_string | array; | |
identifier.name("identifier"); | |
integer_r.name("integer"); | |
escape_seq.name("escape sequence"); | |
quoted_string.name("quoted string"); | |
array.name("array"); | |
keyval.name("key-value pair"); | |
named_section.name("named section"); | |
section.name("section"); | |
expr.name("expression"); | |
} | |
qi::rule<Iter, lvmtext_t(), lvmtext_skipper<Iter> > expr; | |
qi::rule<Iter, lvmtext_array(), lvmtext_skipper<Iter> > array; | |
qi::rule<Iter, lvmtext_keyval(), lvmtext_skipper<Iter> > keyval; | |
qi::rule<Iter, lvmtext_keyval(), lvmtext_skipper<Iter> > named_section; | |
qi::rule<Iter, lvmtext_section(), lvmtext_skipper<Iter> > section; | |
qi::rule<Iter, lvmtext_string()> identifier; | |
qi::rule<Iter, lvmtext_int()> integer_r; | |
qi::rule<Iter, lvmtext_string()> quoted_string; | |
qi::rule<Iter, lvmtext_string()> string; | |
qi::rule<Iter, char()> escape_seq; | |
}; | |
void tab(size_t indent) { | |
for (size_t i = 0; i < indent; ++i) | |
std::cout << " "; | |
} | |
template <typename Printer> | |
struct lvmtext_keyval_printer : boost::static_visitor<> { | |
const Printer& p; | |
const std::string& k; | |
const lvmtext_t& v; | |
size_t indent; | |
lvmtext_keyval_printer(const Printer& p, const std::string& k, | |
const lvmtext_t& v, size_t indent = 0) | |
: p(p), k(k), v(v), indent(indent) { } | |
void pref() const { | |
tab(indent); | |
std::cout << k << " "; | |
} | |
void operator()(const lvmtext_section& s) const { | |
pref(); | |
boost::apply_visitor(p, v); | |
} | |
template <typename T> void operator()(const T& t) const { | |
pref(); | |
std::cout << "= "; | |
boost::apply_visitor(p, v); | |
} | |
}; | |
struct lvmtext_printer : boost::static_visitor<> { | |
size_t indent; | |
lvmtext_printer(size_t indent = 0) : indent(indent) { } | |
void operator()(const lvmtext_string& s) const { | |
std::cout << '"'; | |
lvmtext_string::const_iterator it = s.begin(); | |
for (; it != s.end(); ++it) { | |
if (*it == '\\' || *it == '"') | |
std::cout << '\\'; | |
std::cout << *it; | |
} | |
std::cout << '"'; | |
} | |
void operator()(const lvmtext_int& i) const { | |
std::cout << i; | |
} | |
void operator()(const lvmtext_array& a) const { | |
std::cout << '['; | |
std::vector<lvmtext_t>::const_iterator it = a.items.begin(); | |
bool first = true; | |
for (; it != a.items.end(); ++it) { | |
if (!first) | |
std::cout << ", "; | |
first = false; | |
boost::apply_visitor(*this, *it); | |
} | |
std::cout << ']'; | |
} | |
void operator()(const lvmtext_section& s) const { | |
lvmtext_printer next(indent + 1); | |
std::cout << "{\n"; | |
lvmtext_section::items_type::const_iterator it = s.items.begin(); | |
for (; it != s.items.end(); ++it) { | |
lvmtext_keyval_printer<lvmtext_printer> kvp(next, it->first, | |
it->second, indent + 1); | |
boost::apply_visitor(kvp, it->second); | |
std::cout << "\n"; | |
} | |
tab(indent); | |
std::cout << "}"; | |
} | |
}; | |
void lvmtext_print_keyval(const lvmtext_keyval& kv, size_t indent = 0) { | |
lvmtext_keyval_printer<lvmtext_printer> kvp(lvmtext_printer(), kv.first, | |
kv.second); | |
boost::apply_visitor(kvp, kv.second); | |
} | |
} // namespace | |
int main(int argc, char *argv[]) { | |
if (argc < 2) { | |
std::cerr << "Need some input text\n"; | |
return -1; | |
} | |
std::string input = lvmfuse::slurp(argv[1]); | |
typedef std::string::const_iterator iter_t; | |
iter_t iter = input.begin(), end = input.end(); | |
lvmfuse::lvmtext_parser<iter_t> parser; | |
lvmfuse::lvmtext_skipper<iter_t> skip; | |
namespace qi = boost::spirit::qi; | |
std::string name; | |
lvmfuse::lvmtext_out desc; | |
bool ok = qi::parse(iter, end, | |
parser.identifier >> *qi::space >> qi::lit('{'), name); | |
if (!ok) { | |
std::cout << "name parse failed\n"; | |
} else { | |
std::cout << "name: " << name << "\n\n"; | |
iter = input.begin(); | |
ok = qi::phrase_parse(iter, end, parser, skip, desc); | |
if (ok && iter == end) { | |
lvmfuse::lvmtext_printer()(desc); | |
std::cout << "\n"; | |
} else { | |
std::cout << "parse failed\n"; | |
} | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
vg_inchon { | |
id = "PDEa5f-UUI1-sNlK-STGr-nY0u-g2Ro-yp0mHl" | |
seqno = 3 | |
format = "lvm2" # informational | |
status = ["RESIZEABLE", "READ", "WRITE"] | |
flags = [] | |
extent_size = 65536 | |
max_lv = 0 | |
max_pv = 0 | |
metadata_copies = 0 | |
physical_volumes { | |
pv0 { | |
id = "c5Qwkf-SGZL-9wAp-ODHk-sKfm-lZOH-wOkyxI" | |
device = "/dev/sda8" | |
status = ["ALLOCATABLE"] | |
flags = [] | |
dev_size = 93712384 | |
pe_start = 2048 | |
pe_count = 1429 | |
} | |
} | |
logical_volumes { | |
lv_swap { | |
id = "Ly5ntm-Ulxg-Hyl8-kEkw-LxFg-kkly-68sd59" | |
status = ["READ", "WRITE", "VISIBLE"] | |
flags = [] | |
creation_host = "inchon.localdomain" | |
creation_time = 1341261432 | |
segment_count = 1 | |
segment1 { | |
start_extent = 0 | |
extent_count = 187 | |
type = "striped" | |
stripe_count = 1 # linear | |
stripes = [ | |
"pv0", 0 | |
] | |
} | |
} | |
lv_root { | |
id = "tbgm4e-6xOn-V6US-lROm-18Eu-uAgy-V0oqnd" | |
status = ["READ", "WRITE", "VISIBLE"] | |
flags = [] | |
creation_host = "inchon.localdomain" | |
creation_time = 1341261432 | |
segment_count = 1 | |
segment1 { | |
start_extent = 0 | |
extent_count = 1242 | |
type = "striped" | |
stripe_count = 1 # linear | |
stripes = [ | |
"pv0", 187 | |
] | |
} | |
} | |
} | |
} | |
# Generated by LVM2 version 2.02.95(2) (2012-03-06): Mon Jul 2 16:37:12 2012 | |
contents = "Text Format Volume Group" | |
version = 1 | |
description = "" | |
creation_host = "inchon.localdomain" # Linux inchon.localdomain 3.3.4-5.fc17.x86_64 #1 SMP Mon May 7 17:29:34 UTC 2012 x86_64 | |
creation_time = 1341261432 # Mon Jul 2 16:37:12 2012 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment