<commit_before>/*
    Copyright (c) 2009-2011 250bpm s.r.o.
    Copyright (c) 2011 Botond Ballo
    Copyright (c) 2007-2009 iMatix Corporation

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to
    deal in the Software without restriction, including without limitation the
    rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    sell copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
*/

#ifndef __ZMQ_HPP_INCLUDED__
#define __ZMQ_HPP_INCLUDED__

#include <zmq.h>

#include <algorithm>
#include <cassert>
#include <cstring>
#include <exception>

//  Detect whether the compiler supports C++11 rvalue references.
#if (defined(__GNUC__) && (__GNUC__ > 4 || \
      (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && \
      defined(__GXX_EXPERIMENTAL_CXX0X__))
    #define ZMQ_HAS_RVALUE_REFS
    #define ZMQ_DELETED_FUNCTION = delete
#elif defined(__clang__)
    #if __has_feature(cxx_rvalue_references)
        #define ZMQ_HAS_RVALUE_REFS
    #endif

    #if __has_feature(cxx_deleted_functions)
        #define ZMQ_DELETED_FUNCTION = delete
    #endif
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
    #define ZMQ_HAS_RVALUE_REFS
    #define ZMQ_DELETED_FUNCTION
#else
    #define ZMQ_DELETED_FUNCTION
#endif

// In order to prevent unused variable warnings when building in non-debug
// mode use this macro to make assertions.
#ifndef NDEBUG
#   define ZMQ_ASSERT(expression) assert(expression)
#else
#   define ZMQ_ASSERT(expression) (expression)
#endif

namespace zmq
{

    typedef zmq_free_fn free_fn;
    typedef zmq_pollitem_t pollitem_t;

    class error_t : public std::exception
    {
    public:

        error_t () : errnum (zmq_errno ()) {}

        virtual const char *what () const throw ()
        {
            return zmq_strerror (errnum);
        }

        int num () const
        {
            return errnum;
        }

    private:

        int errnum;
    };

    inline int poll (zmq_pollitem_t *items_, int nitems_, long timeout_ = -1)
    {
        int rc = zmq_poll (items_, nitems_, timeout_);
        if (rc < 0)
            throw error_t ();
        return rc;
    }

    inline void version (int *major_, int *minor_, int *patch_)
    {
        zmq_version (major_, minor_, patch_);
    }

    class message_t
    {
        friend class socket_t;

    public:

        inline message_t ()
        {
            int rc = zmq_msg_init (&msg);
            if (rc != 0)
                throw error_t ();
        }

        inline explicit message_t (size_t size_)
        {
            int rc = zmq_msg_init_size (&msg, size_);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t (void *data_, size_t size_, free_fn *ffn_,
            void *hint_ = NULL)
        {
            int rc = zmq_msg_init_data (&msg, data_, size_, ffn_, hint_);
            if (rc != 0)
                throw error_t ();
        }

#ifdef ZMQ_HAS_RVALUE_REFS
        inline message_t (message_t &&rhs) : msg (rhs.msg)
        {
            int rc = zmq_msg_init (&rhs.msg);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t &operator = (message_t &&rhs)
        {
            std::swap (msg, rhs.msg);
            return *this;
        }
#endif

        inline ~message_t ()
        {
            int rc = zmq_msg_close (&msg);
            ZMQ_ASSERT (rc == 0);
        }

        inline void rebuild ()
        {
            int rc = zmq_msg_close (&msg);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init (&msg);
            if (rc != 0)
                throw error_t ();
        }

        inline void rebuild (size_t size_)
        {
            int rc = zmq_msg_close (&msg);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init_size (&msg, size_);
            if (rc != 0)
                throw error_t ();
        }

        inline void rebuild (void *data_, size_t size_, free_fn *ffn_,
            void *hint_ = NULL)
        {
            int rc = zmq_msg_close (&msg);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init_data (&msg, data_, size_, ffn_, hint_);
            if (rc != 0)
                throw error_t ();
        }

        inline void move (message_t *msg_)
        {
            int rc = zmq_msg_move (&msg, &(msg_->msg));
            if (rc != 0)
                throw error_t ();
        }

        inline void copy (message_t *msg_)
        {
            int rc = zmq_msg_copy (&msg, &(msg_->msg));
            if (rc != 0)
                throw error_t ();
        }

        inline void *data ()
        {
            return zmq_msg_data (&msg);
        }

        inline const void* data () const
        {
            return zmq_msg_data (const_cast<zmq_msg_t*>(&msg));
        }

        inline size_t size () const
        {
            return zmq_msg_size (const_cast<zmq_msg_t*>(&msg));
        }

    private:

        //  The underlying message
        zmq_msg_t msg;

        //  Disable implicit message copying, so that users won't use shared
        //  messages (less efficient) without being aware of the fact.
        message_t (const message_t&);
        void operator = (const message_t&);
    };

    class context_t
    {
        friend class socket_t;

    public:

        inline explicit context_t (int io_threads_)
        {
            ptr = zmq_init (io_threads_);
            if (ptr == NULL)
                throw error_t ();
        }

#ifdef ZMQ_HAS_RVALUE_REFS
        inline context_t (context_t &&rhs) : ptr (rhs.ptr)
        {
            rhs.ptr = NULL;
        }
        inline context_t &operator = (context_t &&rhs)
        {
            std::swap (ptr, rhs.ptr);
            return *this;
        }
#endif

        inline ~context_t ()
        {
            close();
        }

        inline void close()
        {
            if (ptr == NULL)
                return;
            int rc = zmq_term (ptr);
            ZMQ_ASSERT (rc == 0);
            ptr = NULL;
        }

        //  Be careful with this, it's probably only useful for
        //  using the C api together with an existing C++ api.
        //  Normally you should never need to use this.
        inline operator void* ()
        {
            return ptr;
        }

    private:

        void *ptr;

        context_t (const context_t&);
        void operator = (const context_t&);
    };

    class monitor_t
    {
	public:
		virtual void on_event_connected() = 0;
    	virtual void on_event_connect_delayed() = 0;
		virtual void on_event_connect_retried() = 0;
		virtual void on_event_listening() = 0;
		virtual void on_event_bind_failed() = 0;
		virtual void on_event_accepted() = 0;
		virtual void on_event_accept_failed() = 0;
		virtual void on_event_closed() = 0;
		virtual void on_event_close_failed() = 0;
		virtual void on_event_disconnected() = 0;
		virtual void on_event_unknown(int event) = 0;
    };

    class socket_t
    {
    public:

        inline socket_t (context_t &context_, int type_)
        {
            ptr = zmq_socket (context_.ptr, type_);
            if (ptr == NULL)
                throw error_t ();
        }

#ifdef ZMQ_HAS_RVALUE_REFS
        inline socket_t(socket_t&& rhs) : ptr(rhs.ptr)
        {
            rhs.ptr = NULL;
        }
        inline socket_t& operator=(socket_t&& rhs)
        {
            std::swap(ptr, rhs.ptr);
            return *this;
        }
#endif

        inline ~socket_t ()
        {
            close();
        }

        inline operator void* ()
        {
            return ptr;
        }

        inline void close()
        {
            if(ptr == NULL)
                // already closed
                return ;
            int rc = zmq_close (ptr);
            ZMQ_ASSERT (rc == 0);
            ptr = 0 ;
        }

        inline void setsockopt (int option_, const void *optval_,
            size_t optvallen_)
        {
            int rc = zmq_setsockopt (ptr, option_, optval_, optvallen_);
            if (rc != 0)
                throw error_t ();
        }

        inline void getsockopt (int option_, void *optval_,
            size_t *optvallen_)
        {
            int rc = zmq_getsockopt (ptr, option_, optval_, optvallen_);
            if (rc != 0)
                throw error_t ();
        }

        inline void bind (const char *addr_)
        {
            int rc = zmq_bind (ptr, addr_);
            if (rc != 0)
                throw error_t ();
			myaddr = std::string(addr_);
			monaddr = "inproc://monitor/" + myaddr;
			rc = zmq_socket_monitor (ptr, monaddr.c_str(), ZMQ_EVENT_ALL);
            if (rc != 0)
                throw error_t ();
        }

        inline void connect (const char *addr_)
        {
            int rc = zmq_connect (ptr, addr_);
            if (rc != 0)
                throw error_t ();
			myaddr = std::string(addr_);
			monaddr = "inproc://monitor/" + myaddr;
			rc = zmq_socket_monitor (ptr, monaddr.c_str(), ZMQ_EVENT_ALL);
            if (rc != 0)
                throw error_t ();
        }

        inline bool connected()
        {
            return(ptr != NULL);
        }

        inline void monitor (void* ctx, monitor_t* mon)
        {
			zmq_event_t event;
			int rc;

			assert(mon);

			void *s = zmq_socket (ctx, ZMQ_PAIR);
			assert (s);

			const char* addr = myaddr.c_str();

			rc = zmq_connect (s, monaddr.c_str());
			assert (rc == 0);
			while (true) {
				zmq_msg_t msg;
				zmq_msg_init (&msg);
				rc = zmq_recvmsg (s, &msg, 0);
				if (rc == -1 && zmq_errno() == ETERM) break;
				assert (rc != -1);
				memcpy (&event, zmq_msg_data (&msg), sizeof (event));

				switch (event.event) {
				case ZMQ_EVENT_CONNECTED:
					mon->on_event_connected();
					break;
				case ZMQ_EVENT_CONNECT_DELAYED:
					mon->on_event_connect_delayed();
					break;
				case ZMQ_EVENT_CONNECT_RETRIED:
					mon->on_event_connect_retried();
					break;
				case ZMQ_EVENT_LISTENING:
					mon->on_event_listening();
					break;
				case ZMQ_EVENT_BIND_FAILED:
					mon->on_event_bind_failed();
					break;
				case ZMQ_EVENT_ACCEPTED:
					mon->on_event_accepted();
					break;
				case ZMQ_EVENT_ACCEPT_FAILED:
					mon->on_event_accept_failed();
					break;
				case ZMQ_EVENT_CLOSED:
				    mon->on_event_closed();
					break;
				case ZMQ_EVENT_CLOSE_FAILED:
					mon->on_event_close_failed();
					break;
				case ZMQ_EVENT_DISCONNECTED:
					mon->on_event_disconnected();
					break;
				default:
					mon->on_event_unknown(event.event);
					break;
				}
				zmq_msg_close (&msg);
			}
			zmq_close (s);
            if (rc != 0)
                throw error_t ();
        }

        inline size_t send (const void *buf_, size_t len_, int flags_ = 0)
        {
            int nbytes = zmq_send (ptr, buf_, len_, flags_);
            if (nbytes >= 0)
                return (size_t) nbytes;
            if (zmq_errno () == EAGAIN)
                return 0;
            throw error_t ();
        }

        inline bool send (message_t &msg_, int flags_ = 0)
        {
            int nbytes = zmq_msg_send (&(msg_.msg), ptr, flags_);
            if (nbytes >= 0)
                return true;
            if (zmq_errno () == EAGAIN)
                return false;
            throw error_t ();
        }

        inline size_t recv (void *buf_, size_t len_, int flags_ = 0)
        {
            int nbytes = zmq_recv (ptr, buf_, len_, flags_);
            if (nbytes >= 0)
                return (size_t) nbytes;
            if (zmq_errno () == EAGAIN)
                return 0;
            throw error_t ();
        }

        inline bool recv (message_t *msg_, int flags_ = 0)
        {
            int nbytes = zmq_msg_recv (&(msg_->msg), ptr, flags_);
            if (nbytes >= 0)
                return true;
            if (zmq_errno () == EAGAIN)
                return false;
            throw error_t ();
        }

    private:

        void *ptr;
		monitor_t *mon;
		std::string monaddr;
		std::string myaddr;

        socket_t (const socket_t&) ZMQ_DELETED_FUNCTION;
        void operator = (const socket_t&) ZMQ_DELETED_FUNCTION;
    };

}

#endif
<commit_msg>work in progress...<commit_after>/*
    Copyright (c) 2009-2011 250bpm s.r.o.
    Copyright (c) 2011 Botond Ballo
    Copyright (c) 2007-2009 iMatix Corporation

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to
    deal in the Software without restriction, including without limitation the
    rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    sell copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    IN THE SOFTWARE.
*/

#ifndef __ZMQ_HPP_INCLUDED__
#define __ZMQ_HPP_INCLUDED__

#include <zmq.h>

#include <algorithm>
#include <cassert>
#include <cstring>
#include <exception>

//  Detect whether the compiler supports C++11 rvalue references.
#if (defined(__GNUC__) && (__GNUC__ > 4 || \
      (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && \
      defined(__GXX_EXPERIMENTAL_CXX0X__))
    #define ZMQ_HAS_RVALUE_REFS
    #define ZMQ_DELETED_FUNCTION = delete
#elif defined(__clang__)
    #if __has_feature(cxx_rvalue_references)
        #define ZMQ_HAS_RVALUE_REFS
    #endif

