Make bilint read input from stdin

* include/abg-libxml-utils.h (new_reader_from_istream): Declare
	new public entry point.
	* src/abg-libxml-utils.cc (xml_istream_input_read)
	(xml_istream_input_close): New static functions.
	(new_reader_from_istream): Define new public input function.
	* include/abg-reader.h (read_translation_unit_from_istream):
	Declare new entry points.
	* src/abg-reader.cc (read_translation_unit_from_istream): Define
	new entry points.
	* tools/bilint.cc (options::{read_from_stdin, noout}): New
	members.
	(display_usage): Document --stdin and --noout.
	(parse_command_line): Adjust to consider that no option on the
	command line means reading from stdin, just like --stdin.  Support
	the --noout option as well.
	(main): Support Read the abi instr from stdin; in that case, what
	was read is just serialized back to stdout, unless --noout was
	supplied.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2013-12-11 15:20:42 +01:00
parent d3929eaf23
commit 7350cfd893
5 changed files with 181 additions and 41 deletions

View File

@ -21,6 +21,7 @@
/// @file
#include <tr1/memory>
#include <istream>
#include <libxml/xmlreader.h>
namespace abigail
@ -55,6 +56,7 @@ typedef shared_ptr<xmlChar> xml_char_sptr;
reader_sptr new_reader_from_file(const std::string& path);
reader_sptr new_reader_from_buffer(const std::string& buffer);
reader_sptr new_reader_from_istream(std::istream*);
xml_char_sptr build_xml_char_sptr(xmlChar*);
template<class T>

View File

@ -29,6 +29,7 @@
#ifndef __ABG_READER_H__
#define __ABG_READER_H__
#include <istream>
#include "abg-corpus.h"
namespace abigail
@ -55,6 +56,13 @@ bool
read_translation_unit_from_buffer(const string& buffer,
translation_unit& tu);
bool
read_translation_unit_from_istream(std::istream* in,
translation_unit& tu);
translation_unit_sptr
read_translation_unit_from_istream(std::istream* in);
abigail::corpus_sptr
read_corpus_from_file(const string& path);

View File

@ -21,12 +21,15 @@
/// @file
#include <string>
#include <iostream>
#include "abg-libxml-utils.h"
namespace abigail
{
namespace xml
{
using std::istream;
/// Instantiate an xmlTextReader that parses the content of an on-disk
/// file, wrap it into a smart pointer and return it.
///
@ -56,6 +59,58 @@ new_reader_from_buffer(const std::string& buffer)
return p;
}
/// This is an xmlInputReadCallback, meant to be passed to
/// xmlNewTextReaderForIO. It reads a number of bytes from an istream.
///
/// @param context an std::istream* cast into a void*. This is the
/// istream that the xmlTextReader is too read data from.
///
/// @param buffer the buffer where to copy the data read from the
/// input stream.
///
/// @param len the number of byte to read from the input stream and to
/// copy into @ref buffer.
///
/// @return the number of bytes read or -1 in case of error.
static int
xml_istream_input_read(void* context,
char* buffer,
int len)
{
istream* in = reinterpret_cast<istream*>(context);
in->read(buffer, len);
if (in->fail())
return -1;
return in->gcount();
}
/// This is an xmlInputCloseCallback, meant to be passed to
/// xmlNewTextReaderForIO. It's supposed to close the input stream
/// that the xmlTextReader is reading from. This particular
/// implementation is noop; it does nothing.
///
/// @return 0.
static int
xml_istream_input_close(void*)
{return 0;}
/// Instanciate an xmlTextReader that parses a content coming from an
/// input stream.
///
/// @param in the input stream to consider.
///
/// @return reader_sptr a pointer to the newly instantiated xml
/// reader.
reader_sptr
new_reader_from_istream(std::istream* in)
{
reader_sptr p =
build_sptr(xmlReaderForIO(&xml_istream_input_read,
&xml_istream_input_close,
in, "", 0, 0));
return p;
}
/// Build and return a shared_ptr for a pointer to xmlTextReader
template<>
shared_ptr<xmlTextReader>

View File

@ -48,6 +48,7 @@ using std::stack;
using std::tr1::unordered_map;
using std::tr1::dynamic_pointer_cast;
using std::vector;
using std::istream;
using zip_utils::zip_sptr;
using zip_utils::zip_file_sptr;
using zip_utils::open_archive;
@ -2697,6 +2698,38 @@ handle_class_tdecl(read_context& ctxt)
return is_ok;
}
/// De-serialize a translation unit from an ABI Instrumentation xml
/// file coming from an input stream.
///
/// @param in a pointer to the input stream.
///
/// @param tu the translation unit resulting from the parsing. This
/// is populated iff the function returns true.
///
/// @return true upon successful parsing, false otherwise.
bool
read_translation_unit_from_istream(istream* in,
translation_unit& tu)
{
read_context read_ctxt(xml::new_reader_from_istream(in));
return read_input(read_ctxt, tu);
}
/// De-serialize a translation unit from an ABI Instrumentation xml
/// file coming from an input stream.
///
/// @param in a pointer to the input stream.
///
/// @return a pointer to the resulting translation unit.
translation_unit_sptr
read_translation_unit_from_istream(istream* in)
{
translation_unit_sptr result(new translation_unit(""));
if (!read_translation_unit_from_istream(in, *result))
return translation_unit_sptr();
return result;
}
/// De-serialize a translation unit from an ABI Instrumentation XML
/// file at a given path.
///

