diff options
author | Murray Cumming <murrayc@murrayc.com> | 2004-12-19 18:10:34 +0000 |
---|---|---|
committer | Murray Cumming <murrayc@src.gnome.org> | 2004-12-19 18:10:34 +0000 |
commit | 9e40b3dfcc5ae40b035f3f393a24c7b18ec3a8a9 (patch) | |
tree | 47894a2aa787debf2dc5b8162e2dbebb41c0e15b /examples | |
parent | 2ac23a2361c8df1403449234e33e5c2127bb4e5b (diff) | |
download | glibmm-9e40b3dfcc5ae40b035f3f393a24c7b18ec3a8a9.tar.gz |
Adapted and added iochannel_stream example from Chris Vine in bug #138259.
2004-12-19 Murray Cumming <murrayc@murrayc.com>
* examples/: Adapted and added iochannel_stream example from
Chris Vine in bug #138259.
Diffstat (limited to 'examples')
-rw-r--r-- | examples/Makefile.am | 2 | ||||
-rw-r--r-- | examples/iochannel_stream/Makefile.am | 6 | ||||
-rw-r--r-- | examples/iochannel_stream/fdstream.cc | 280 | ||||
-rw-r--r-- | examples/iochannel_stream/fdstream.h | 89 | ||||
-rw-r--r-- | examples/iochannel_stream/main.cc | 103 |
5 files changed, 479 insertions, 1 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am index 4062a34e..7212b8a7 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,4 +1,4 @@ -example_dirs = markup options thread +example_dirs = markup options thread iochannel_stream # These use gtkmm stuff: # thread diff --git a/examples/iochannel_stream/Makefile.am b/examples/iochannel_stream/Makefile.am new file mode 100644 index 00000000..0097e60e --- /dev/null +++ b/examples/iochannel_stream/Makefile.am @@ -0,0 +1,6 @@ +include $(top_srcdir)/examples/Makefile.am_fragment + +#Build the executable, but don't install it. +noinst_PROGRAMS = example +example_SOURCES = main.cc fdstream.h fdstream.cc + diff --git a/examples/iochannel_stream/fdstream.cc b/examples/iochannel_stream/fdstream.cc new file mode 100644 index 00000000..dd75d1f8 --- /dev/null +++ b/examples/iochannel_stream/fdstream.cc @@ -0,0 +1,280 @@ +/* Copyright (C) 2004 The glibmm Development Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "fdstream.h" + +#include <glibmm/main.h> +#include <glibmm/convert.h> + +fdstreambuf::fdstreambuf() +{ + reset(); +} + +fdstreambuf::fdstreambuf(int fd, bool manage, bool convert) +: manage_(manage) +{ + create_iochannel(fd, manage, convert); +} + +void fdstreambuf::create_iochannel(int fd, bool /* manage */, bool convert) +{ + sync(); + reset(); + + if(fd >= 0) + { + iochannel_ = Glib::IOChannel::create_from_fd(fd); + + if(!convert) + { + iochannel_->set_encoding(""); + iochannel_->set_buffered(true); + } + else + { + std::string charset; + Glib::get_charset(charset); + iochannel_->set_encoding(charset); + } + + iochannel_->set_close_on_unref(manage_); + } +} + +void fdstreambuf::connect(const sigc::slot<bool, Glib::IOCondition>& callback, + Glib::IOCondition condition) +{ + Glib::signal_io().connect(callback, iochannel_, condition); +} + +// the standard requires sync to return 0 for success and -1 for error +int fdstreambuf::sync() +{ + if (!iochannel_) + return -1; + + try + { + iochannel_->flush(); + } + catch(const Glib::Error&) + { + return -1; + } + + return 0; +} + +void fdstreambuf::close_iochannel() +{ + iochannel_->set_close_on_unref(false); + reset(); + + try + { + iochannel_->close(true); + } + catch(const Glib::Error&) + {} +} + +// the standard requires this to return either the character +// written on overflow or traits_type::eof() (= EOF with char_type == char) +fdstreambuf::traits_type::int_type fdstreambuf::overflow(int_type c) +{ + if(!traits_type::eq_int_type(c, traits_type::eof())) + { + try + { + gsize result = 0; + char write_char = c; + iochannel_->write(&write_char, 1, result); + } + catch(const Glib::Error&) + { + return traits_type::eof(); + } + } + return traits_type::not_eof(c); +} + +// the standard requires this to return the number of characters written +// (which will be 0 for stream failure - it is not correct to return EOF) +std::streamsize fdstreambuf::xsputn(const char* source, std::streamsize num) +{ + gsize result = 0; + + // the documentation for Glib::IOChannel indicates that Glib::IOChannel::write() + // will only do a short write in the event of stream failure, so there is no + // need to check result and have a second bite (byte) at it as would be + // necessary with Unix write() + try + { + iochannel_->write(source, num, result); + } + catch(const Glib::Error&) + { + result = 0; + } + + return result; +} + +// the standard requires this to return the first character available +// on underflow or traits_type::eof() (= EOF with char_type == char) +fdstreambuf::traits_type::int_type fdstreambuf::underflow() +{ + if(gptr() < egptr()) + return traits_type::to_int_type(*gptr()); + + // copy the character in bump position (if any) to putback position + if(gptr() - eback()) + *pushback_buffer = *(gptr() - 1); + + // now insert a character into the bump position + gsize result = 0; + try + { + iochannel_->read(pushback_buffer + 1, 1, result); + } + catch(const Glib::Error&) + { + return traits_type::eof(); + } + + // if (result == 0) return traits_type::eof(); + + // reset buffer pointers + setg(pushback_buffer, + pushback_buffer + 1, + pushback_buffer + 2); + + // return character in bump/peek position + return traits_type::to_int_type(*gptr()); // == *(pushback_buffer + 1) +} + +// the standard requires this to return the number of characters fetched +// (which will be 0 for stream failure - it is not correct to return EOF) +std::streamsize fdstreambuf::xsgetn(char* dest, std::streamsize num) +{ + std::streamsize chars_read = 0; + + // available would normally be 0, but could be up to 2 if there + // have been putbacks or a peek and a putback + std::streamsize available = egptr() - gptr(); + + // if num is less than or equal to the characters already in the + // putback buffer, extract from buffer + if (num <= available) + { + traits_type::copy(dest, gptr(), num); + gbump(num); + chars_read = num; + } + else + { + // first copy out putback buffer + if (available) + { + traits_type::copy(dest, gptr(), available); + chars_read = available; + } + + // read up to everything else we need with Glib::IOChannel::read() + gsize result = 0; + try + { + do + { + iochannel_->read(dest + chars_read, + num - chars_read, + result); + if (result > 0) + chars_read += result; + } + while (result > 0 && result < static_cast<gsize>(num - chars_read)); + } + catch(const Glib::Error&) + { + return chars_read; + } + + if(chars_read) + { + // now mimic extraction of all characters by sgetc() by putting + // two characters into the buffer (if available) and resetting the + // buffer pointers + int putback_count = 0; + if(chars_read >= 2) + { + *pushback_buffer = *(dest + (chars_read - 2)); + putback_count = 2; + } + else + { + if(gptr() - eback()) + { + *pushback_buffer = *gptr(); + putback_count = 2; + } + else putback_count = 1; + } + + *(pushback_buffer + 1) = *(dest + (chars_read - 1)); + + // reset buffer pointers + setg(pushback_buffer + (2 - putback_count), + pushback_buffer + 2, + pushback_buffer + 2); + } + } + + return chars_read; +} + +fdstream::fdstream(int fd, bool manage, bool convert) +: std::istream(0), + std::ostream(0), + buf(fd, manage, convert) +{ + std::istream::rdbuf(&buf); + std::ostream::rdbuf(&buf); +} + +fdstream::fdstream() +: std::istream(0), + std::ostream(0) +{ + std::istream::rdbuf(&buf); + std::ostream::rdbuf(&buf); +} + +void fdstream::attach(int fd, bool manage, bool convert) +{ + buf.create_iochannel(fd, manage, convert); +} + +void fdstream::close() +{ + buf.close_iochannel(); +} + +void fdstream::connect(const sigc::slot<bool, Glib::IOCondition>& callback, Glib::IOCondition condition) +{ + buf.connect(callback, condition); +} diff --git a/examples/iochannel_stream/fdstream.h b/examples/iochannel_stream/fdstream.h new file mode 100644 index 00000000..3537e226 --- /dev/null +++ b/examples/iochannel_stream/fdstream.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2004 The glibmm Development Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef GLIBMMEXAMPLE_FDSTREAM_H +#define GLIBMMEXAMPLE_FDSTREAM_H + +#include <istream> +#include <ostream> +#include <streambuf> +#include <glibmm/iochannel.h> + +class fdstreambuf : public std::streambuf +{ +public: + fdstreambuf(int fd, bool manage, bool convert); + fdstreambuf(); + + // see comments in fdstream class definition about the convert argument + // in fdstreambuf::fdstreambuf() and fdstreambuf::create_iochannel + void create_iochannel(int fd, bool manage, bool convert); + void close_iochannel(); + void connect(const sigc::slot<bool, Glib::IOCondition>& callback, Glib::IOCondition condition); + + +protected: + virtual int_type underflow(); + virtual std::streamsize xsgetn(char* dest, std::streamsize num); + virtual int sync(); + virtual int_type overflow(int_type c); + virtual std::streamsize xsputn(const char* source, std::streamsize num); + +private: + Glib::RefPtr<Glib::IOChannel> iochannel_; + bool manage_; + + // pushback_buffer does not do any buffering: it reserves one character + // for pushback and one character for a peek() and/or for bumping + // with sbumpc/uflow() + char_type pushback_buffer[2]; + + void reset() { + setg(pushback_buffer + 1, pushback_buffer + 1, pushback_buffer + 1); + } +}; + +class fdstream : + public std::istream, + public std::ostream +{ +public: + + explicit fdstream(int fd, bool manage = true, bool convert = false); + fdstream(); + + // NOTE: in fdstream::attach() and fdstream::fdstream() + // you do not want to set convert to true if you are using + // Glib::ustring, as operator << and >> for Glib::ustring + // do their own conversion. If it is set, the IOChannel buffer + // will convert to the user's locale when writing to or reading + // from the filedescriptor. If in doubt, leave the default + // value of false. + + // If fdstream is managing a file descriptor, attaching a new + // one will close the old one + void attach(int fd, bool manage = true, bool convert = false); + + void close(); + void connect(const sigc::slot<bool, Glib::IOCondition>& callback, + Glib::IOCondition condition); + +private: + fdstreambuf buf; +}; + +#endif /*GLIBMMEXAMPLE_FDSTREAM_H*/ diff --git a/examples/iochannel_stream/main.cc b/examples/iochannel_stream/main.cc new file mode 100644 index 00000000..41ee140d --- /dev/null +++ b/examples/iochannel_stream/main.cc @@ -0,0 +1,103 @@ +/* Copyright (C) 2004 The glibmm Development Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <glibmm.h> +#include <fcntl.h> +#include <unistd.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <iostream> + +#include "fdstream.h" + +fdstream input_stream; +Glib::RefPtr<Glib::MainLoop> mainloop; + +//int read_fd; + +/* + send to the fifo with: + echo "Hello" > testfifo + + quit the program with: + echo "Q" > testfifo +*/ + +// this will be our signal handler for read operations +// it will print out the message sent to the fifo +// and quit the program if the message was, or began +// with, 'Q' +bool MyCallback(Glib::IOCondition io_condition) +{ + if ((io_condition & Glib::IO_IN) == 0) + { + std::cerr << "Invalid fifo response" << std::endl; + } + else + { + // stream for stdout (does the same as std::cout + // - this is an example of using fdstream for output) + fdstream out(1, false); + std::string text; + input_stream >> text; + out << text << std::endl; + + if (text[0] == 'Q') + mainloop->quit(); + } + + return true; +} + + +int main( /* int argc, char *argv[] */) +{ + Glib::init(); + + // the usual Glib::Main object + mainloop = Glib::MainLoop::create(); + + if(access("testfifo", F_OK) == -1) + { + // fifo doesn't exit - create it + if (mkfifo("testfifo", 0666) != 0) + { + std::cerr << "error creating fifo" << std::endl; + return -1; + } + } + + int read_fd = open("testfifo", O_RDONLY); + if(read_fd == -1) + { + std::cerr << "error opening fifo" << std::endl; + return -1; + } + + input_stream.attach(read_fd); + input_stream.connect(sigc::ptr_fun(MyCallback), Glib::IO_IN); + + // and last but not least - run the application main loop + mainloop->run(); + + // now remove the temporary fifo + if(unlink("testfifo")) + std::cerr << "error removing fifo" << std::endl; + + return 0; +} |