    #if __has_feature(cxx_deleted_functions)
        #define ZMQ_DELETED_FUNCTION = delete
    #endif
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
    #define ZMQ_HAS_RVALUE_REFS
    #define ZMQ_DELETED_FUNCTION
#else
    #define ZMQ_DELETED_FUNCTION
#endif

// In order to prevent unused variable warnings when building in non-debug
// mode use this macro to make assertions.
#ifndef NDEBUG
#   define ZMQ_ASSERT(expression) assert(expression)
#else
#   define ZMQ_ASSERT(expression) (expression)
#endif

namespace zmq
{

    typedef zmq_free_fn free_fn;
    typedef zmq_pollitem_t pollitem_t;

    class error_t : public std::exception
    {
    public:

        error_t () : errnum (zmq_errno ()) {}

        virtual const char *what () const throw ()
        {
            return zmq_strerror (errnum);
        }

        int num () const
        {
            return errnum;
        }

    private:

        int errnum;
    };

    inline int poll (zmq_pollitem_t *items_, int nitems_, long timeout_ = -1)
    {
        int rc = zmq_poll (items_, nitems_, timeout_);
        if (rc < 0)
            throw error_t ();
        return rc;
    }

    inline void version (int *major_, int *minor_, int *patch_)
    {
        zmq_version (major_, minor_, patch_);
    }

    class message_t
    {
        friend class socket_t;

    public:

        inline message_t ()
        {
            int rc = zmq_msg_init (&msg);
            if (rc != 0)
                throw error_t ();
        }

        inline explicit message_t (size_t size_)
        {
            int rc = zmq_msg_init_size (&msg, size_);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t (void *data_, size_t size_, free_fn *ffn_,
            void *hint_ = NULL)
        {
            int rc = zmq_msg_init_data (&msg, data_, size_, ffn_, hint_);
            if (rc != 0)
                throw error_t ();
        }

#ifdef ZMQ_HAS_RVALUE_REFS
        inline message_t (message_t &&rhs) : msg (rhs.msg)
        {
            int rc = zmq_msg_init (&rhs.msg);
            if (rc != 0)
                throw error_t ();
        }

        inline message_t &operator = (message_t &&rhs)
        {
            std::swap (msg, rhs.msg);
            return *this;
        }
#endif

        inline ~message_t ()
        {
            int rc = zmq_msg_close (&msg);
            ZMQ_ASSERT (rc == 0);
        }

        inline void rebuild ()
        {
            int rc = zmq_msg_close (&msg);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init (&msg);
            if (rc != 0)
                throw error_t ();
        }

        inline void rebuild (size_t size_)
        {
            int rc = zmq_msg_close (&msg);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init_size (&msg, size_);
            if (rc != 0)
                throw error_t ();
        }

        inline void rebuild (void *data_, size_t size_, free_fn *ffn_,
            void *hint_ = NULL)
        {
            int rc = zmq_msg_close (&msg);
            if (rc != 0)
                throw error_t ();
            rc = zmq_msg_init_data (&msg, data_, size_, ffn_, hint_);
            if (rc != 0)
                throw error_t ();
        }

        inline void move (message_t *msg_)
        {
            int rc = zmq_msg_move (&msg, &(msg_->msg));
            if (rc != 0)
                throw error_t ();
        }

        inline void copy (message_t *msg_)
        {
            int rc = zmq_msg_copy (&msg, &(msg_->msg));
            if (rc != 0)
                throw error_t ();
        }

        inline void *data ()
        {
            return zmq_msg_data (&msg);
        }

        inline const void* data () const
        {
            return zmq_msg_data (const_cast<zmq_msg_t*>(&msg));
        }

        inline size_t size () const
        {
            return zmq_msg_size (const_cast<zmq_msg_t*>(&msg));
        }

    private:

        //  The underlying message
        zmq_msg_t msg;

        //  Disable implicit message copying, so that users won't use shared
        //  messages (less efficient) without being aware of the fact.
        message_t (const message_t&);
        void operator = (const message_t&);
    };

    class context_t
    {
        friend class socket_t;

    public:

        inline explicit context_t (int io_threads_)
        {
            ptr = zmq_init (io_threads_);
            if (ptr == NULL)
                throw error_t ();
        }

#ifdef ZMQ_HAS_RVALUE_REFS
        inline context_t (context_t &&rhs) : ptr (rhs.ptr)
        {
            rhs.ptr = NULL;
        }
        inline context_t &operator = (context_t &&rhs)
        {
            std::swap (ptr, rhs.ptr);
            return *this;
        }
#endif

        inline ~context_t ()
        {
            close();
        }

        inline void close()
        {
            if (ptr == NULL)
                return;
            int rc = zmq_term (ptr);
            ZMQ_ASSERT (rc == 0);
            ptr = NULL;
        }

        //  Be careful with this, it's probably only useful for
        //  using the C api together with an existing C++ api.
        //  Normally you should never need to use this.
        inline operator void* ()
        {
            return ptr;
        }

    private:

        void *ptr;

        context_t (const context_t&);
        void operator = (const context_t&);
    };

    class monitor_t
    {
	public:
		virtual void on_event_connected() = 0;
    	virtual void on_event_connect_delayed() = 0;
		virtual void on_event_connect_retried() = 0;
		virtual void on_event_listening() = 0;
		virtual void on_event_bind_failed() = 0;
		virtual void on_event_accepted() = 0;
		virtual void on_event_accept_failed() = 0;
		virtual void on_event_closed() = 0;
		virtual void on_event_close_failed() = 0;
		virtual void on_event_disconnected() = 0;
		virtual void on_event_unknown(int event) = 0;
    };

    class socket_t
    {
    public:

        inline socket_t (context_t &context_, int type_) : is_monitored(false)
        {
            ptr = zmq_socket (context_.ptr, type_);
            if (ptr == NULL)
                throw error_t ();
        }

#ifdef ZMQ_HAS_RVALUE_REFS
        inline socket_t(socket_t&& rhs) : ptr(rhs.ptr), is_monitored(false)
        {
            rhs.ptr = NULL;
        }
        inline socket_t& operator=(socket_t&& rhs)
        {
            std::swap(ptr, rhs.ptr);
            return *this;
        }
#endif

        inline ~socket_t ()
        {
            close();
        }

        inline operator void* ()
        {
            return ptr;
        }

        inline void close()
        {
            if(ptr == NULL)
                // already closed
                return ;
            int rc = zmq_close (ptr);
            ZMQ_ASSERT (rc == 0);
            ptr = 0 ;
        }

        inline void setsockopt (int option_, const void *optval_,
            size_t optvallen_)
        {
            int rc = zmq_setsockopt (ptr, option_, optval_, optvallen_);
            if (rc != 0)
                throw error_t ();
        }

        inline void getsockopt (int option_, void *optval_,
            size_t *optvallen_)
        {
            int rc = zmq_getsockopt (ptr, option_, optval_, optvallen_);
            if (rc != 0)
                throw error_t ();
        }

        inlinde void init_monitor(const char *addr_)
        {
            std::string myaddr = std::string(addr_);
            std::string monaddr = "inproc://monitor/" + myaddr;
			rc = zmq_socket_monitor (ptr, monaddr.c_str(), ZMQ_EVENT_ALL);
            if (rc != 0)
                throw error_t ();
        }

        inline void bind (const char *addr_)
        {
            int rc = zmq_bind (ptr, addr_);
            if (rc != 0)
                throw error_t ();
            if (is_monitored)
            {
                init_monitor()
            }
        }

        inline void connect (const char *addr_)
        {
            int rc = zmq_connect (ptr, addr_);
            if (rc != 0)
                throw error_t ();
            if (is_monitored)
            {
                init_monitor()
            }
        }

        inline bool connected()
        {
            return(ptr != NULL);
        }

        inline void monitor (void* ctx, monitor_t* mon)
        {
			zmq_event_t event;
			int rc;

			assert(mon);

			void *s = zmq_socket (ctx, ZMQ_PAIR);
			assert (s);

			const char* addr = myaddr.c_str();

			rc = zmq_connect (s, monaddr.c_str());
			assert (rc == 0);
			while (true) {
				zmq_msg_t msg;
				zmq_msg_init (&msg);
				rc = zmq_recvmsg (s, &msg, 0);
				if (rc == -1 && zmq_errno() == ETERM) break;
				assert (rc != -1);
				memcpy (&event, zmq_msg_data (&msg), sizeof (event));

				switch (event.event) {
				case ZMQ_EVENT_CONNECTED:
					mon->on_event_connected(event.connected.addr);
					break;
				case ZMQ_EVENT_CONNECT_DELAYED:
					mon->on_event_connect_delayed();
					break;
				case ZMQ_EVENT_CONNECT_RETRIED:
					mon->on_event_connect_retried();
					break;
				case ZMQ_EVENT_LISTENING:
					mon->on_event_listening();
					break;
				case ZMQ_EVENT_BIND_FAILED:
					mon->on_event_bind_failed();
					break;
				case ZMQ_EVENT_ACCEPTED:
					mon->on_event_accepted();
					break;
				case ZMQ_EVENT_ACCEPT_FAILED:
					mon->on_event_accept_failed();
					break;
				case ZMQ_EVENT_CLOSED:
				    mon->on_event_closed();
					break;
				case ZMQ_EVENT_CLOSE_FAILED:
					mon->on_event_close_failed();
					break;
				case ZMQ_EVENT_DISCONNECTED:
					mon->on_event_disconnected();
					break;
				default:
					mon->on_event_unknown(event.event);
					break;
				}
				zmq_msg_close (&msg);
			}
			zmq_close (s);
            if (rc != 0)
                throw error_t ();
        }

        inline size_t send (const void *buf_, size_t len_, int flags_ = 0)
        {
            int nbytes = zmq_send (ptr, buf_, len_, flags_);
            if (nbytes >= 0)
                return (size_t) nbytes;
            if (zmq_errno () == EAGAIN)
                return 0;
            throw error_t ();
        }

        inline bool send (message_t &msg_, int flags_ = 0)
        {
            int nbytes = zmq_msg_send (&(msg_.msg), ptr, flags_);
            if (nbytes >= 0)
                return true;
            if (zmq_errno () == EAGAIN)
                return false;
            throw error_t ();
        }

        inline size_t recv (void *buf_, size_t len_, int flags_ = 0)
        {
            int nbytes = zmq_recv (ptr, buf_, len_, flags_);
            if (nbytes >= 0)
                return (size_t) nbytes;
            if (zmq_errno () == EAGAIN)
                return 0;
            throw error_t ();
        }