View File

@ -41,14 +41,25 @@
using std::string;
using std::cerr;
using std::cin;
using std::cout;
using std::ostream;
using std::ofstream;
using abigail::tools::check_file;
using abigail::xml_reader::read_translation_unit_from_file;
using abigail::xml_reader::read_translation_unit_from_istream;
using abigail::xml_writer::write_translation_unit;
struct options
{
string file_path;
bool read_from_stdin;
bool noout;
options()
: read_from_stdin(false),
noout(false)
{}
};//end struct options;
void
@ -56,14 +67,19 @@ display_usage(const string& prog_name, ostream& out)
{
out << "usage: " << prog_name << "[options] [<bi-file1>\n"
<< " where options can be:\n"
<< " --help display this message\n";
<< " --help display this message\n"
<< " --noout do not display anything on stdout\n"
<< " --stdin|-- read bi-file content from stdin\n";
}
bool
parse_command_line(int argc, char* argv[], options& opts)
{
if (argc < 2)
return false;
{
opts.read_from_stdin = true;
return true;
}
for (int i = 1; i < argc; ++i)
{
@ -76,13 +92,16 @@ parse_command_line(int argc, char* argv[], options& opts)
}
else if (!strcmp(argv[i], "--help"))
return false;
else if (!strcmp(argv[i], "--stdin"))
opts.read_from_stdin = true;
else if (!strcmp(argv[i], "--noout"))
opts.noout = true;
else
return false;
}
if (opts.file_path.empty())
return false;
opts.read_from_stdin = true;
return true;
}
@ -97,45 +116,68 @@ main(int argc, char* argv[])
display_usage(argv[0], cerr);
return true;
}
if (!check_file(opts.file_path, cerr))
return true;
abigail::translation_unit_sptr tu =
read_translation_unit_from_file(opts.file_path);
if (!tu)
if (opts.read_from_stdin)
{
cerr << "failed to read " << opts.file_path << "\n";
return true;
if (!cin.good())
return true;
abigail::translation_unit_sptr tu =
read_translation_unit_from_istream(&cin);
if (!tu)
{
cerr << "failed to read the ABI instrumentation from stdin\n";
return true;
}
if (!opts.noout)
write_translation_unit(*tu, 0, cout);
return false;
}
else if (!opts.file_path.empty())
{
if (!check_file(opts.file_path, cerr))
return true;
abigail::translation_unit_sptr tu =
read_translation_unit_from_file(opts.file_path);
if (!tu)
{
cerr << "failed to read " << opts.file_path << "\n";
return true;
}
char tmpn[L_tmpnam];
tmpnam(tmpn);
string ofile_name = tmpn;
ofstream of(ofile_name.c_str(), std::ios_base::trunc);
if (!of.is_open())
{
cerr << "open temporary output file " << ofile_name << "\n";
return true;
}
bool r = write_translation_unit(*tu, /*indent=*/0, of);
bool is_ok = r;
of.close();
if (!is_ok)
cerr << "failed to write the translation unit "
<< opts.file_path << " back\n";
if (is_ok)
{
string cmd = "diff -u " + opts.file_path + " " + ofile_name;
if (system(cmd.c_str()))
is_ok = false;
}
remove(ofile_name.c_str());
return !is_ok;
}
char tmpn[L_tmpnam];
tmpnam(tmpn);
string ofile_name = tmpn;
ofstream of(ofile_name.c_str(), std::ios_base::trunc);
if (!of.is_open())
{
cerr << "open temporary output file " << ofile_name << "\n";
return true;
}
bool r = abigail::xml_writer::write_translation_unit(*tu, /*indent=*/0, of);
bool is_ok = r;
of.close();
if (!is_ok)
cerr << "failed to write the translation unit "
<< opts.file_path << " back\n";
if (is_ok)
{
string cmd = "diff -u " + opts.file_path + " " + ofile_name;
if (system(cmd.c_str()))
is_ok = false;
}
remove(ofile_name.c_str());
return !is_ok;
return true;
}