summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorMurray Cumming <murrayc@murrayc.com>2004-12-19 18:10:34 +0000
committerMurray Cumming <murrayc@src.gnome.org>2004-12-19 18:10:34 +0000
commit9e40b3dfcc5ae40b035f3f393a24c7b18ec3a8a9 (patch)
tree47894a2aa787debf2dc5b8162e2dbebb41c0e15b /examples
parent2ac23a2361c8df1403449234e33e5c2127bb4e5b (diff)
downloadglibmm-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.am2
-rw-r--r--examples/iochannel_stream/Makefile.am6
-rw-r--r--examples/iochannel_stream/fdstream.cc280
-rw-r--r--examples/iochannel_stream/fdstream.h89
-rw-r--r--examples/iochannel_stream/main.cc103
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;
+}