        inline bool recv (message_t *msg_, int flags_ = 0)
        {
            int nbytes = zmq_msg_recv (&(msg_->msg), ptr, flags_);
            if (nbytes >= 0)
                return true;
            if (zmq_errno () == EAGAIN)
                return false;
            throw error_t ();
        }

        inline void enable_monitoring()
        {
            is_monitored = true;
        }

    private:
        bool is_monitored;
        void *ptr;
		monitor_t *mon;
		std::string monaddr;
		std::string myaddr;

        socket_t (const socket_t&) ZMQ_DELETED_FUNCTION;
        void operator = (const socket_t&) ZMQ_DELETED_FUNCTION;
    };

}

#endif
<|endoftext|>


<commit_before><commit_msg>ARM: Reduce the stack requirements of GetNoCodeAgeSequence.<commit_after><|endoftext|>


<commit_before>/* This file is part of Mapnik (c++ mapping toolkit)
 * Copyright (C) 2005 Artem Pavlenko
 *
 * Mapnik is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//$Id: postgis.cc 44 2005-04-22 18:53:54Z pavlenko $

#include "postgis.hpp"
#include <string>
#include <algorithm>
#include <set>
#include <sstream>
#include "connection_manager.hpp"

DATASOURCE_PLUGIN(postgis_datasource)

const std::string postgis_datasource::GEOMETRY_COLUMNS="geometry_columns";
const std::string postgis_datasource::SPATIAL_REF_SYS="spatial_ref_system";

using std::clog;
using std::clog;
using std::endl;

using boost::lexical_cast;
using boost::bad_lexical_cast;
using boost::shared_ptr;

postgis_datasource::postgis_datasource(const parameters& params)
    : table_(params.get("table")),
      type_(datasource::Vector),
      desc_(params.get("name")),
      creator_(params.get("host"),
	       params.get("dbname"),
	       params.get("user"),
	       params.get("password"))

{
    ConnectionManager *mgr=ConnectionManager::instance();
    mgr->registerPool(creator_,10,20);

    shared_ptr<Pool<Connection,ConnectionCreator> > pool=mgr->getPool(creator_.id());
    if (pool)
    {
	const shared_ptr<Connection>& conn = pool->borrowObject();
	if (conn && conn->isOK())
	{
	    PoolGuard<shared_ptr<Connection>,shared_ptr<Pool<Connection,ConnectionCreator> > > guard(conn,pool);

	    std::string table_name=table_from_sql(table_);

	    std::ostringstream s;
	    s << "select f_geometry_column,srid,type from ";
	    s << GEOMETRY_COLUMNS <<" where f_table_name='"<<table_name<<"'";

	    shared_ptr<ResultSet> rs=conn->executeQuery(s.str());

	    if (rs->next())
	    {
		try
		{
		    srid_ = lexical_cast<int>(rs->getValue("srid"));
		    desc_.set_srid(srid_);
		}
		catch (bad_lexical_cast &ex)
		{
		    clog << ex.what() << endl;
		}
		geometryColumn_=rs->getValue("f_geometry_column");
		std::string postgisType=rs->getValue("type");
	    }
	    rs->close();
	    s.str("");
	    s << "select xmin(ext),ymin(ext),xmax(ext),ymax(ext)";
	    s << " from (select estimated_extent('"<<table_name<<"','"<<geometryColumn_<<"') as ext) as tmp";

	    rs=conn->executeQuery(s.str());
	    if (rs->next())
	    {
		try
		{
		    double lox=lexical_cast<double>(rs->getValue(0));
		    double loy=lexical_cast<double>(rs->getValue(1));
		    double hix=lexical_cast<double>(rs->getValue(2));
		    double hiy=lexical_cast<double>(rs->getValue(3));
		    extent_.init(lox,loy,hix,hiy);
		}
		catch (bad_lexical_cast &ex)
		{
		    clog << ex.what() << endl;
		}
	    }
	    rs->close();

	    // collect attribute desc
	    s.str("");
	    s << "select * from "<<table_<<" limit 1";
	    rs=conn->executeQuery(s.str());
	    if (rs->next())
	    {
		int count = rs->getNumFields();
		for (int i=0;i<count;++i)
		{
		    std::string fld_name=rs->getFieldName(i);
		    int length = rs->getFieldLength(i);

		    int type_oid = rs->getTypeOID(i);
		    switch (type_oid)
		    {
		    case 17285: // geometry
			desc_.add_descriptor(attribute_descriptor(fld_name,Geometry));
			break;
		    case 21:    // int2
		    case 23:    // int4
			desc_.add_descriptor(attribute_descriptor(fld_name,Integer,false,length));
 			break;
                    case 701:  // float8
 			desc_.add_descriptor(attribute_descriptor(fld_name,Double,false,length));
		    case 1042:  // bpchar
		    case 1043:  // varchar
			desc_.add_descriptor(attribute_descriptor(fld_name,String));
			break;
		    default: // shouldn't get here
			clog << "unknown type_oid="<<type_oid<<endl;
			desc_.add_descriptor(attribute_descriptor(fld_name,String));
			break;
		    }
		}
	    }
	}
    }
}

std::string postgis_datasource::name_="postgis";

std::string postgis_datasource::name()
{
    return name_;
}

int postgis_datasource::type() const
{
    return type_;
}

layer_descriptor const& postgis_datasource::get_descriptor() const
{
    return desc_;
}

std::string postgis_datasource::table_from_sql(const std::string& sql)
{
    std::string table_name(sql);
    transform(table_name.begin(),table_name.end(),table_name.begin(),tolower);
    std::string::size_type idx=table_name.rfind("from");
    if (idx!=std::string::npos)
    {
        idx=table_name.find_first_not_of(" ",idx+4);
        table_name=table_name.substr(idx);
        idx=table_name.find_first_of(" )");
        return table_name.substr(0,idx);
    }
    return table_name;
}

featureset_ptr postgis_datasource::features(const query& q) const
{
    Featureset *fs=0;
    Envelope<double> const& box=q.get_bbox();
    ConnectionManager *mgr=ConnectionManager::instance();
    shared_ptr<Pool<Connection,ConnectionCreator> > pool=mgr->getPool(creator_.id());
    if (pool)
    {
	const shared_ptr<Connection>& conn = pool->borrowObject();
	if (conn && conn->isOK())
	{
	    PoolGuard<shared_ptr<Connection>,shared_ptr<Pool<Connection,ConnectionCreator> > > guard(conn,pool);
	    std::ostringstream s;
	    // can we rely on 'gid' name???
	    s << "select gid,asbinary("<<geometryColumn_<<") as geom";
	    std::set<std::string> const& props=q.property_names();
	    std::set<std::string>::const_iterator pos=props.begin();
	    while (pos!=props.end())
	    {
		s <<",\""<<*pos<<"\"";
		++pos;
	    }

	    s << " from " << table_<<" where "<<geometryColumn_<<" && setSRID('BOX3D(";
	    s << box.minx() << " " << box.miny() << ",";
	    s << box.maxx() << " " << box.maxy() << ")'::box3d,"<<srid_<<")";
	    clog << s.str() << endl;
	    shared_ptr<ResultSet> rs=conn->executeQuery(s.str(),1);
	    fs=new postgis_featureset(rs,props.size());
	}
    }
    return featureset_ptr(fs);
}

const Envelope<double>& postgis_datasource::envelope() const
{
    return extent_;
}

postgis_datasource::~postgis_datasource() {}
<commit_msg>changed from gid to ogc_fid (is it standard?)<commit_after>/* This file is part of Mapnik (c++ mapping toolkit)
 * Copyright (C) 2005 Artem Pavlenko
 *
 * Mapnik is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//$Id: postgis.cc 44 2005-04-22 18:53:54Z pavlenko $

#include "postgis.hpp"
#include <string>
#include <algorithm>
#include <set>
#include <sstream>
#include "connection_manager.hpp"

DATASOURCE_PLUGIN(postgis_datasource)

const std::string postgis_datasource::GEOMETRY_COLUMNS="geometry_columns";
const std::string postgis_datasource::SPATIAL_REF_SYS="spatial_ref_system";

using std::clog;
using std::clog;
using std::endl;

using boost::lexical_cast;
using boost::bad_lexical_cast;
using boost::shared_ptr;

postgis_datasource::postgis_datasource(const parameters& params)
    : table_(params.get("table")),
      type_(datasource::Vector),
      desc_(params.get("name")),
      creator_(params.get("host"),
	       params.get("dbname"),
	       params.get("user"),
	       params.get("password"))

{
    ConnectionManager *mgr=ConnectionManager::instance();
    mgr->registerPool(creator_,10,20);

    shared_ptr<Pool<Connection,ConnectionCreator> > pool=mgr->getPool(creator_.id());
    if (pool)
    {
	const shared_ptr<Connection>& conn = pool->borrowObject();
	if (conn && conn->isOK())
	{
	    PoolGuard<shared_ptr<Connection>,shared_ptr<Pool<Connection,ConnectionCreator> > > guard(conn,pool);

	    std::string table_name=table_from_sql(table_);

	    std::ostringstream s;
	    s << "select f_geometry_column,srid,type from ";
	    s << GEOMETRY_COLUMNS <<" where f_table_name='"<<table_name<<"'";

	    shared_ptr<ResultSet> rs=conn->executeQuery(s.str());

	    if (rs->next())
	    {
		try
		{
		    srid_ = lexical_cast<int>(rs->getValue("srid"));
		    desc_.set_srid(srid_);
		}
		catch (bad_lexical_cast &ex)
		{
		    clog << ex.what() << endl;
		}
		geometryColumn_=rs->getValue("f_geometry_column");
		std::string postgisType=rs->getValue("type");
	    }
	    rs->close();
	    s.str("");
	    s << "select xmin(ext),ymin(ext),xmax(ext),ymax(ext)";
	    s << " from (select estimated_extent('"<<table_name<<"','"<<geometryColumn_<<"') as ext) as tmp";

	    rs=conn->executeQuery(s.str());
	    if (rs->next())
	    {
		try
		{
		    double lox=lexical_cast<double>(rs->getValue(0));
		    double loy=lexical_cast<double>(rs->getValue(1));
		    double hix=lexical_cast<double>(rs->getValue(2));
		    double hiy=lexical_cast<double>(rs->getValue(3));
		    extent_.init(lox,loy,hix,hiy);
		}
		catch (bad_lexical_cast &ex)
		{
		    clog << ex.what() << endl;
		}
	    }
	    rs->close();

	    // collect attribute desc
	    s.str("");
	    s << "select * from "<<table_<<" limit 1";
	    rs=conn->executeQuery(s.str());
	    if (rs->next())
	    {
		int count = rs->getNumFields();
		for (int i=0;i<count;++i)
		{
		    std::string fld_name=rs->getFieldName(i);
		    int length = rs->getFieldLength(i);

		    int type_oid = rs->getTypeOID(i);
		    switch (type_oid)
		    {
		    case 17285: // geometry
			desc_.add_descriptor(attribute_descriptor(fld_name,Geometry));
			break;
		    case 21:    // int2
		    case 23:    // int4
			desc_.add_descriptor(attribute_descriptor(fld_name,Integer,false,length));
 			break;
                    case 701:  // float8
 			desc_.add_descriptor(attribute_descriptor(fld_name,Double,false,length));
		    case 1042:  // bpchar
		    case 1043:  // varchar
			desc_.add_descriptor(attribute_descriptor(fld_name,String));
			break;
		    default: // shouldn't get here
			clog << "unknown type_oid="<<type_oid<<endl;
			desc_.add_descriptor(attribute_descriptor(fld_name,String));
			break;
		    }
		}
	    }
	}
    }
}

std::string postgis_datasource::name_="postgis";

std::string postgis_datasource::name()
{
    return name_;
}

int postgis_datasource::type() const
{
    return type_;
}

layer_descriptor const& postgis_datasource::get_descriptor() const
{
    return desc_;
}

std::string postgis_datasource::table_from_sql(const std::string& sql)
{
    std::string table_name(sql);
    transform(table_name.begin(),table_name.end(),table_name.begin(),tolower);
    std::string::size_type idx=table_name.rfind("from");
    if (idx!=std::string::npos)
    {
        idx=table_name.find_first_not_of(" ",idx+4);
        table_name=table_name.substr(idx);
        idx=table_name.find_first_of(" )");
        return table_name.substr(0,idx);
    }
    return table_name;
}

featureset_ptr postgis_datasource::features(const query& q) const
{
    Featureset *fs=0;
    Envelope<double> const& box=q.get_bbox();
    ConnectionManager *mgr=ConnectionManager::instance();
    shared_ptr<Pool<Connection,ConnectionCreator> > pool=mgr->getPool(creator_.id());
    if (pool)
    {
	const shared_ptr<Connection>& conn = pool->borrowObject();
	if (conn && conn->isOK())
	{
	    PoolGuard<shared_ptr<Connection>,shared_ptr<Pool<Connection,ConnectionCreator> > > guard(conn,pool);
	    std::ostringstream s;
	    // can we rely on 'gid' name???
	    s << "select ogc_fid,asbinary("<<geometryColumn_<<") as geom";
	    std::set<std::string> const& props=q.property_names();
	    std::set<std::string>::const_iterator pos=props.begin();
	    while (pos!=props.end())
	    {
		s <<",\""<<*pos<<"\"";
		++pos;
	    }

	    s << " from " << table_<<" where "<<geometryColumn_<<" && setSRID('BOX3D(";
	    s << box.minx() << " " << box.miny() << ",";
	    s << box.maxx() << " " << box.maxy() << ")'::box3d,"<<srid_<<")";
	    clog << s.str() << endl;
	    shared_ptr<ResultSet> rs=conn->executeQuery(s.str(),1);
	    fs=new postgis_featureset(rs,props.size());
	}
    }
    return featureset_ptr(fs);
}

const Envelope<double>& postgis_datasource::envelope() const
{
    return extent_;
}

postgis_datasource::~postgis_datasource() {}
<|endoftext|>


<commit_before><commit_msg>Don't calculate other players' scores based on your own.<commit_after><|endoftext|>


<commit_before><commit_msg>Fix gcc false positive pedantic error:<commit_after><|endoftext|>


<commit_before>#include <TF3.h>
#include <TFile.h>
#include <TChain.h>
#include <TVectorD.h>

#include "RThetaPhi.h"
#include "Units.h"
using namespace GeFiCa;

#include <cmath>
#include <iostream>
using namespace std;

void RThetaPhi::DoSOR2(int idx)
{
   if (fIsFixed[idx])return;

   double density=fImpurity[idx]*Qe;
   double h2=fdC1m[idx];
   double h3=fdC1p[idx];
   double h4=fdC2m[idx];
   double h1=fdC2p[idx];
   double h0=fdC3m[idx];
   double h5=fdC3p[idx];

   // get potentials of points around point idx
   double pthetam,pthetap,prm,prp,pphip,pphim;
   if (idx<n1*n2) pphim=fV[idx+n-n1*n2];
   else pphim=fV[idx-n1*n2];
   if (idx>=n-n1*n2) pphip=fV[idx-(n-n1*n2)];
   else pphip=fV[idx+n1*n2];
   if (idx%(n1*n2)>(n1*n2)-n1-1) {
      if(idx<n/2) pthetap=fV[idx+n/2];
      else pthetap=fV[idx-n/2];
   } else
      pthetap=fV[idx+n1];
   if (idx%(n1*n2)<n1) {
      if(idx<n/2)pthetam=fV[idx+n/2];
      else pthetam=fV[idx-n/2];
   } else
      pthetam=fV[idx-n1];
   if ((idx%(n1*n2))%n1==n1-1) prp=fV[idx];
   else prp=fV[idx+1];
   if ((idx%(n1*n2))%n1==0) prm=fV[idx];
   else prm=fV[idx-1];

   double r=fC1[idx];
   double O=fC2[idx];
   double tmp = (density/epsilon/2
         +(prp-prm)/r/(h2+h3)
         +(pthetap-pthetam)/r/r/(h1+h4)/sin(O)*cos(O)/2
         +(prp/h3+prm/h2)/(h3+h2)
         +(pthetap/h1+pthetam/h4)/r/r/(h4+h1)
         +(pphip/h5+pphim/h0)/r/r/sin(O)/sin(O)/(h0+h5))
      /(     1/h2/h3
            +1/r/r/h1/h4
            +1/r/r/sin(O)/sin(O)/h5/h0);
   double min=prm;
   double max=prm;
   if(min>prp)min=prp;
   if (min>pphip)min=pphip;
   if (min>pphim)min=pphim;
   if (min>pthetam)min=pthetam;
   if (min>pthetam)min=pthetam;

   //find max
   if(max<prp)max=prp;
   if (max<pphip)min=pphip;
   if (max<pphim)max=pphim;
   if (max<pthetam)max=pthetam;
   if (max<pthetam)max=pthetam;
   //if tmp is greater or smaller than max and min, set tmp to it.
   //fV[idx]=Csor*(tmp-fV[idx])+fV[idx];
   //if need calculate depleted voltage
   double oldP=fV[idx];
   tmp=Csor*(tmp-oldP)+oldP;
   if(tmp<min) {
      fV[idx]=min;
      fIsDepleted[idx]=false;
   } else if(tmp>max) {
      fV[idx]=max;
      fIsDepleted[idx]=false;
   } else
      fIsDepleted[idx]=true;

   if(fIsDepleted[idx]||V0==V1) fV[idx]=tmp;
}
//_____________________________________________________________________________
//
double RThetaPhi::GetData(double tarx, double tary, double tarz, EOutput output)
{
   int idx=FindIdx(tarx,tary,tarz,0,n);
   double ab=(tarx-fC1[idx])/fdC1p[idx];
   double aa=1-ab;
   double ba=(tary-fC2[idx])/fdC2p[idx];
   double bb=1-ba;
   double ac=(tarz-fC3[idx])/fdC3p[idx];
   double ca=1-ac;
   double tar0,tar1,tar2,tar3,tar4,tar5,tar6,tar7,*tar=NULL;
   switch(output)
   {
      case 0:tar= fImpurity;break;
      case 1:tar= fV;break;
      case 2:tar= fE1;break;
      case 3:tar= fE2;break;
      case 4:tar= fE3;break;
   }
   if(tary==0)return (tar[n1*n2-1]+tar[n1*n2-1+n/2])/2;
   tar3=-1;
   tar5=-1;
   tar6=-1;
   tar7=-1;
   tar0=tar[idx];
   if(idx>=(n-n1*n2)) {
      tar4=tar[idx-n+n1*n2];
      tar5=tar[idx-n+n1*n2+1];
      tar6=tar[idx-n+n1*n2+n1];
      tar7=tar[idx-n+n1*n2+n1+1];
   } else
      tar4=tar[idx+n1*n2];

   if(idx%(n1*n2)%n1==n1-1) {tar2=0;tar3=0;tar6=0;tar7=0;}
   else {tar2=tar[idx+n1];}
   if(idx%(n1*n2)/n1==n2-1) {tar1=0;tar3=0;tar5=0;tar7=0;}
   else {tar1=tar[idx+1];}
   if(tar3==-1)tar3=tar[idx+n1+1];
   if(tar5==-1)tar5=tar[idx+n1*n2+1];
   if(tar6==-1)tar6=tar[idx+n1*n2+n1];
   if(tar7==-1)tar7=tar[idx+n1*n2+n1+1];

   return ((tar0*aa+tar1*ab)*ba+(tar2*aa+tar3*ab)*bb)*ac
      +((tar4*aa+tar5*ab)*ba+(tar6*aa+tar7*ab)*bb)*ca;
}
<commit_msg>updated<commit_after>#include <TF3.h>
#include <TFile.h>
#include <TChain.h>
#include <TVectorD.h>

#include "RThetaPhi.h"
#include "Units.h"
using namespace GeFiCa;

#include <cmath>
#include <iostream>
using namespace std;

void RThetaPhi::DoSOR2(int idx)
{
   if (fIsFixed[idx])return;

   double density=fImpurity[idx]*Qe;
   double h2=fdC1m[idx];
   double h3=fdC1p[idx];
   double h4=fdC2m[idx];
   double h1=fdC2p[idx];
   double h0=fdC3m[idx];
   double h5=fdC3p[idx];

   // get potentials of points around point idx
   double pthetam,pthetap,prm,prp,pphip,pphim;
   if (idx<n1*n2) pphim=fV[idx+n-n1*n2];
   else pphim=fV[idx-n1*n2];
   if (idx>=n-n1*n2) pphip=fV[idx-(n-n1*n2)];
   else pphip=fV[idx+n1*n2];
   if (idx%(n1*n2)>(n1*n2)-n1-1) {
      if(idx<n/2) pthetap=fV[idx+n/2];
      else pthetap=fV[idx-n/2];
   } else
      pthetap=fV[idx+n1];
   if (idx%(n1*n2)<n1) {
      if(idx<n/2)pthetam=fV[idx+n/2];
      else pthetam=fV[idx-n/2];
   } else
      pthetam=fV[idx-n1];
   if ((idx%(n1*n2))%n1==n1-1) prp=fV[idx];
   else prp=fV[idx+1];
   if ((idx%(n1*n2))%n1==0) prm=fV[idx];
   else prm=fV[idx-1];

   double r=fC1[idx];
   double O=fC2[idx];
   double tmp = (density/epsilon/2
         +(prp-prm)/r/(h2+h3)
         +(pthetap-pthetam)/r/r/(h1+h4)/sin(O)*cos(O)/2
         +(prp/h3+prm/h2)/(h3+h2)
         +(pthetap/h1+pthetam/h4)/r/r/(h4+h1)
         +(pphip/h5+pphim/h0)/r/r/sin(O)/sin(O)/(h0+h5))
      /(     1/h2/h3
            +1/r/r/h1/h4
            +1/r/r/sin(O)/sin(O)/h5/h0);
   double min=prm;
   double max=prm;
   if(min>prp)min=prp;
   if (min>pphip)min=pphip;
   if (min>pphim)min=pphim;
   if (min>pthetam)min=pthetam;
   if (min>pthetam)min=pthetam;

   //find max
   if(max<prp)max=prp;
   if (max<pphip)max=pphip;
   if (max<pphim)max=pphim;
   if (max<pthetam)max=pthetam;
   if (max<pthetam)max=pthetam;
   //if tmp is greater or smaller than max and min, set tmp to it.
   //fV[idx]=Csor*(tmp-fV[idx])+fV[idx];
   //if need calculate depleted voltage
   double oldP=fV[idx];
   tmp=Csor*(tmp-oldP)+oldP;
   if(tmp<min) {
      fV[idx]=min;
      fIsDepleted[idx]=false;
   } else if(tmp>max) {
      fV[idx]=max;
      fIsDepleted[idx]=false;
   } else
      fIsDepleted[idx]=true;

   if(fIsDepleted[idx]||V0==V1) fV[idx]=tmp;
}
//_____________________________________________________________________________
//
double RThetaPhi::GetData(double tarx, double tary, double tarz, EOutput output)
{
   int idx=FindIdx(tarx,tary,tarz,0,n);
   double ab=(tarx-fC1[idx])/fdC1p[idx];
   double aa=1-ab;
   double ba=(tary-fC2[idx])/fdC2p[idx];
   double bb=1-ba;
   double ac=(tarz-fC3[idx])/fdC3p[idx];
   double ca=1-ac;
   double tar0,tar1,tar2,tar3,tar4,tar5,tar6,tar7,*tar=NULL;
   switch(output)
   {
      case 0:tar= fImpurity;break;
      case 1:tar= fV;break;
      case 2:tar= fE1;break;
      case 3:tar= fE2;break;
      case 4:tar= fE3;break;
   }
   if(tary==0)return (tar[n1*n2-1]+tar[n1*n2-1+n/2])/2;
   tar3=-1;
   tar5=-1;
   tar6=-1;
   tar7=-1;
   tar0=tar[idx];
   if(idx>=(n-n1*n2)) {
      tar4=tar[idx-n+n1*n2];
      tar5=tar[idx-n+n1*n2+1];
      tar6=tar[idx-n+n1*n2+n1];
      tar7=tar[idx-n+n1*n2+n1+1];
   } else
      tar4=tar[idx+n1*n2];

   if(idx%(n1*n2)%n1==n1-1) {tar2=0;tar3=0;tar6=0;tar7=0;}
   else {tar2=tar[idx+n1];}
   if(idx%(n1*n2)/n1==n2-1) {tar1=0;tar3=0;tar5=0;tar7=0;}
   else {tar1=tar[idx+1];}
   if(tar3==-1)tar3=tar[idx+n1+1];
   if(tar5==-1)tar5=tar[idx+n1*n2+1];
   if(tar6==-1)tar6=tar[idx+n1*n2+n1];
   if(tar7==-1)tar7=tar[idx+n1*n2+n1+1];

   return ((tar0*aa+tar1*ab)*ba+(tar2*aa+tar3*ab)*bb)*ac
      +((tar4*aa+tar5*ab)*ba+(tar6*aa+tar7*ab)*bb)*ca;
}
<|endoftext|>


<commit_before>// Copyright 2017 Netherlands eScience Center and Netherlands Institute for Radio Astronomy (ASTRON)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <ReadData.hpp>

namespace AstroData
{

RingBufferError::RingBufferError(const std::string &message) : message(message) {}

RingBufferError::~RingBufferError() noexcept {}

const char *RingBufferError::what() const noexcept
{
    return message.c_str();
}

void readZappedChannels(Observation &observation, const std::string &inputFilename, std::vector<unsigned int> &zappedChannels)
{
    unsigned int nrChannels = 0;
    std::ifstream input;

    input.open(inputFilename);
    if (!input)
    {
        throw FileError("ERROR: impossible to open zapped channels file \"" + inputFilename + "\"");
    }
    while (!input.eof())
    {
        unsigned int channel = observation.getNrChannels();

        input >> channel;
        if (channel < observation.getNrChannels())
        {
            zappedChannels[channel] = 1;
            nrChannels++;
        }
    }
    input.close();
    observation.setNrZappedChannels(nrChannels);
}

void readIntegrationSteps(const Observation &observation, const std::string &inputFilename, std::set<unsigned int> &integrationSteps)
{
    std::ifstream input;

    input.open(inputFilename);
    if (!input)
    {
        throw FileError("ERROR: impossible to open integration steps file \"" + inputFilename + "\"");
    }
    while (!input.eof())
    {
        unsigned int step = observation.getNrSamplesPerBatch();

        input >> step;
        if (step < observation.getNrSamplesPerBatch())
        {
            integrationSteps.insert(step);
        }
    }
    input.close();
}

std::uint64_t getSIGPROCHeaderSize(const std::string &inputFilename)
{
    std::uint64_t headerSize = 0;
    std::uint8_t state = 0;
    char buffer = '\0';
    std::ifstream inputFile;

    inputFile.open(inputFilename.c_str(), std::ios::binary);
    inputFile.exceptions(std::ifstream::failbit);
    if ( !inputFile )
    {
        throw FileError("ERROR: impossible to open SIGPROC file \"" + inputFilename + "\".");
    }
    while ( inputFile.get(buffer) )
    {
        switch ( buffer )
        {
            case 'H':
                state = 1;
                break;
            case 'E':
                if ( (state == 1) || (state == 5) || (state == 8) )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            case 'A':
                if ( state == 2 )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            case 'D':
                if ( (state == 3) || (state == 9) )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            case 'R':
                if ( state == 6 )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            case '_':
                if ( state == 7 )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            case 'N':
                if ( state == 8 )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            default:
                break;
        }
        headerSize++;
        if ( state == 10 )
        {
            break;
        }
    }
    return headerSize;
}

#ifdef HAVE_PSRDADA
void readPSRDADAHeader(Observation &observation, dada_hdu_t &ringBuffer)
{
    // Staging variables for the header elements
    unsigned int uintValue = 0;
    float floatValue[2] = {0.0f, 0.0f};
    // Header string
    uint64_t headerBytes = 0;
    char *header = 0;

    header = ipcbuf_get_next_read(ringBuffer.header_block, &headerBytes);
    if ((header == 0) || (headerBytes == 0))
    {
        throw RingBufferError("ERROR: impossible to read the PSRDADA header");
    }
    ascii_header_get(header, "SAMPLES_PER_BATCH", "%d", &uintValue);
    observation.setNrSamplesPerBatch(uintValue);
    ascii_header_get(header, "NCHAN", "%d", &uintValue);
    ascii_header_get(header, "MIN_FREQUENCY", "%f", &floatValue[0]);
    ascii_header_get(header, "CHANNEL_BANDWIDTH", "%f", &floatValue[1]);
    observation.setFrequencyRange(observation.getNrSubbands(), uintValue, floatValue[0], floatValue[1]);
    ascii_header_get(header, "TSAMP", "%f", &floatValue[0]);
    observation.setSamplingTime(floatValue[0]);
    if (ipcbuf_mark_cleared(ringBuffer.header_block) < 0)
    {
        throw RingBufferError("ERROR: impossible to mark the PSRDADA header as cleared");
    }
}
#endif // HAVE_PSRDADA

} // namespace AstroData
<commit_msg>Correct state transition numbers.<commit_after>// Copyright 2017 Netherlands eScience Center and Netherlands Institute for Radio Astronomy (ASTRON)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <ReadData.hpp>

namespace AstroData
{

RingBufferError::RingBufferError(const std::string &message) : message(message) {}

RingBufferError::~RingBufferError() noexcept {}

const char *RingBufferError::what() const noexcept
{
    return message.c_str();
}

void readZappedChannels(Observation &observation, const std::string &inputFilename, std::vector<unsigned int> &zappedChannels)
{
    unsigned int nrChannels = 0;
    std::ifstream input;

    input.open(inputFilename);
    if (!input)
    {
        throw FileError("ERROR: impossible to open zapped channels file \"" + inputFilename + "\"");
    }
    while (!input.eof())
    {
        unsigned int channel = observation.getNrChannels();

        input >> channel;
        if (channel < observation.getNrChannels())
        {
            zappedChannels[channel] = 1;
            nrChannels++;
        }
    }
    input.close();
    observation.setNrZappedChannels(nrChannels);
}

void readIntegrationSteps(const Observation &observation, const std::string &inputFilename, std::set<unsigned int> &integrationSteps)
{
    std::ifstream input;

    input.open(inputFilename);
    if (!input)
    {
        throw FileError("ERROR: impossible to open integration steps file \"" + inputFilename + "\"");
    }
    while (!input.eof())
    {
        unsigned int step = observation.getNrSamplesPerBatch();

        input >> step;
        if (step < observation.getNrSamplesPerBatch())
        {
            integrationSteps.insert(step);
        }
    }
    input.close();
}

std::uint64_t getSIGPROCHeaderSize(const std::string &inputFilename)
{
    std::uint64_t headerSize = 0;
    std::uint8_t state = 0;
    char buffer = '\0';
    std::ifstream inputFile;

    inputFile.open(inputFilename.c_str(), std::ios::binary);
    inputFile.exceptions(std::ifstream::failbit);
    if ( !inputFile )
    {
        throw FileError("ERROR: impossible to open SIGPROC file \"" + inputFilename + "\".");
    }
    while ( inputFile.get(buffer) )
    {
        switch ( buffer )
        {
            case 'H':
                state = 1;
                break;
            case 'E':
                if ( (state == 1) || (state == 4) || (state == 7) )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            case 'A':
                if ( state == 2 )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            case 'D':
                if ( (state == 3) || (state == 9) )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            case 'R':
                if ( state == 5 )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            case '_':
                if ( state == 6 )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            case 'N':
                if ( state == 8 )
                {
                    state++;
                }
                else
                {
                    state = 0;
                }
                break;
            default:
                break;
        }
        headerSize++;
        if ( state == 10 )
        {
            break;
        }
    }
    return headerSize;
}

#ifdef HAVE_PSRDADA
void readPSRDADAHeader(Observation &observation, dada_hdu_t &ringBuffer)
{
    // Staging variables for the header elements
    unsigned int uintValue = 0;
    float floatValue[2] = {0.0f, 0.0f};
    // Header string
    uint64_t headerBytes = 0;
    char *header = 0;

    header = ipcbuf_get_next_read(ringBuffer.header_block, &headerBytes);
    if ((header == 0) || (headerBytes == 0))
    {
        throw RingBufferError("ERROR: impossible to read the PSRDADA header");
    }
    ascii_header_get(header, "SAMPLES_PER_BATCH", "%d", &uintValue);
    observation.setNrSamplesPerBatch(uintValue);
    ascii_header_get(header, "NCHAN", "%d", &uintValue);
    ascii_header_get(header, "MIN_FREQUENCY", "%f", &floatValue[0]);
    ascii_header_get(header, "CHANNEL_BANDWIDTH", "%f", &floatValue[1]);
    observation.setFrequencyRange(observation.getNrSubbands(), uintValue, floatValue[0], floatValue[1]);
    ascii_header_get(header, "TSAMP", "%f", &floatValue[0]);
    observation.setSamplingTime(floatValue[0]);
    if (ipcbuf_mark_cleared(ringBuffer.header_block) < 0)
    {
        throw RingBufferError("ERROR: impossible to mark the PSRDADA header as cleared");
    }
}
#endif // HAVE_PSRDADA

} // namespace AstroData
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

#include "appshell_extensions.h"

#include <algorithm>
#include <CommDlg.h>
#include <ShlObj.h>
#include <Shlwapi.h>
#include <stdio.h>
#include <sys/stat.h>

// Forward declarations for functions at the bottom of this file
void FixFilename(ExtensionString& filename);
void EscapeJSONString(const std::wstring& str, std::wstring& finalResult);
int ConvertErrnoCode(int errorCode, bool isReading = true);
int ConvertWinErrorCode(int errorCode, bool isReading = true);

static int CALLBACK SetInitialPathCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
    if (BFFM_INITIALIZED == uMsg && NULL != lpData)
    {
        SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lpData);
    }

    return 0;
}

int32 ShowOpenDialog(bool allowMulitpleSelection,
                     bool chooseDirectory,
                     ExtensionString title,
                     ExtensionString initialDirectory,
                     ExtensionString fileTypes,
                     CefRefPtr<CefListValue>& selectedFiles)
{
    wchar_t szFile[MAX_PATH];
    szFile[0] = 0;

    FixFilename(initialDirectory);

    // TODO (issue #64) - This method should be using IFileDialog instead of the
    /* outdated SHGetPathFromIDList and GetOpenFileName.

    Useful function to parse fileTypesStr:
    template<class T>
    int inline findAndReplaceString(T& source, const T& find, const T& replace)
    {
    int num=0;
    int fLen = find.size();
    int rLen = replace.size();
    for (int pos=0; (pos=source.find(find, pos))!=T::npos; pos+=rLen)
    {
    num++;
    source.replace(pos, fLen, replace);
    }
    return num;
    }
    */

