00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef GNUPLOT_IOSTREAM_H
00024 #define GNUPLOT_IOSTREAM_H
00025
00026
00027 #include <stdio.h>
00028 #ifdef GNUPLOT_ENABLE_PTY
00029 #include <termios.h>
00030 #include <unistd.h>
00031 #include <pty.h>
00032 #endif // GNUPLOT_ENABLE_PTY
00033
00034
00035 #include <fstream>
00036 #include <iostream>
00037 #include <sstream>
00038 #include <stdexcept>
00039 #include <string>
00040 #include <utility>
00041 #include <iomanip>
00042 #include <vector>
00043
00044
00045 #include "boost/iostreams/device/file_descriptor.hpp"
00046 #include "boost/iostreams/stream.hpp"
00047 #include "boost/version.hpp"
00048 #include "boost/utility.hpp"
00049 #ifdef GNUPLOT_ENABLE_BLITZ
00050 #include "blitz/array.h"
00051 #endif
00052
00053
00054 #if BOOST_VERSION >= 104600
00055 #define GNUPLOT_USE_TMPFILE
00056 #include "boost/filesystem.hpp"
00057 #endif // BOOST_VERSION
00058
00059
00060 #ifdef WIN32
00061 #define PCLOSE _pclose
00062 #define POPEN _popen
00063 #define FILENO _fileno
00064 #else
00065 #define PCLOSE pclose
00066 #define POPEN popen
00067 #define FILENO fileno
00068 #endif
00069
00071
00072 #ifdef GNUPLOT_USE_TMPFILE
00073
00074 class GnuplotTmpfile {
00075 public:
00076 GnuplotTmpfile() :
00077 file(boost::filesystem::unique_path(
00078 boost::filesystem::temp_directory_path() /
00079 "tmp-gnuplot-%%%%-%%%%-%%%%-%%%%"))
00080 { }
00081
00082 private:
00083
00084 GnuplotTmpfile(const GnuplotTmpfile &);
00085 const GnuplotTmpfile& operator=(const GnuplotTmpfile &);
00086
00087 public:
00088 ~GnuplotTmpfile() {
00089
00090 try {
00091 remove(file);
00092 } catch(const std::exception &e) {
00093 std::cerr << "Failed to remove temporary file " << file << std::endl;
00094 }
00095 }
00096
00097 public:
00098 boost::filesystem::path file;
00099 };
00100 #endif // GNUPLOT_USE_TMPFILE
00101
00103
00104
00105 class GnuplotFeedback {
00106 public:
00107 GnuplotFeedback() { }
00108 virtual ~GnuplotFeedback() { }
00109 virtual std::string filename() const = 0;
00110 virtual FILE *handle() const = 0;
00111
00112 private:
00113
00114 GnuplotFeedback(const GnuplotFeedback &);
00115 const GnuplotFeedback& operator=(const GnuplotFeedback &);
00116 };
00117
00118 #ifdef GNUPLOT_ENABLE_PTY
00119 #define GNUPLOT_ENABLE_FEEDBACK
00120 class GnuplotFeedbackPty : public GnuplotFeedback {
00121 public:
00122 explicit GnuplotFeedbackPty(bool debug_messages) :
00123 pty_fn(),
00124 pty_fh(NULL),
00125 master_fd(-1),
00126 slave_fd(-1)
00127 {
00128
00129 if(0 > openpty(&master_fd, &slave_fd, NULL, NULL, NULL)) {
00130 perror("openpty");
00131 throw std::runtime_error("openpty failed");
00132 }
00133 char pty_fn_buf[1024];
00134 if(ttyname_r(slave_fd, pty_fn_buf, 1024)) {
00135 perror("ttyname_r");
00136 throw std::runtime_error("ttyname failed");
00137 }
00138 pty_fn = std::string(pty_fn_buf);
00139 if(debug_messages) {
00140 std::cerr << "feedback_fn=" << pty_fn << std::endl;
00141 }
00142
00143
00144 struct termios tios;
00145 if(tcgetattr(slave_fd, &tios) < 0) {
00146 perror("tcgetattr");
00147 throw std::runtime_error("tcgetattr failed");
00148 }
00149 tios.c_lflag &= ~(ECHO | ECHONL);
00150 if(tcsetattr(slave_fd, TCSAFLUSH, &tios) < 0) {
00151 perror("tcsetattr");
00152 throw std::runtime_error("tcsetattr failed");
00153 }
00154
00155 pty_fh = fdopen(master_fd, "r");
00156 if(!pty_fh) {
00157 throw std::runtime_error("fdopen failed");
00158 }
00159 }
00160
00161 private:
00162
00163 GnuplotFeedbackPty(const GnuplotFeedbackPty &);
00164 const GnuplotFeedbackPty& operator=(const GnuplotFeedbackPty &);
00165
00166 public:
00167 ~GnuplotFeedbackPty() {
00168 if(pty_fh) fclose(pty_fh);
00169 if(master_fd > 0) ::close(master_fd);
00170 if(slave_fd > 0) ::close(slave_fd);
00171 }
00172
00173 std::string filename() const {
00174 return pty_fn;
00175 }
00176
00177 FILE *handle() const {
00178 return pty_fh;
00179 }
00180
00181 private:
00182 std::string pty_fn;
00183 FILE *pty_fh;
00184 int master_fd, slave_fd;
00185 };
00186
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 #endif // GNUPLOT_ENABLE_PTY, GNUPLOT_USE_TMPFILE
00224
00226
00227
00228 class GnuplotWriter {
00229 public:
00230 explicit GnuplotWriter(std::ostream *_stream, bool _send_e=true) :
00231 stream(_stream),
00232 send_e(_send_e)
00233 { }
00234
00235 private:
00236 template <class T>
00237 void sendEntry(T v) {
00238 *stream << v << " ";
00239 }
00240
00241 template <class T, class U>
00242 void sendEntry(std::pair<T, U> v) {
00243 sendEntry(v.first, v.second);
00244 }
00245
00246 template <class T, class U>
00247 void sendEntry(T t, U u) {
00248 sendEntry(t);
00249 sendEntry(u);
00250 }
00251
00252 std::string formatCode( float *) { return "%float"; }
00253 std::string formatCode( double *) { return "%double"; }
00254 std::string formatCode( int8_t *) { return "%int8"; }
00255 std::string formatCode( uint8_t *) { return "%uint8"; }
00256 std::string formatCode( int16_t *) { return "%int16"; }
00257 std::string formatCode(uint16_t *) { return "%uint16"; }
00258 std::string formatCode( int32_t *) { return "%int32"; }
00259 std::string formatCode(uint32_t *) { return "%uint32"; }
00260 std::string formatCode( int64_t *) { return "%int64"; }
00261 std::string formatCode(uint64_t *) { return "%uint64"; }
00262
00263 public:
00264
00265 template <class T>
00266 void sendIter(T p, T last) {
00267 while(p != last) {
00268 sendEntry(*p);
00269 *stream << "\n";
00270 ++p;
00271 }
00272 if(send_e) {
00273 *stream << "e" << std::endl;
00274 }
00275 }
00276
00277
00278 template <class T, class U>
00279 void sendIterPair(T x, T x_last, U y, U y_last) {
00280 while(x != x_last && y != y_last) {
00281 sendEntry(*x, *y);
00282 *stream << "\n";
00283 ++x;
00284 ++y;
00285 }
00286
00287 assert(x==x_last && y==y_last);
00288 if(send_e) {
00289 *stream << "e" << std::endl;
00290 }
00291 }
00292
00293
00294
00295 template <class T>
00296 void send(T arr) {
00297 sendIter(arr.begin(), arr.end());
00298 }
00299
00300 template <class T>
00301 void sendBinary(const std::vector<T> &arr) {
00302 stream->write(reinterpret_cast<const char *>(&arr[0]), arr.size() * sizeof(T));
00303 }
00304
00305 template <class T>
00306 std::string binfmt(const std::vector<T> &arr) {
00307 std::ostringstream tmp;
00308 tmp << " format='" << formatCode((T*)NULL) << "'";
00309 tmp << " array=(" << arr.size() << ")";
00310 tmp << " ";
00311 return tmp.str();
00312 }
00313
00314
00315 template <class T>
00316 void send(const std::vector<std::vector <T> > &vectors) {
00317
00318 assert(vectors.size() > 0);
00319 for(size_t i=1; i<vectors.size(); i++) {
00320 assert(vectors[i].size() == vectors[i-1].size());
00321 }
00322
00323 for(size_t i=0; i<vectors[0].size(); i++) {
00324 for(size_t j=0; j<vectors.size(); j++) {
00325 sendEntry(vectors[j][i]);
00326 }
00327 *stream << "\n";
00328 }
00329 if(send_e) {
00330 *stream << "e" << std::endl;
00331 }
00332 }
00333
00334 template <class T>
00335 std::string binfmt(const std::vector<std::vector<T> > &arr) {
00336 assert(arr.size() > 0);
00337 std::ostringstream tmp;
00338 tmp << " format='";
00339 for(size_t i=0; i<arr.size(); i++) {
00340 tmp << formatCode((T*)NULL);
00341 }
00342 tmp << "' array=(" << arr[0].size() << ")";
00343 tmp << " ";
00344 return tmp.str();
00345 }
00346
00347
00348 template <class T>
00349 void sendBinary(const std::vector<std::vector <T> > &vectors) {
00350
00351 assert(vectors.size() > 0);
00352 for(size_t i=1; i<vectors.size(); i++) {
00353 assert(vectors[i].size() == vectors[i-1].size());
00354 }
00355
00356 for(size_t i=0; i<vectors[0].size(); i++) {
00357 for(size_t j=0; j<vectors.size(); j++) {
00358 const T &val = vectors[j][i];
00359 stream->write(reinterpret_cast<const char *>(&val), sizeof(T));
00360 }
00361 }
00362 }
00363
00364 #ifdef GNUPLOT_ENABLE_BLITZ
00365
00366 template <class T>
00367 void send(const blitz::Array<T, 2> &a) {
00368 for(int i=a.lbound(0); i<=a.ubound(0); i++) {
00369 for(int j=a.lbound(1); j<=a.ubound(1); j++) {
00370 sendEntry(a(i, j));
00371 *stream << "\n";
00372 }
00373 *stream << "\n";
00374 }
00375 if(send_e) {
00376 *stream << "e" << std::endl;
00377 }
00378 }
00379
00380 template <class T, int d>
00381 void sendBinary(const blitz::Array<T, d> &arr) {
00382 stream->write(reinterpret_cast<const char *>(arr.data()), arr.size() * sizeof(T));
00383 }
00384
00385 template <class T>
00386 std::string binfmt(const blitz::Array<T, 2> &arr) {
00387 std::ostringstream tmp;
00388 tmp << " format='" << formatCode((T*)NULL) << "'";
00389 tmp << " array=(" << arr.extent(0) << "," << arr.extent(1) << ")";
00390 if(arr.isMajorRank(0)) tmp << "scan=yx";
00391 tmp << " ";
00392 return tmp.str();
00393 }
00394
00395 private:
00396 template <class T, int N>
00397 void sendEntry(blitz::TinyVector<T, N> v) {
00398 for(int i=0; i<N; i++) {
00399 sendEntry(v[i]);
00400 }
00401 }
00402
00403 template <class T, int N>
00404 std::string formatCode(blitz::TinyVector<T, N> *) {
00405 std::ostringstream tmp;
00406 for(int i=0; i<N; i++) {
00407 tmp << formatCode((T*)NULL);
00408 }
00409 return tmp.str();
00410 }
00411 #endif // GNUPLOT_ENABLE_BLITZ
00412
00413 private:
00414 std::ostream *stream;
00415 bool send_e;
00416 };
00417
00419
00420 class Gnuplot : public boost::iostreams::stream<
00421 boost::iostreams::file_descriptor_sink>
00422 {
00423 public:
00424 explicit Gnuplot(const std::string &cmd = "gnuplot") :
00425 boost::iostreams::stream<boost::iostreams::file_descriptor_sink>(
00426 FILENO(pout = POPEN(cmd.c_str(), "w")),
00427 boost::iostreams::never_close_handle
00428 ),
00429 pout(pout),
00430 is_pipe(true),
00431 feedback(NULL),
00432 writer(this),
00433 tmp_files(),
00434 debug_messages(false)
00435 {
00436 *this << std::scientific << std::setprecision(18);
00437 }
00438
00439 explicit Gnuplot(FILE *fh) :
00440 boost::iostreams::stream<boost::iostreams::file_descriptor_sink>(
00441 FILENO(pout = fh),
00442 boost::iostreams::never_close_handle
00443 ),
00444 pout(pout),
00445 is_pipe(false),
00446 feedback(NULL),
00447 writer(this),
00448 tmp_files(),
00449 debug_messages(false)
00450 {
00451 *this << std::scientific << std::setprecision(18);
00452 }
00453
00454 private:
00455
00456 Gnuplot(const Gnuplot &);
00457 const Gnuplot& operator=(const Gnuplot &);
00458
00459 public:
00460 ~Gnuplot() {
00461 if(debug_messages) {
00462 std::cerr << "ending gnuplot session" << std::endl;
00463 }
00464
00465
00466
00467
00468 *this << std::flush;
00469 fflush(pout);
00470
00471
00472
00473 if(is_pipe) {
00474 if(PCLOSE(pout)) {
00475 std::cerr << "pclose returned error" << std::endl;
00476 }
00477 } else {
00478 if(fclose(pout)) {
00479 std::cerr << "fclose returned error" << std::endl;
00480 }
00481 }
00482
00483 if(feedback) delete(feedback);
00484 }
00485
00486 public:
00487
00488
00489
00490 template <class T1>
00491 Gnuplot &send(T1 arg1) {
00492 writer.send(arg1);
00493 return *this;
00494 }
00495
00496
00497
00498
00499 template <typename T, std::size_t N>
00500 Gnuplot &send(T (&arr)[N]) {
00501 writer.sendIter(arr, arr+N);
00502 return *this;
00503 }
00504
00505 template <class T1, class T2>
00506 Gnuplot &send(T1 arg1, T2 arg2) {
00507 writer.sendIter(arg1, arg2);
00508 return *this;
00509 }
00510
00511 template <class T1, class T2, class T3, class T4>
00512 Gnuplot &send(T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
00513 writer.sendIterPair(arg1, arg2, arg3, arg4);
00514 return *this;
00515 }
00516
00517 template <class T1>
00518 Gnuplot &sendBinary(T1 arg1) {
00519 writer.sendBinary(arg1);
00520 return *this;
00521 }
00522
00523 template <class T>
00524 std::string binfmt(T arg) {
00525 return writer.binfmt(arg);
00526 }
00527
00528 private:
00529 std::string make_tmpfile() {
00530 #ifdef GNUPLOT_USE_TMPFILE
00531 boost::shared_ptr<GnuplotTmpfile> tmp_file(new GnuplotTmpfile());
00532
00533
00534 tmp_files.push_back(tmp_file);
00535 return tmp_file->file.string();
00536 #else
00537 throw(std::logic_error("no filename given and temporary files not enabled"));
00538 #endif // GNUPLOT_USE_TMPFILE
00539 }
00540
00541 public:
00542
00543 template <class T1>
00544 std::string file(T1 arg1, std::string filename="") {
00545 if(filename.empty()) filename = make_tmpfile();
00546 std::fstream tmp_stream(filename.c_str(), std::fstream::out);
00547 GnuplotWriter tmp_writer(&tmp_stream, false);
00548 tmp_writer.send(arg1);
00549 tmp_stream.close();
00550
00551 std::ostringstream cmdline;
00552
00553 cmdline << " '" << filename << "' ";
00554 return cmdline.str();
00555 }
00556
00557
00558 template <class T1>
00559 std::string binaryFile(T1 arg1, std::string filename="") {
00560 if(filename.empty()) filename = make_tmpfile();
00561 std::fstream tmp_stream(filename.c_str(), std::fstream::out | std::fstream::binary);
00562 GnuplotWriter tmp_writer(&tmp_stream);
00563 tmp_writer.sendBinary(arg1);
00564 tmp_stream.close();
00565
00566 std::ostringstream cmdline;
00567
00568 cmdline << " '" << filename << "' binary" << binfmt(arg1);
00569 return cmdline.str();
00570 }
00571
00572 void clearTmpfiles() {
00573
00574 tmp_files.clear();
00575 }
00576
00577 #ifdef GNUPLOT_ENABLE_FEEDBACK
00578
00579
00580
00581 void getMouse(
00582 double &mx, double &my, int &mb,
00583 std::string msg="Click Mouse!"
00584 ) {
00585 allocFeedback();
00586
00587 *this << "set mouse" << std::endl;
00588 *this << "pause mouse \"" << msg << "\\n\"" << std::endl;
00589 *this << "if (exists(\"MOUSE_X\")) print MOUSE_X, MOUSE_Y, MOUSE_BUTTON; else print 0, 0, -1;" << std::endl;
00590 if(debug_messages) {
00591 std::cerr << "begin scanf" << std::endl;
00592 }
00593 if(3 != fscanf(feedback->handle(), "%50lf %50lf %50d", &mx, &my, &mb)) {
00594 throw std::runtime_error("could not parse reply");
00595 }
00596 if(debug_messages) {
00597 std::cerr << "end scanf" << std::endl;
00598 }
00599 }
00600
00601 void allocFeedback() {
00602 if(!feedback) {
00603 #ifdef GNUPLOT_ENABLE_PTY
00604 feedback = new GnuplotFeedbackPty(debug_messages);
00605
00607
00608 #endif
00609 *this << "set print \"" << feedback->filename() << "\"" << std::endl;
00610 }
00611 }
00612 #endif // GNUPLOT_ENABLE_FEEDBACK
00613
00614 private:
00615 FILE *pout;
00616 bool is_pipe;
00617 GnuplotFeedback *feedback;
00618 GnuplotWriter writer;
00619 #ifdef GNUPLOT_USE_TMPFILE
00620 std::vector<boost::shared_ptr<GnuplotTmpfile> > tmp_files;
00621 #else
00622
00623 std::vector<int> tmp_files;
00624 #endif // GNUPLOT_USE_TMPFILE
00625
00626 public:
00627 bool debug_messages;
00628 };
00629
00630 #endif // GNUPLOT_IOSTREAM_H