From 5ddc5963ce06ecea574e90ca503a3ee598522d8f Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 4 Dec 2009 13:08:01 +0100 Subject: support multiline data output from scripts run under the grapher This is accompanied by support for multiline output in hover text. * grapher/StapParser.cxx (ioCallback): Read data 'til the end of line character, not just '\n'. Be careful to use I/O functions that don't treat '\n' specially. * grapher/StapParser.hxx: ditto * grapher/CairoWidget.cxx (CairoTextBox::draw): Perform line breaks for hover text. * testsuite/systemtap.examples/general/grapher.stp: Do multiline output of keyboard events. Also, fix longstanding breaking in the pty probe. --- grapher/CairoWidget.cxx | 36 +++++++++++++++++++++++++++++++----- grapher/GraphWidget.cxx | 2 +- grapher/StapParser.cxx | 27 +++++++++++++++++++-------- grapher/StapParser.hxx | 3 ++- 4 files changed, 53 insertions(+), 15 deletions(-) (limited to 'grapher') diff --git a/grapher/CairoWidget.cxx b/grapher/CairoWidget.cxx index f627dfaa..db0e464e 100644 --- a/grapher/CairoWidget.cxx +++ b/grapher/CairoWidget.cxx @@ -1,9 +1,15 @@ #include "CairoWidget.hxx" #include +#include + +#include namespace systemtap { + using namespace std; + using namespace boost; + void CairoPlayButton::draw(Cairo::RefPtr cr) { if (!_visible) @@ -44,10 +50,22 @@ namespace systemtap { if (!_visible) return; + vector lines; + split(lines, contents, is_any_of("\n")); + vector extents; + double width = 0.0, height = 0.0; + for (vector::iterator itr = lines.begin(), end = lines.end(); + itr != end; + ++itr) + { + Cairo::TextExtents extent; + cr->get_text_extents(*itr, extent); + extents.push_back(extent); + width = max(width, extent.width); + height += extent.height; + } + cr->save(); - Cairo::TextExtents extents; - cr->get_text_extents(contents, extents); - double width = extents.width, height = extents.height; cr->move_to(_x0 - 2, _y0 - 2); cr->line_to(_x0 + width + 2, _y0 - 2); cr->line_to(_x0 + width + 2, _y0 + height + 2); @@ -56,8 +74,16 @@ namespace systemtap cr->set_source_rgba(1.0, 1.0, 1.0, .8); cr->fill(); cr->set_source_rgba(0.0, 0.0, 0.0, 1.0); - cr->move_to(_x0, _y0 + height); - cr->show_text(contents); + vector::iterator titr = extents.begin(); + double texty = _y0; + for (vector::iterator itr = lines.begin(), end = lines.end(); + itr != end; + ++itr,++titr) + { + cr->move_to(_x0, texty + titr->height); + cr->show_text(*itr); + texty += titr->height; + } cr->restore(); } } diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index 9067988a..e37485b8 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -275,7 +275,7 @@ namespace systemtap { if (!_hoverText) _hoverText = shared_ptr(new CairoTextBox()); - _hoverText->setOrigin(_mouseX + 5, _mouseY - 5); + _hoverText->setOrigin(_mouseX + 10, _mouseY - 5); Graph::DatasetList& dataSets = g->getDatasets(); for (Graph::DatasetList::reverse_iterator ritr = dataSets.rbegin(), end = dataSets.rend(); diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index 6218e229..2a246475 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -76,14 +77,14 @@ vector commaSplit(const boost::sub_range& range) _win->hide(); return true; } - buf[bytes_read] = '\0'; - _buffer += buf; + _buffer.append(buf, bytes_read); string::size_type ret = string::npos; - while ((ret = _buffer.find('\n')) != string::npos) + while ((ret = _buffer.find(_lineEndChar)) != string::npos) { Glib::ustring dataString(_buffer, 0, ret); - // %DataSet and %CSV declare a data set; all other statements begin with - // the name of a data set. + // %DataSet and %CSV declare a data set; all other + // statements begin with the name of a data set. + // Except %LineEnd :) sub_range found; if (dataString[0] == '%') { @@ -142,6 +143,15 @@ vector commaSplit(const boost::sub_range& range) setIter->second)); } } + else if ((found = find_first(dataString, "%LineEnd:"))) + { + istringstream stream(Glib::ustring(found.end(), + dataString.end())); + int charAsInt = 0; + // parse hex and octal numbers too + stream >> std::setbase(0) >> charAsInt; + _lineEndChar = static_cast(charAsInt); + } else { cerr << "Unknown declaration " << dataString << endl; @@ -199,9 +209,10 @@ vector commaSplit(const boost::sub_range& range) else { int64_t time; - string data; - stream >> time >> data; - parseData(itr->second, time, data); + stringbuf data; + stream >> time; + stream.get(data, _lineEndChar); + parseData(itr->second, time, data.str()); } } } diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index a77ad1bc..4f1cbd5a 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -14,10 +14,11 @@ class StapParser GraphWidget* _widget; int _errFd; int _inFd; + unsigned char _lineEndChar; public: StapParser(Gtk::Window* win, GraphWidget* widget) : _win(win), _widget(widget), _errFd(-1), - _inFd(-1) + _inFd(-1), _lineEndChar('\n') { } void parseData(std::tr1::shared_ptr gdata, -- cgit