    if (chooseDirectory) {
        BROWSEINFO bi = {0};
        bi.hwndOwner = GetActiveWindow();
        bi.lpszTitle = title.c_str();
        bi.ulFlags = BIF_NEWDIALOGSTYLE;
        bi.lpfn = SetInitialPathCallback;
        bi.lParam = (LPARAM)initialDirectory.c_str();

        LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
        if (pidl != 0) {
            if (SHGetPathFromIDList(pidl, szFile)) {
                // Add directory path to the result
                selectedFiles->SetString(0, szFile);
            }
            IMalloc* pMalloc = NULL;
            SHGetMalloc(&pMalloc);
            if (pMalloc) {
                pMalloc->Free(pidl);
                pMalloc->Release();
            }
        }
    } else {
        OPENFILENAME ofn;

        ZeroMemory(&ofn, sizeof(ofn));
        ofn.hwndOwner = GetActiveWindow();
        ofn.lStructSize = sizeof(ofn);
        ofn.lpstrFile = szFile;
        ofn.nMaxFile = MAX_PATH;

        // TODO (issue #65) - Use passed in file types. Note, when fileTypesStr is null, all files should be shown
        /* findAndReplaceString( fileTypesStr, std::string(" "), std::string(";*."));
        LPCWSTR allFilesFilter = L"All Files\0*.*\0\0";*/

        ofn.lpstrFilter = L"All Files\0*.*\0Web Files\0*.js;*.css;*.htm;*.html\0\0";

        ofn.lpstrInitialDir = initialDirectory.c_str();
        ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER;
        if (allowMulitpleSelection)
            ofn.Flags |= OFN_ALLOWMULTISELECT;

        if (GetOpenFileName(&ofn)) {
            if (allowMulitpleSelection) {
                // Multiple selection encodes the files differently

                // If multiple files are selected, the first null terminator
                // signals end of directory that the files are all in
                std::wstring dir(szFile);

                // Check for two null terminators, which signal that only one file
                // was selected
                if (szFile[dir.length() + 1] == '\0') {
                    selectedFiles->SetString(0, ExtensionString(dir));
                } else {
                    // Multiple files are selected
                    wchar_t fullPath[MAX_PATH];
                    for (int i = (dir.length() + 1), fileIndex = 0; ; fileIndex++) {
                        // Get the next file name
                        std::wstring file(&szFile[i]);

                        // Two adjacent null characters signal the end of the files
                        if (file.length() == 0)
                            break;

                        // The filename is relative to the directory that was specified as
                        // the first string
                        if (PathCombine(fullPath, dir.c_str(), file.c_str()) != NULL)
                            selectedFiles->SetString(fileIndex, ExtensionString(fullPath));

                        // Go to the start of the next file name
                        i += file.length() + 1;
                    }
                }

            } else {
                // If multiple files are not allowed, add the single file
                selectedFiles->SetString(0, szFile);
            }
        }
    }

