From d8b25fe2e585634567483124a33c3b779d2516f5 Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Sun, 23 Mar 2014 18:48:24 +0100 Subject: implemented php output streams as was asked for in issue #51 --- include/streams.h | 34 +++++++++++++++++++++ phpcpp.h | 1 + src/includes.h | 2 ++ src/streambuf.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/streambuf.h | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ src/streams.cpp | 40 +++++++++++++++++++++++++ 6 files changed, 247 insertions(+) create mode 100644 include/streams.h create mode 100644 src/streambuf.cpp create mode 100644 src/streambuf.h create mode 100644 src/streams.cpp diff --git a/include/streams.h b/include/streams.h new file mode 100644 index 0000000..c4d5339 --- /dev/null +++ b/include/streams.h @@ -0,0 +1,34 @@ +/** + * Streams.h + * + * Just like the standard std::cout and std::cerr objects to output data, you + * can use similar stream objects for outputting data to PHP. Php::out is the + * C++ equivalent of the PHP echo() function, and Php::err() is the C++ stream + * that behaves like calling trigger_error() from PHP. + * + * Php::out << "this is example text" << std::endl; + * Php::err << "this is an error message" << std::endl; + * + * @author Emiel Bruijntjes + * @copyright 2014 Copernica BV + */ + +/** + * Set up namespace + */ +namespace Php { + +/** + * Define the out and err objects + */ +extern std::ostream out; +extern std::ostream error; +extern std::ostream notice; +extern std::ostream warning; +extern std::ostream deprecated; + +/** + * End namespace + */ +} + diff --git a/phpcpp.h b/phpcpp.h index b9f10df..028636e 100644 --- a/phpcpp.h +++ b/phpcpp.h @@ -54,6 +54,7 @@ #include #include #include +#include /** * Macro to export a function diff --git a/src/includes.h b/src/includes.h index cf7dff3..2f5cc1c 100644 --- a/src/includes.h +++ b/src/includes.h @@ -73,6 +73,7 @@ #include "../include/namespace.h" #include "../include/extension.h" #include "../include/call.h" +#include "../include/streams.h" #include "../include/init.h" /** @@ -96,6 +97,7 @@ #include "hashiterator.h" #include "invaliditerator.h" #include "traverseiterator.h" +#include "streambuf.h" #ifndef ZVAL_COPY_VALUE #define ZVAL_COPY_VALUE(z, v) \ diff --git a/src/streambuf.cpp b/src/streambuf.cpp new file mode 100644 index 0000000..d4b4680 --- /dev/null +++ b/src/streambuf.cpp @@ -0,0 +1,90 @@ +/** + * StreamBuf.cpp + * + * Implementation file for the StreamBuf class + * + * @see http://www.mr-edd.co.uk/blog/beginners_guide_streambuf + * + * @author Emiel Bruijntjes + * @copyright 2014 Copernica BV + */ +#include "includes.h" + +/** + * Set up namespace + */ +namespace Php { + +/** + * Constructor + * @param error + */ +StreamBuf::StreamBuf(int error) : _error(error) +{ + // we reserve one byte, so that when overflow is called, we still have one + // byte extra in the buffer to put the overflowed byte int + setp(_buffer, _buffer+1024-1); +} + + +/** + * Method that is called when the internal buffer overflows + * @param c + * @return int + */ +int StreamBuf::overflow(int c) +{ + // end-of-file has not output, we call EOF directly, and by using the + // comma operator we ensure that EOF is returned + if (c == EOF) return sync(), EOF; + + // because we lied the underlying buffer about the size of the buffer + // by one byte, there is no real overflow, and we can still add the byte + // to the end of the buffer + *pptr() = c; + + // increment buffer size + pbump(1); + + // and now we're going to syn the buffer + return sync() == -1 ? EOF : c; +} + +/** + * Called when the internal buffer should be synchronized + * @return int + */ +int StreamBuf::sync() +{ + // current buffer size + size_t size = pptr() - pbase(); + + // is this the error stream or the regular output stream? + if (_error) + { + // write to error (the zend_error() method is a varargs function, + // which means that we have to include a printf() like format as first + // parameter. We can not specify pbase() directly, because (1) it is + // not null terminated and (2) it could contain % signs and allow all + // sorts of buffer overflows. + zend_error(_error, "%.*s", (int)size, pbase()); + + } + else + { + // write to zend + zend_write(pbase(), size); + } + + // reset the buffer + pbump(-size); + + // done + return 0; +} + +/** + * End namespace + */ +} + \ No newline at end of file diff --git a/src/streambuf.h b/src/streambuf.h new file mode 100644 index 0000000..ed1506a --- /dev/null +++ b/src/streambuf.h @@ -0,0 +1,80 @@ +/** + * StreamBuf.h + * + * PHP output stream buffer which is used by the Php::out object to + * have an output stream just like the regular std::ostream buffers, + * but that sends all output to PHP output + * + * @author Emiel Bruijntjes + * @copyright 2014 Copernica BV + */ + +/** + * Set up namespace + */ +namespace Php { + +/** + * Class definition + */ +class StreamBuf : public std::streambuf +{ +public: + /** + * Constructor + * @param error the error type, or 0 for regular output + */ + StreamBuf(int error); + + /** + * No copying or moving + * @param that + */ + StreamBuf(const StreamBuf &that) = delete; + StreamBuf(StreamBuf &&that) = delete; + + /** + * Destructor + */ + virtual ~StreamBuf() {} + + /** + * No copying or moving + * @param that + */ + StreamBuf &operator=(const StreamBuf &that) = delete; + StreamBuf &operator=(StreamBuf &&that) = delete; + +protected: + /** + * Method that is called when the internal buffer overflows + * @param c + * @return int + */ + virtual int overflow(int c = EOF) override; + + /** + * Called when the internal buffer should be synchronized + * @return int + */ + virtual int sync() override; + +private: + /** + * The error type, or 0 for regular output + * @var int + */ + int _error; + + /** + * The internal buffer + * @var char[] + */ + char _buffer[1024]; +}; + +/** + * End namespace + */ +} + diff --git a/src/streams.cpp b/src/streams.cpp new file mode 100644 index 0000000..ba6d916 --- /dev/null +++ b/src/streams.cpp @@ -0,0 +1,40 @@ +/** + * Streams.cpp + * + * Implementation of the streams + * + * @author Emiel Bruijntjes + * @copyright 2014 Copernica BV + */ +#include "includes.h" + +/** + * Set up namespace + */ +namespace Php { + +/** + * Some static buffers for writing data + * @var StreamBuf + */ +static StreamBuf bufOut (0); +static StreamBuf bufError (E_ERROR); +static StreamBuf bufWarning (E_WARNING); +static StreamBuf bufNotice (E_NOTICE); +static StreamBuf bufDeprecated (E_DEPRECATED); + +/** + * Create the actual steams + * @var std::ostream + */ +std::ostream out (&bufOut); +std::ostream error (&bufError); +std::ostream warning (&bufWarning); +std::ostream notice (&bufNotice); +std::ostream deprecated (&bufDeprecated); + +/** + * End namespace + */ +} + -- cgit v1.2.3