# # # add_file "mangle.cc" # content [004a0da4eb54257a40e5b33b45e3cecfccae36e3] # ============================================================ --- mangle.cc 004a0da4eb54257a40e5b33b45e3cecfccae36e3 +++ mangle.cc 004a0da4eb54257a40e5b33b45e3cecfccae36e3 @@ -0,0 +1,125 @@ +// 2006-04-13 Timothy Brownawell +// GPL v2 or greater +// +// link with boost_program_options +// +// mangle -p pattern -d delim [-d delim...] -f fieldspec [-f fieldspec...] +// pattern is a printf-style pattern +// delim is the stanza delimiter +// fieldspec is key,num , where key is a key name and values are numbered +// 1 to n, and -n to -1 + +#include +#include +#include +#include + +#include +#include +#include + +#include "io.hh" + +using std::string; +using std::vector; +using std::cin; +using std::cout; +using std::pair; +using std::make_pair; +using basic_io::stanza; +using basic_io::stanza_reader; +using boost::lexical_cast; + +namespace po = boost::program_options; + +int main(int argc, char **argv) +{ + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "print this message") + ("pattern,p", po::value(), "output pattern, like printf") + ("field,f", po::value >(), "key,num field specifier") + ("delim,d", po::value >(), "key that begins a stanza") + ("reverse,V", "output non-matching stanzas") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + if (vm.count("help") || !vm.count("pattern") || !vm.count("delim")) + { + cout << desc << "\n"; + cout << "--pattern is required, " + << "and --delim must be given at least once.\n"; + cout << "field 0 is the key name\n"; + cout << "other fields are numberd 1 to n, and -n to -1\n"; + return 1; + } + string pattern = vm["pattern"].as(); + { + unsigned int p=pattern.find('\\'); + unsigned int pbase = p; + while (p < pattern.size()-1) + { + switch(pattern[p+1]) + { + case 'n': pattern.replace(p, 2, "\n"); break; + case 'r': pattern.replace(p, 2, "\r"); break; + case 't': pattern.replace(p, 2, "\t"); break; + case 'v': pattern.replace(p, 2, "\v"); break; + case '"': pattern.replace(p, 2, "\""); break; + case '\'': pattern.replace(p, 2, "\'"); break; + case '?': pattern.replace(p, 2, "\?"); break; + case 'a': pattern.replace(p, 2, "\a"); break; + case 'b': pattern.replace(p, 2, "\b"); break; + case 'f': pattern.replace(p, 2, "\f"); break; + case '\\': pattern.replace(p, 2, "\\"); break; + default: + pbase = p+1; + } + p = pattern.find('\\', pbase); + } + } + + vector > fields; + { + vector f = vm["field"].as >(); + for (vector::iterator i = f.begin(); i != f.end(); ++i) + { + unsigned int n = i->rfind(','); + string key = i->substr(0, n); + int pos = lexical_cast(i->substr(n+1)); + fields.push_back(make_pair(key, pos)); + } + } + + stanza st; + stanza_reader sr(cin, vm["delim"].as >()); + bool first = true; + while (sr.get(st)) + { + boost::format f(pattern); + for (vector >::iterator i = fields.begin(); + i != fields.end(); ++i) + { + using basic_io::item; + string s; + for (vector::iterator j = st.items.begin(); + j != st.items.end(); ++j) + { + if (j->key == i->first) + { + if (!i->second) + s = j->key; + else if (i->second < 0 && -i->second <= j->values.size()) + s = j->values[j->values.size() + i->second].parsed; + else if (i->second <= j->values.size()) + s = j->values[i->second-1].parsed; + break; + } + } + f % s; + } + cout<