    return NO_ERROR;
}

int32 ReadDir(ExtensionString path, CefRefPtr<CefListValue>& directoryContents)
{
    FixFilename(path);

    path += L"\\*";

    WIN32_FIND_DATA ffd;
    HANDLE hFind = FindFirstFile(path.c_str(), &ffd);

    std::vector<ExtensionString> resultFiles;
    std::vector<ExtensionString> resultDirs;

    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            // Ignore '.' and '..'
            if (!wcscmp(ffd.cFileName, L".") || !wcscmp(ffd.cFileName, L".."))
                continue;

            // Collect file and directory names separately
            if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                resultDirs.push_back(ExtensionString(ffd.cFileName));
            } else {
                resultFiles.push_back(ExtensionString(ffd.cFileName));
            }
        }
        while (FindNextFile(hFind, &ffd) != 0);

        FindClose(hFind);
    }
    else {
        return ConvertWinErrorCode(GetLastError());
    }

    // On Windows, list directories first, then files
    size_t i, total = 0;
    for (i = 0; i < resultDirs.size(); i++)
        directoryContents->SetString(total++, resultDirs[i]);
    for (i = 0; i < resultFiles.size(); i++)
        directoryContents->SetString(total++, resultFiles[i]);

    return NO_ERROR;
}

int32 GetFileModificationTime(ExtensionString filename, uint32& modtime, bool& isDir)
{
    FixFilename(filename);

    DWORD dwAttr = GetFileAttributes(filename.c_str());

    if (dwAttr == INVALID_FILE_ATTRIBUTES) {
        return ConvertWinErrorCode(GetLastError());
    }

    isDir = ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0);

    struct _stat buffer;
    if(_wstat(filename.c_str(), &buffer) == -1) {
        return ConvertErrnoCode(errno);
    }

    modtime = buffer.st_mtime;

    return NO_ERROR;
}

int32 ReadFile(ExtensionString filename, ExtensionString encoding, std::string& contents)
{
    FixFilename(filename);

    if (encoding != L"utf8")
        return ERR_UNSUPPORTED_ENCODING;

    DWORD dwAttr;
    dwAttr = GetFileAttributes(filename.c_str());
    if (INVALID_FILE_ATTRIBUTES == dwAttr)
        return ConvertWinErrorCode(GetLastError());

    if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
        return ERR_CANT_READ;

    HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ,
        0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    int32 error = NO_ERROR;

    if (INVALID_HANDLE_VALUE == hFile)
        return ConvertWinErrorCode(GetLastError());

    DWORD dwFileSize = GetFileSize(hFile, NULL);
    DWORD dwBytesRead;
    char* buffer = (char*)malloc(dwFileSize);
    if (buffer && ReadFile(hFile, buffer, dwFileSize, &dwBytesRead, NULL)) {
        contents = std::string(buffer, dwFileSize);
    }
    else {
        if (!buffer)
            error = ERR_UNKNOWN;
        else
            error = ConvertWinErrorCode(GetLastError());
    }
    CloseHandle(hFile);
    if (buffer)
        free(buffer);

    return error;
}

int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding)
{
    FixFilename(filename);

    if (encoding != L"utf8")
        return ERR_UNSUPPORTED_ENCODING;

    HANDLE hFile = CreateFile(filename.c_str(), GENERIC_WRITE,
        0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD dwBytesWritten;
    int error = NO_ERROR;

    if (INVALID_HANDLE_VALUE == hFile)
        return ConvertWinErrorCode(GetLastError(), false);

    // TODO (issue 67) -  Should write to temp file and handle encoding
    if (!WriteFile(hFile, contents.c_str(), contents.length(), &dwBytesWritten, NULL)) {
        error = ConvertWinErrorCode(GetLastError(), false);
    }

    CloseHandle(hFile);
    return error;
}

int32 SetPosixPermissions(ExtensionString filename, int32 mode)
{
    FixFilename(filename);

    DWORD dwAttr = GetFileAttributes(filename.c_str());

    if (dwAttr == INVALID_FILE_ATTRIBUTES)
        return ERR_NOT_FOUND;

    if ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0)
        return NO_ERROR;

    bool write = (mode & 0200) != 0;
    bool read = (mode & 0400) != 0;
    int mask = (write ? _S_IWRITE : 0) | (read ? _S_IREAD : 0);

    if (_wchmod(filename.c_str(), mask) == -1) {
        return ConvertErrnoCode(errno);
    }

    return NO_ERROR;
}

int32 DeleteFileOrDirectory(ExtensionString filename)
{
    FixFilename(filename);

    if (!DeleteFile(filename.c_str()))
        return ConvertWinErrorCode(GetLastError());

    return NO_ERROR;
}

void FixFilename(ExtensionString& filename)
{
    // Convert '/' to '\'
    replace(filename.begin(), filename.end(), '/', '\\');
}

// Maps errors from errno.h to the brackets error codes
// found in brackets_extensions.js
int ConvertErrnoCode(int errorCode, bool isReading)
{
    switch (errorCode) {
    case NO_ERROR:
        return NO_ERROR;
    case EINVAL:
        return ERR_INVALID_PARAMS;
    case ENOENT:
        return ERR_NOT_FOUND;
    default:
        return ERR_UNKNOWN;
    }
}

// Maps errors from  WinError.h to the brackets error codes
// found in brackets_extensions.js
int ConvertWinErrorCode(int errorCode, bool isReading)
{
    switch (errorCode) {
    case NO_ERROR:
        return NO_ERROR;
    case ERROR_PATH_NOT_FOUND:
    case ERROR_FILE_NOT_FOUND:
        return ERR_NOT_FOUND;
    case ERROR_ACCESS_DENIED:
        return isReading ? ERR_CANT_READ : ERR_CANT_WRITE;
    case ERROR_WRITE_PROTECT:
        return ERR_CANT_WRITE;
    case ERROR_HANDLE_DISK_FULL:
        return ERR_OUT_OF_SPACE;
    default:
        return ERR_UNKNOWN;
    }
}

<commit_msg>Remove the unneeded forward declaration.<commit_after>/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

#include "appshell_extensions.h"

#include <algorithm>
#include <CommDlg.h>
#include <ShlObj.h>
#include <Shlwapi.h>
#include <stdio.h>
#include <sys/stat.h>

// Forward declarations for functions at the bottom of this file
void FixFilename(ExtensionString& filename);
int ConvertErrnoCode(int errorCode, bool isReading = true);
int ConvertWinErrorCode(int errorCode, bool isReading = true);

static int CALLBACK SetInitialPathCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
    if (BFFM_INITIALIZED == uMsg && NULL != lpData)
    {
        SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lpData);
    }

    return 0;
}

int32 ShowOpenDialog(bool allowMulitpleSelection,
                     bool chooseDirectory,
                     ExtensionString title,
                     ExtensionString initialDirectory,
                     ExtensionString fileTypes,
                     CefRefPtr<CefListValue>& selectedFiles)
{
    wchar_t szFile[MAX_PATH];
    szFile[0] = 0;

    FixFilename(initialDirectory);

    // TODO (issue #64) - This method should be using IFileDialog instead of the
    /* outdated SHGetPathFromIDList and GetOpenFileName.

    Useful function to parse fileTypesStr:
    template<class T>
    int inline findAndReplaceString(T& source, const T& find, const T& replace)
    {
    int num=0;
    int fLen = find.size();
    int rLen = replace.size();
    for (int pos=0; (pos=source.find(find, pos))!=T::npos; pos+=rLen)
    {
    num++;
    source.replace(pos, fLen, replace);
    }
    return num;
    }
    */

    if (chooseDirectory) {
        BROWSEINFO bi = {0};
        bi.hwndOwner = GetActiveWindow();
        bi.lpszTitle = title.c_str();
        bi.ulFlags = BIF_NEWDIALOGSTYLE;
        bi.lpfn = SetInitialPathCallback;
        bi.lParam = (LPARAM)initialDirectory.c_str();

        LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
        if (pidl != 0) {
            if (SHGetPathFromIDList(pidl, szFile)) {
                // Add directory path to the result
                selectedFiles->SetString(0, szFile);
            }
            IMalloc* pMalloc = NULL;
            SHGetMalloc(&pMalloc);
            if (pMalloc) {
                pMalloc->Free(pidl);
                pMalloc->Release();
            }
        }
    } else {
        OPENFILENAME ofn;

        ZeroMemory(&ofn, sizeof(ofn));
        ofn.hwndOwner = GetActiveWindow();
        ofn.lStructSize = sizeof(ofn);
        ofn.lpstrFile = szFile;
        ofn.nMaxFile = MAX_PATH;

        // TODO (issue #65) - Use passed in file types. Note, when fileTypesStr is null, all files should be shown
        /* findAndReplaceString( fileTypesStr, std::string(" "), std::string(";*."));
        LPCWSTR allFilesFilter = L"All Files\0*.*\0\0";*/

        ofn.lpstrFilter = L"All Files\0*.*\0Web Files\0*.js;*.css;*.htm;*.html\0\0";

        ofn.lpstrInitialDir = initialDirectory.c_str();
        ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER;
        if (allowMulitpleSelection)
            ofn.Flags |= OFN_ALLOWMULTISELECT;

        if (GetOpenFileName(&ofn)) {
            if (allowMulitpleSelection) {
                // Multiple selection encodes the files differently

                // If multiple files are selected, the first null terminator
                // signals end of directory that the files are all in
                std::wstring dir(szFile);

                // Check for two null terminators, which signal that only one file
                // was selected
                if (szFile[dir.length() + 1] == '\0') {
                    selectedFiles->SetString(0, ExtensionString(dir));
                } else {
                    // Multiple files are selected
                    wchar_t fullPath[MAX_PATH];
                    for (int i = (dir.length() + 1), fileIndex = 0; ; fileIndex++) {
                        // Get the next file name
                        std::wstring file(&szFile[i]);

                        // Two adjacent null characters signal the end of the files
                        if (file.length() == 0)
                            break;

                        // The filename is relative to the directory that was specified as
                        // the first string
                        if (PathCombine(fullPath, dir.c_str(), file.c_str()) != NULL)
                            selectedFiles->SetString(fileIndex, ExtensionString(fullPath));

                        // Go to the start of the next file name
                        i += file.length() + 1;
                    }
                }

            } else {
                // If multiple files are not allowed, add the single file
                selectedFiles->SetString(0, szFile);
            }
        }
    }

    return NO_ERROR;
}

int32 ReadDir(ExtensionString path, CefRefPtr<CefListValue>& directoryContents)
{
    FixFilename(path);

    path += L"\\*";

    WIN32_FIND_DATA ffd;
    HANDLE hFind = FindFirstFile(path.c_str(), &ffd);

    std::vector<ExtensionString> resultFiles;
    std::vector<ExtensionString> resultDirs;

    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            // Ignore '.' and '..'
            if (!wcscmp(ffd.cFileName, L".") || !wcscmp(ffd.cFileName, L".."))
                continue;

            // Collect file and directory names separately
            if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                resultDirs.push_back(ExtensionString(ffd.cFileName));
            } else {
                resultFiles.push_back(ExtensionString(ffd.cFileName));
            }
        }
        while (FindNextFile(hFind, &ffd) != 0);

        FindClose(hFind);
    }
    else {
        return ConvertWinErrorCode(GetLastError());
    }

    // On Windows, list directories first, then files
    size_t i, total = 0;
    for (i = 0; i < resultDirs.size(); i++)
        directoryContents->SetString(total++, resultDirs[i]);
    for (i = 0; i < resultFiles.size(); i++)
        directoryContents->SetString(total++, resultFiles[i]);

    return NO_ERROR;
}

int32 GetFileModificationTime(ExtensionString filename, uint32& modtime, bool& isDir)
{
    FixFilename(filename);

    DWORD dwAttr = GetFileAttributes(filename.c_str());

    if (dwAttr == INVALID_FILE_ATTRIBUTES) {
        return ConvertWinErrorCode(GetLastError());
    }

    isDir = ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0);

    struct _stat buffer;
    if(_wstat(filename.c_str(), &buffer) == -1) {
        return ConvertErrnoCode(errno);
    }

    modtime = buffer.st_mtime;

    return NO_ERROR;
}

int32 ReadFile(ExtensionString filename, ExtensionString encoding, std::string& contents)
{
    FixFilename(filename);

    if (encoding != L"utf8")
        return ERR_UNSUPPORTED_ENCODING;

    DWORD dwAttr;
    dwAttr = GetFileAttributes(filename.c_str());
    if (INVALID_FILE_ATTRIBUTES == dwAttr)
        return ConvertWinErrorCode(GetLastError());

    if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
        return ERR_CANT_READ;

    HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ,
        0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    int32 error = NO_ERROR;

    if (INVALID_HANDLE_VALUE == hFile)
        return ConvertWinErrorCode(GetLastError());

    DWORD dwFileSize = GetFileSize(hFile, NULL);
    DWORD dwBytesRead;
    char* buffer = (char*)malloc(dwFileSize);
    if (buffer && ReadFile(hFile, buffer, dwFileSize, &dwBytesRead, NULL)) {
        contents = std::string(buffer, dwFileSize);
    }
    else {
        if (!buffer)
            error = ERR_UNKNOWN;
        else
            error = ConvertWinErrorCode(GetLastError());
    }
    CloseHandle(hFile);
    if (buffer)
        free(buffer);

    return error;
}

int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding)
{
    FixFilename(filename);

    if (encoding != L"utf8")
        return ERR_UNSUPPORTED_ENCODING;

    HANDLE hFile = CreateFile(filename.c_str(), GENERIC_WRITE,
        0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD dwBytesWritten;
    int error = NO_ERROR;

    if (INVALID_HANDLE_VALUE == hFile)
        return ConvertWinErrorCode(GetLastError(), false);

    // TODO (issue 67) -  Should write to temp file and handle encoding
    if (!WriteFile(hFile, contents.c_str(), contents.length(), &dwBytesWritten, NULL)) {
        error = ConvertWinErrorCode(GetLastError(), false);
    }

    CloseHandle(hFile);
    return error;
}

int32 SetPosixPermissions(ExtensionString filename, int32 mode)
{
    FixFilename(filename);

    DWORD dwAttr = GetFileAttributes(filename.c_str());

    if (dwAttr == INVALID_FILE_ATTRIBUTES)
        return ERR_NOT_FOUND;

    if ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0)
        return NO_ERROR;

    bool write = (mode & 0200) != 0;
    bool read = (mode & 0400) != 0;
    int mask = (write ? _S_IWRITE : 0) | (read ? _S_IREAD : 0);

    if (_wchmod(filename.c_str(), mask) == -1) {
        return ConvertErrnoCode(errno);
    }

    return NO_ERROR;
}

int32 DeleteFileOrDirectory(ExtensionString filename)
{
    FixFilename(filename);

    if (!DeleteFile(filename.c_str()))
        return ConvertWinErrorCode(GetLastError());

    return NO_ERROR;
}

void FixFilename(ExtensionString& filename)
{
    // Convert '/' to '\'
    replace(filename.begin(), filename.end(), '/', '\\');
}

// Maps errors from errno.h to the brackets error codes
// found in brackets_extensions.js
int ConvertErrnoCode(int errorCode, bool isReading)
{
    switch (errorCode) {
    case NO_ERROR:
        return NO_ERROR;
    case EINVAL:
        return ERR_INVALID_PARAMS;
    case ENOENT:
        return ERR_NOT_FOUND;
    default:
        return ERR_UNKNOWN;
    }
}

// Maps errors from  WinError.h to the brackets error codes
// found in brackets_extensions.js
int ConvertWinErrorCode(int errorCode, bool isReading)
{
    switch (errorCode) {
    case NO_ERROR:
        return NO_ERROR;
    case ERROR_PATH_NOT_FOUND:
    case ERROR_FILE_NOT_FOUND:
        return ERR_NOT_FOUND;
    case ERROR_ACCESS_DENIED:
        return isReading ? ERR_CANT_READ : ERR_CANT_WRITE;
    case ERROR_WRITE_PROTECT:
        return ERR_CANT_WRITE;
    case ERROR_HANDLE_DISK_FULL:
        return ERR_OUT_OF_SPACE;
    default:
        return ERR_UNKNOWN;
    }
}

<|endoftext|>


<commit_before>// Fault handler information.  MacOSX version.
// Copyright (C) 1993-1999, 2002-2003  Bruno Haible <clisp.org at bruno>

// Copyright (C) 2003  Paolo Bonzini <gnu.org at bonzini>

// Used under BSD license with permission from Paolo Bonzini and Bruno Haible,
// 2005-03-10:

// http://sourceforge.net/mailarchive/message.php?msg_name=200503102200.32002.bruno%40clisp.org

// Modified for Factor by Slava Pestov

#include "master.hpp"

namespace factor {

// The exception port on which our thread listens.
mach_port_t our_exception_port;

// The following sources were used as a *reference* for this exception handling
// code:

// 1. Apple's mach/xnu documentation
// 2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
//    omnigroup's macosx-dev list.
//    http://www.wodeveloper.com/omniLists/macosx-dev/2000/June/msg00137.html

// Modify a suspended thread's thread_state so that when the thread resumes
// executing, the call frame of the current C primitive (if any) is rewound, and
// the appropriate Factor error is thrown from the top-most Factor frame.
void factor_vm::call_fault_handler(exception_type_t exception,
                                   exception_data_type_t code,
                                   MACH_EXC_STATE_TYPE* exc_state,
                                   MACH_THREAD_STATE_TYPE* thread_state,
                                   MACH_FLOAT_STATE_TYPE* float_state) {
  cell handler = 0;

  if (exception == EXC_BAD_ACCESS) {
    set_memory_protection_error(MACH_EXC_STATE_FAULT(exc_state),
                                (cell)MACH_PROGRAM_COUNTER(thread_state));
    handler = (cell)factor::memory_signal_handler_impl;
  } else if (exception == EXC_ARITHMETIC && code != MACH_EXC_INTEGER_DIV) {
    signal_fpu_status = fpu_status(mach_fpu_status(float_state));
    mach_clear_fpu_status(float_state);
    handler = (cell)factor::fp_signal_handler_impl;
  } else {
    switch (exception) {
      case EXC_ARITHMETIC:
        signal_number = SIGFPE;
        break;
      case EXC_BAD_INSTRUCTION:
        signal_number = SIGILL;
        break;
      default:
        signal_number = SIGABRT;
        break;
    }

    handler = (cell)factor::synchronous_signal_handler_impl;
  }

  FACTOR_ASSERT(handler != 0);

  dispatch_signal_handler((cell*)&MACH_STACK_POINTER(thread_state),
                          (cell*)&MACH_PROGRAM_COUNTER(thread_state),
                          (cell)handler);
}

static void call_fault_handler(mach_port_t thread, exception_type_t exception,
                               exception_data_type_t code,
                               MACH_EXC_STATE_TYPE* exc_state,
                               MACH_THREAD_STATE_TYPE* thread_state,
                               MACH_FLOAT_STATE_TYPE* float_state) {
  // Look up the VM instance involved
  THREADHANDLE thread_id = pthread_from_mach_thread_np(thread);
  FACTOR_ASSERT(thread_id);
  std::map<THREADHANDLE, factor_vm*>::const_iterator vm =
      thread_vms.find(thread_id);

  // Handle the exception
  if (vm != thread_vms.end())
    vm->second->call_fault_handler(exception, code, exc_state, thread_state,
                                   float_state);
}

// Handle an exception by invoking the user's fault handler and/or forwarding
// the duty to the previously installed handlers.
extern "C" kern_return_t catch_exception_raise(
    mach_port_t exception_port, mach_port_t thread, mach_port_t task,
    exception_type_t exception, exception_data_t code,
    mach_msg_type_number_t code_count) {
  // 10.6 likes to report exceptions from child processes too. Ignore those
  if (task != mach_task_self())
    return KERN_FAILURE;

  // Get fault information and the faulting thread's register contents..
  // See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_get_state.html.
  MACH_EXC_STATE_TYPE exc_state;
  mach_msg_type_number_t exc_state_count = MACH_EXC_STATE_COUNT;
  if (thread_get_state(thread, MACH_EXC_STATE_FLAVOR, (natural_t*)&exc_state,
                       &exc_state_count) !=
      KERN_SUCCESS) {
    // The thread is supposed to be suspended while the exception
    // handler is called. This shouldn't fail.
    return KERN_FAILURE;
  }

  MACH_THREAD_STATE_TYPE thread_state;
  mach_msg_type_number_t thread_state_count = MACH_THREAD_STATE_COUNT;
  if (thread_get_state(thread, MACH_THREAD_STATE_FLAVOR,
                       (natural_t*)&thread_state, &thread_state_count) !=
      KERN_SUCCESS) {
    // The thread is supposed to be suspended while the exception
    // handler is called. This shouldn't fail.
    return KERN_FAILURE;
  }

  MACH_FLOAT_STATE_TYPE float_state;
  mach_msg_type_number_t float_state_count = MACH_FLOAT_STATE_COUNT;
  if (thread_get_state(thread, MACH_FLOAT_STATE_FLAVOR,
                       (natural_t*)&float_state, &float_state_count) !=
      KERN_SUCCESS) {
    // The thread is supposed to be suspended while the exception
    // handler is called. This shouldn't fail.
    return KERN_FAILURE;
  }

  // Modify registers so to have the thread resume executing the
  // fault handler
  call_fault_handler(thread, exception, code[0], &exc_state, &thread_state,
                     &float_state);

  // Set the faulting thread's register contents..
  // See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_set_state.html.
  if (thread_set_state(thread, MACH_FLOAT_STATE_FLAVOR,
                       (natural_t*)&float_state, float_state_count) !=
      KERN_SUCCESS) {
    return KERN_FAILURE;
  }

  if (thread_set_state(thread, MACH_THREAD_STATE_FLAVOR,
                       (natural_t*)&thread_state, thread_state_count) !=
      KERN_SUCCESS) {
    return KERN_FAILURE;
  }

  return KERN_SUCCESS;
}

// The main function of the thread listening for exceptions.
static void* mach_exception_thread(void* arg) {
  for (;;) {
    // These two structures contain some private kernel data. We don't need
    // to access any of it so we don't bother defining a proper struct. The
    // correct definitions are in the xnu source code.
    // Buffer for a message to be received.
    struct {
      mach_msg_header_t head;
      mach_msg_body_t msgh_body;
      char data[1024];
    } msg;
    // Buffer for a reply message.
    struct {
      mach_msg_header_t head;
      char data[1024];
    } reply;

    // Wait for a message on the exception port.
    if (mach_msg(&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(msg),
                 our_exception_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL) !=
        MACH_MSG_SUCCESS) {
      abort();
    }

    // Handle the message: Call exc_server, which will call
    // catch_exception_raise and produce a reply message.
    exc_server(&msg.head, &reply.head);

    // Send the reply.
    if (mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0,
                 MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL) !=
        MACH_MSG_SUCCESS) {
      abort();
    }
  }
  return NULL;  // quiet warning
}

// Initialize the Mach exception handler thread.
void mach_initialize() {
  mach_port_t self;
  exception_mask_t mask;

  self = mach_task_self();

  // Allocate a port on which the thread shall listen for exceptions.
  if (mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, &our_exception_port) !=
      KERN_SUCCESS)
    fatal_error("mach_port_allocate() failed", 0);

  // See
  // http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_port_insert_right.html.

  if (mach_port_insert_right(self, our_exception_port, our_exception_port,
                             MACH_MSG_TYPE_MAKE_SEND) !=
      KERN_SUCCESS)
    fatal_error("mach_port_insert_right() failed", 0);

  // The exceptions we want to catch.
  mask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC;

  // Create the thread listening on the exception port.
  start_thread(mach_exception_thread, NULL);

  // Replace the exception port info for these exceptions with our own.
  // Note that we replace the exception port for the entire task, not only
  // for a particular thread. This has the effect that when our exception
  // port gets the message, the thread specific exception port has already
  // been asked, and we don't need to bother about it. See
  // http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_set_exception_ports.html.
  if (task_set_exception_ports(self, mask, our_exception_port,
                               EXCEPTION_DEFAULT, MACHINE_THREAD_STATE) !=
      KERN_SUCCESS)
    fatal_error("task_set_exception_ports() failed", 0);
}

}
<commit_msg>vm: Silence more unused parameters warnings.<commit_after>// Fault handler information.  MacOSX version.
// Copyright (C) 1993-1999, 2002-2003  Bruno Haible <clisp.org at bruno>

// Copyright (C) 2003  Paolo Bonzini <gnu.org at bonzini>

// Used under BSD license with permission from Paolo Bonzini and Bruno Haible,
// 2005-03-10:

// http://sourceforge.net/mailarchive/message.php?msg_name=200503102200.32002.bruno%40clisp.org

// Modified for Factor by Slava Pestov

#include "master.hpp"

namespace factor {

// The exception port on which our thread listens.
mach_port_t our_exception_port;

// The following sources were used as a *reference* for this exception handling
// code:

// 1. Apple's mach/xnu documentation
// 2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
//    omnigroup's macosx-dev list.
//    http://www.wodeveloper.com/omniLists/macosx-dev/2000/June/msg00137.html

// Modify a suspended thread's thread_state so that when the thread resumes
// executing, the call frame of the current C primitive (if any) is rewound, and
// the appropriate Factor error is thrown from the top-most Factor frame.
void factor_vm::call_fault_handler(exception_type_t exception,
                                   exception_data_type_t code,
                                   MACH_EXC_STATE_TYPE* exc_state,
                                   MACH_THREAD_STATE_TYPE* thread_state,
                                   MACH_FLOAT_STATE_TYPE* float_state) {
  cell handler = 0;

  if (exception == EXC_BAD_ACCESS) {
    set_memory_protection_error(MACH_EXC_STATE_FAULT(exc_state),
                                (cell)MACH_PROGRAM_COUNTER(thread_state));
    handler = (cell)factor::memory_signal_handler_impl;
  } else if (exception == EXC_ARITHMETIC && code != MACH_EXC_INTEGER_DIV) {
    signal_fpu_status = fpu_status(mach_fpu_status(float_state));
    mach_clear_fpu_status(float_state);
    handler = (cell)factor::fp_signal_handler_impl;
  } else {
    switch (exception) {
      case EXC_ARITHMETIC:
        signal_number = SIGFPE;
        break;
      case EXC_BAD_INSTRUCTION:
        signal_number = SIGILL;
        break;
      default:
        signal_number = SIGABRT;
        break;
    }

    handler = (cell)factor::synchronous_signal_handler_impl;
  }

  FACTOR_ASSERT(handler != 0);

  dispatch_signal_handler((cell*)&MACH_STACK_POINTER(thread_state),
                          (cell*)&MACH_PROGRAM_COUNTER(thread_state),
                          (cell)handler);
}

static void call_fault_handler(mach_port_t thread, exception_type_t exception,
                               exception_data_type_t code,
                               MACH_EXC_STATE_TYPE* exc_state,
                               MACH_THREAD_STATE_TYPE* thread_state,
                               MACH_FLOAT_STATE_TYPE* float_state) {
  // Look up the VM instance involved
  THREADHANDLE thread_id = pthread_from_mach_thread_np(thread);
  FACTOR_ASSERT(thread_id);
  std::map<THREADHANDLE, factor_vm*>::const_iterator vm =
      thread_vms.find(thread_id);

  // Handle the exception
  if (vm != thread_vms.end())
    vm->second->call_fault_handler(exception, code, exc_state, thread_state,
                                   float_state);
}

// Handle an exception by invoking the user's fault handler and/or forwarding
// the duty to the previously installed handlers.
extern "C" kern_return_t catch_exception_raise(
    mach_port_t exception_port, mach_port_t thread, mach_port_t task,
    exception_type_t exception, exception_data_t code,
    mach_msg_type_number_t code_count) {
  (void) exception_port;
  (void) code_count;
  // 10.6 likes to report exceptions from child processes too. Ignore those
  if (task != mach_task_self())
    return KERN_FAILURE;

  // Get fault information and the faulting thread's register contents..
  // See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_get_state.html.
  MACH_EXC_STATE_TYPE exc_state;
  mach_msg_type_number_t exc_state_count = MACH_EXC_STATE_COUNT;
  if (thread_get_state(thread, MACH_EXC_STATE_FLAVOR, (natural_t*)&exc_state,
                       &exc_state_count) !=
      KERN_SUCCESS) {
    // The thread is supposed to be suspended while the exception
    // handler is called. This shouldn't fail.
    return KERN_FAILURE;
  }

  MACH_THREAD_STATE_TYPE thread_state;
  mach_msg_type_number_t thread_state_count = MACH_THREAD_STATE_COUNT;
  if (thread_get_state(thread, MACH_THREAD_STATE_FLAVOR,
                       (natural_t*)&thread_state, &thread_state_count) !=
      KERN_SUCCESS) {
    // The thread is supposed to be suspended while the exception
    // handler is called. This shouldn't fail.
    return KERN_FAILURE;
  }

  MACH_FLOAT_STATE_TYPE float_state;
  mach_msg_type_number_t float_state_count = MACH_FLOAT_STATE_COUNT;
  if (thread_get_state(thread, MACH_FLOAT_STATE_FLAVOR,
                       (natural_t*)&float_state, &float_state_count) !=
      KERN_SUCCESS) {
    // The thread is supposed to be suspended while the exception
    // handler is called. This shouldn't fail.
    return KERN_FAILURE;
  }

  // Modify registers so to have the thread resume executing the
  // fault handler
  call_fault_handler(thread, exception, code[0], &exc_state, &thread_state,
                     &float_state);

  // Set the faulting thread's register contents..
  // See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_set_state.html.
  if (thread_set_state(thread, MACH_FLOAT_STATE_FLAVOR,
                       (natural_t*)&float_state, float_state_count) !=
      KERN_SUCCESS) {
    return KERN_FAILURE;
  }

  if (thread_set_state(thread, MACH_THREAD_STATE_FLAVOR,
                       (natural_t*)&thread_state, thread_state_count) !=
      KERN_SUCCESS) {
    return KERN_FAILURE;
  }

  return KERN_SUCCESS;
}

// The main function of the thread listening for exceptions.
static void* mach_exception_thread(void* arg) {
  (void) arg;
  for (;;) {
    // These two structures contain some private kernel data. We don't need
    // to access any of it so we don't bother defining a proper struct. The
    // correct definitions are in the xnu source code.
    // Buffer for a message to be received.
    struct {
      mach_msg_header_t head;
      mach_msg_body_t msgh_body;
      char data[1024];
    } msg;
    // Buffer for a reply message.
    struct {
      mach_msg_header_t head;
      char data[1024];
    } reply;

    // Wait for a message on the exception port.
    if (mach_msg(&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(msg),
                 our_exception_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL) !=
        MACH_MSG_SUCCESS) {
      abort();
    }

    // Handle the message: Call exc_server, which will call
    // catch_exception_raise and produce a reply message.
    exc_server(&msg.head, &reply.head);

    // Send the reply.
    if (mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0,
                 MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL) !=
        MACH_MSG_SUCCESS) {
      abort();
    }
  }
  return NULL;  // quiet warning
}

// Initialize the Mach exception handler thread.
void mach_initialize() {
  mach_port_t self;
  exception_mask_t mask;

  self = mach_task_self();

  // Allocate a port on which the thread shall listen for exceptions.
  if (mach_port_allocate(self, MACH_PORT_RIGHT_RECEIVE, &our_exception_port) !=
      KERN_SUCCESS)
    fatal_error("mach_port_allocate() failed", 0);

  // See
  // http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_port_insert_right.html.

  if (mach_port_insert_right(self, our_exception_port, our_exception_port,
                             MACH_MSG_TYPE_MAKE_SEND) !=
      KERN_SUCCESS)
    fatal_error("mach_port_insert_right() failed", 0);

  // The exceptions we want to catch.
  mask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC;

  // Create the thread listening on the exception port.
  start_thread(mach_exception_thread, NULL);

  // Replace the exception port info for these exceptions with our own.
  // Note that we replace the exception port for the entire task, not only
  // for a particular thread. This has the effect that when our exception
  // port gets the message, the thread specific exception port has already
  // been asked, and we don't need to bother about it. See
  // http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_set_exception_ports.html.
  if (task_set_exception_ports(self, mask, our_exception_port,
                               EXCEPTION_DEFAULT, MACHINE_THREAD_STATE) !=
      KERN_SUCCESS)
    fatal_error("task_set_exception_ports() failed", 0);
}

}
<|endoftext|>


<commit_before><commit_msg>allow for dots in numbers<commit_after><|endoftext|>