<commit_before>/**
 * \file
 * \brief MessageQueueBase class header
 *
 * \author Copyright (C) 2015-2017 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_MESSAGEQUEUEBASE_HPP_
#define INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_MESSAGEQUEUEBASE_HPP_

#include "distortos/Semaphore.hpp"

#include "distortos/internal/synchronization/QueueFunctor.hpp"
#include "distortos/internal/synchronization/SemaphoreFunctor.hpp"

#include "estd/SortedIntrusiveForwardList.hpp"

#include <memory>

namespace distortos
{

namespace internal
{

/// MessageQueueBase class implements basic functionality of MessageQueue template class
class MessageQueueBase
{
public:

	/// entry in the MessageQueueBase
	struct Entry
	{
		/**
		 * \brief Entry's constructor
		 *
		 * \param [in] priorityy is the priority of the entry
		 * \param [in] storagee is the storage for the entry
		 */

		constexpr Entry(const uint8_t priorityy, void* const storagee) :
				node{},
				priority{priorityy},
				storage{storagee}
		{

		}

		/// node for intrusive forward list
		estd::IntrusiveForwardListNode node;

		/// priority of the entry
		uint8_t priority;

		/// storage for the entry
		void* storage;
	};

	/// type of uninitialized storage for Entry
	using EntryStorage = typename std::aligned_storage<sizeof(Entry), alignof(Entry)>::type;

	/// unique_ptr (with deleter) to EntryStorage[]
	using EntryStorageUniquePointer = std::unique_ptr<EntryStorage[], void(&)(EntryStorage*)>;

	/**
	 * type of uninitialized storage for value
	 *
	 * \tparam T is the type of data in queue
	 */

	template<typename T>
	using ValueStorage = typename std::aligned_storage<sizeof(T), alignof(T)>::type;

	/// unique_ptr (with deleter) to storage
	using ValueStorageUniquePointer = std::unique_ptr<void, void(&)(void*)>;

	/// functor which gives descending priority order of elements on the list
	struct DescendingPriority
	{
		/**
		 * \brief DescendingPriority's constructor
		 */

		constexpr DescendingPriority()
		{

		}

		/**
		 * \brief DescendingPriority's function call operator
		 *
		 * \param [in] left is the object on the left side of comparison
		 * \param [in] right is the object on the right side of comparison
		 *
		 * \return true if left's priority is less than right's priority
		 */

		bool operator()(const Entry& left, const Entry& right) const
		{
			return left.priority < right.priority;
		}
	};

	/// type of entry list
	using EntryList = estd::SortedIntrusiveForwardList<DescendingPriority, Entry, &Entry::node>;

	/// type of free entry list
	using FreeEntryList = EntryList::UnsortedIntrusiveForwardList;

	/**
	 * \brief InternalFunctor is a type-erased interface for functors which execute common code of pop() and push()
	 * operations.
	 *
	 * The functor will be called by MessageQueueBase internals with references to \a entryList_ and \a freeEntryList_.
	 * It should perform common actions and execute the QueueFunctor passed from callers.
	 */

	class InternalFunctor : public estd::TypeErasedFunctor<void(EntryList&, FreeEntryList&)>
	{

	};

	/**
	 * \brief MessageQueueBase's constructor
	 *
	 * \param [in] entryStorageUniquePointer is a rvalue reference to EntryStorageUniquePointer with storage for queue
	 * entries (sufficiently large for \a maxElements EntryStorage objects) and appropriate deleter
	 * \param [in] valueStorageUniquePointer is a rvalue reference to ValueStorageUniquePointer with storage for queue
	 * elements (sufficiently large for \a maxElements, each \a elementSize bytes long) and appropriate deleter
	 * \param [in] elementSize is the size of single queue element, bytes
	 * \param [in] maxElements is the number of elements in \a entryStorage array and valueStorage memory block
	 */

	MessageQueueBase(EntryStorageUniquePointer&& entryStorageUniquePointer,
			ValueStorageUniquePointer&& valueStorageUniquePointer, size_t elementSize, size_t maxElements);

	/**
	 * \brief MessageQueueBase's destructor
	 */

	~MessageQueueBase();

	/**
	 * \brief Implementation of pop() using type-erased functor
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a popSemaphore_
	 * \param [out] priority is a reference to variable that will be used to return priority of popped value
	 * \param [in] functor is a reference to QueueFunctor which will execute actions related to popping - it will get a
	 * pointer to storage with element
	 *
	 * \return 0 if element was popped successfully, error code otherwise:
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int pop(const SemaphoreFunctor& waitSemaphoreFunctor, uint8_t& priority, const QueueFunctor& functor);

	/**
	 * \brief Implementation of push() using type-erased functor
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a pushSemaphore_
	 * \param [in] priority is the priority of new element
	 * \param [in] functor is a reference to QueueFunctor which will execute actions related to pushing - it will get a
	 * pointer to storage for element
	 *
	 * \return 0 if element was pushed successfully, error code otherwise:
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int push(const SemaphoreFunctor& waitSemaphoreFunctor, uint8_t priority, const QueueFunctor& functor);

private:

	/**
	 * \brief Implementation of pop() and push() using type-erased internal functor
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a waitSemaphore
	 * \param [in] internalFunctor is a reference to InternalFunctor which will execute actions related to
	 * popping/pushing
	 * \param [in] waitSemaphore is a reference to semaphore that will be waited for, \a popSemaphore_ for pop(), \a
	 * pushSemaphore_ for push()
	 * \param [in] postSemaphore is a reference to semaphore that will be posted after the operation, \a pushSemaphore_
	 * for pop(), \a popSemaphore_ for push()
	 *
	 * \return 0 if operation was successful, error code otherwise:
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int popPush(const SemaphoreFunctor& waitSemaphoreFunctor, const InternalFunctor& internalFunctor,
			Semaphore& waitSemaphore, Semaphore& postSemaphore);

	/// semaphore guarding access to "pop" functions - its value is equal to the number of available elements
	Semaphore popSemaphore_;

	/// semaphore guarding access to "push" functions - its value is equal to the number of free slots
	Semaphore pushSemaphore_;

	/// storage for queue entries
	const EntryStorageUniquePointer entryStorageUniquePointer_;

	/// storage for queue elements
	const ValueStorageUniquePointer valueStorageUniquePointer_;

	/// list of available entries, sorted in descending order of priority
	EntryList entryList_;

	/// list of "free" entries
	FreeEntryList freeEntryList_;
};

}	// namespace internal

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_MESSAGEQUEUEBASE_HPP_
<commit_msg>Add MessageQueueBase::getCapacity()<commit_after>/**
 * \file
 * \brief MessageQueueBase class header
 *
 * \author Copyright (C) 2015-2019 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_MESSAGEQUEUEBASE_HPP_
#define INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_MESSAGEQUEUEBASE_HPP_

#include "distortos/Semaphore.hpp"

#include "distortos/internal/synchronization/QueueFunctor.hpp"
#include "distortos/internal/synchronization/SemaphoreFunctor.hpp"

#include "estd/SortedIntrusiveForwardList.hpp"

#include <memory>

namespace distortos
{

namespace internal
{

/// MessageQueueBase class implements basic functionality of MessageQueue template class
class MessageQueueBase
{
public:

	/// entry in the MessageQueueBase
	struct Entry
	{
		/**
		 * \brief Entry's constructor
		 *
		 * \param [in] priorityy is the priority of the entry
		 * \param [in] storagee is the storage for the entry
		 */

		constexpr Entry(const uint8_t priorityy, void* const storagee) :
				node{},
				priority{priorityy},
				storage{storagee}
		{

		}

		/// node for intrusive forward list
		estd::IntrusiveForwardListNode node;

		/// priority of the entry
		uint8_t priority;

		/// storage for the entry
		void* storage;
	};

	/// type of uninitialized storage for Entry
	using EntryStorage = typename std::aligned_storage<sizeof(Entry), alignof(Entry)>::type;

	/// unique_ptr (with deleter) to EntryStorage[]
	using EntryStorageUniquePointer = std::unique_ptr<EntryStorage[], void(&)(EntryStorage*)>;

	/**
	 * type of uninitialized storage for value
	 *
	 * \tparam T is the type of data in queue
	 */

	template<typename T>
	using ValueStorage = typename std::aligned_storage<sizeof(T), alignof(T)>::type;

	/// unique_ptr (with deleter) to storage
	using ValueStorageUniquePointer = std::unique_ptr<void, void(&)(void*)>;

	/// functor which gives descending priority order of elements on the list
	struct DescendingPriority
	{
		/**
		 * \brief DescendingPriority's constructor
		 */

		constexpr DescendingPriority()
		{

		}

		/**
		 * \brief DescendingPriority's function call operator
		 *
		 * \param [in] left is the object on the left side of comparison
		 * \param [in] right is the object on the right side of comparison
		 *
		 * \return true if left's priority is less than right's priority
		 */

		bool operator()(const Entry& left, const Entry& right) const
		{
			return left.priority < right.priority;
		}
	};

	/// type of entry list
	using EntryList = estd::SortedIntrusiveForwardList<DescendingPriority, Entry, &Entry::node>;

	/// type of free entry list
	using FreeEntryList = EntryList::UnsortedIntrusiveForwardList;

	/**
	 * \brief InternalFunctor is a type-erased interface for functors which execute common code of pop() and push()
	 * operations.
	 *
	 * The functor will be called by MessageQueueBase internals with references to \a entryList_ and \a freeEntryList_.
	 * It should perform common actions and execute the QueueFunctor passed from callers.
	 */

	class InternalFunctor : public estd::TypeErasedFunctor<void(EntryList&, FreeEntryList&)>
	{

	};

	/**
	 * \brief MessageQueueBase's constructor
	 *
	 * \param [in] entryStorageUniquePointer is a rvalue reference to EntryStorageUniquePointer with storage for queue
	 * entries (sufficiently large for \a maxElements EntryStorage objects) and appropriate deleter
	 * \param [in] valueStorageUniquePointer is a rvalue reference to ValueStorageUniquePointer with storage for queue
	 * elements (sufficiently large for \a maxElements, each \a elementSize bytes long) and appropriate deleter
	 * \param [in] elementSize is the size of single queue element, bytes
	 * \param [in] maxElements is the number of elements in \a entryStorage array and valueStorage memory block
	 */

	MessageQueueBase(EntryStorageUniquePointer&& entryStorageUniquePointer,
			ValueStorageUniquePointer&& valueStorageUniquePointer, size_t elementSize, size_t maxElements);

	/**
	 * \brief MessageQueueBase's destructor
	 */

	~MessageQueueBase();

	/**
	 * \return maximum number of elements in queue
	 */

	size_t getCapacity() const
	{
		return popSemaphore_.getMaxValue();
	}

	/**
	 * \brief Implementation of pop() using type-erased functor
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a popSemaphore_
	 * \param [out] priority is a reference to variable that will be used to return priority of popped value
	 * \param [in] functor is a reference to QueueFunctor which will execute actions related to popping - it will get a
	 * pointer to storage with element
	 *
	 * \return 0 if element was popped successfully, error code otherwise:
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int pop(const SemaphoreFunctor& waitSemaphoreFunctor, uint8_t& priority, const QueueFunctor& functor);

	/**
	 * \brief Implementation of push() using type-erased functor
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a pushSemaphore_
	 * \param [in] priority is the priority of new element
	 * \param [in] functor is a reference to QueueFunctor which will execute actions related to pushing - it will get a
	 * pointer to storage for element
	 *
	 * \return 0 if element was pushed successfully, error code otherwise:
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int push(const SemaphoreFunctor& waitSemaphoreFunctor, uint8_t priority, const QueueFunctor& functor);

private:

	/**
	 * \brief Implementation of pop() and push() using type-erased internal functor
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a waitSemaphore
	 * \param [in] internalFunctor is a reference to InternalFunctor which will execute actions related to
	 * popping/pushing
	 * \param [in] waitSemaphore is a reference to semaphore that will be waited for, \a popSemaphore_ for pop(), \a
	 * pushSemaphore_ for push()
	 * \param [in] postSemaphore is a reference to semaphore that will be posted after the operation, \a pushSemaphore_
	 * for pop(), \a popSemaphore_ for push()
	 *
	 * \return 0 if operation was successful, error code otherwise:
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int popPush(const SemaphoreFunctor& waitSemaphoreFunctor, const InternalFunctor& internalFunctor,
			Semaphore& waitSemaphore, Semaphore& postSemaphore);

	/// semaphore guarding access to "pop" functions - its value is equal to the number of available elements
	Semaphore popSemaphore_;

	/// semaphore guarding access to "push" functions - its value is equal to the number of free slots
	Semaphore pushSemaphore_;

	/// storage for queue entries
	const EntryStorageUniquePointer entryStorageUniquePointer_;

	/// storage for queue elements
	const ValueStorageUniquePointer valueStorageUniquePointer_;

	/// list of available entries, sorted in descending order of priority
	EntryList entryList_;

	/// list of "free" entries
	FreeEntryList freeEntryList_;
};

}	// namespace internal

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_INTERNAL_SYNCHRONIZATION_MESSAGEQUEUEBASE_HPP_
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <test/models/model_test_fixture.hpp>

class Models_BugsExamples_Vol1_Bones :
  public Model_Test_Fixture<Models_BugsExamples_Vol1_Bones> {
protected:
  virtual void SetUp() {
  }
public:
  static std::vector<std::string> get_model_path() {
    std::vector<std::string> model_path;
    model_path.push_back("models");
    model_path.push_back("bugs_examples");
    model_path.push_back("vol1");
    model_path.push_back("bones");
    model_path.push_back("bones");
    return model_path;
  }
  static bool has_data() {
    return true;
  }

  static std::vector<std::pair<size_t, double> >
  get_expected_values() {
    std::vector<std::pair<size_t, double> > expected_values;
    return expected_values;
  }

};

INSTANTIATE_TYPED_TEST_CASE_P(Models_BugsExamples_Vol1_Bones,
			      Model_Test_Fixture,
			      Models_BugsExamples_Vol1_Bones);
<commit_msg>test/models/bugs_examples/vol1/bones/bones_test: added reference values for the parameters<commit_after>#include <gtest/gtest.h>
#include <test/models/model_test_fixture.hpp>

class Models_BugsExamples_Vol1_Bones :
  public Model_Test_Fixture<Models_BugsExamples_Vol1_Bones> {
protected:
  virtual void SetUp() {
  }
public:
  static std::vector<std::string> get_model_path() {
    std::vector<std::string> model_path;
    model_path.push_back("models");
    model_path.push_back("bugs_examples");
    model_path.push_back("vol1");
    model_path.push_back("bones");
    model_path.push_back("bones");
    return model_path;
  }
  static bool has_data() {
    return true;
  }

  static std::vector<std::pair<size_t, double> >
  get_expected_values() {
    using std::make_pair;

    std::vector<std::pair<size_t, double> > expected_values;
    expected_values.push_back(make_pair( 0U, 0.3244));
    expected_values.push_back(make_pair( 1U, 1.366));
    expected_values.push_back(make_pair( 2U, 2.357));
    expected_values.push_back(make_pair( 3U, 2.902));
    expected_values.push_back(make_pair( 4U, 5.535));
    expected_values.push_back(make_pair( 5U, 6.751));
    expected_values.push_back(make_pair( 6U, 6.451));
    expected_values.push_back(make_pair( 7U, 8.93));
    expected_values.push_back(make_pair( 8U, 8.981));
    expected_values.push_back(make_pair( 9U, 11.94));
    expected_values.push_back(make_pair(10U, 11.58));
    expected_values.push_back(make_pair(11U, 15.79));
    expected_values.push_back(make_pair(12U, 16.96));

    return expected_values;
  }

};

INSTANTIATE_TYPED_TEST_CASE_P(Models_BugsExamples_Vol1_Bones,
			      Model_Test_Fixture,
			      Models_BugsExamples_Vol1_Bones);
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.2  2000/03/22 00:58:11  rahulj
 * Now we throw exceptions when errors occur.
 * Simplified code based on assumption that calling
 * function will allocate enough storage to store the
 * incoming data.
 *
 * Revision 1.1  2000/03/20 23:48:51  rahulj
 * Added Socket based NetAccessor. This will enable one to
 * use HTTP URL's for system id's. Default build options do
 * not use this NetAccessor. Specify the '-n socket' option
 * to 'runConfigure' to configure Xerces-C to use this new
 * feature. The code works under Solaris 2.6, Linux, AIX
 * and HPUX 11 with aCC.
 * Todo's: enable proper error handling.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <memory.h>

#include <iostream.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>

#include <util/XMLNetAccessor.hpp>
#include <util/NetAccessors/Socket/UnixHTTPURLInputStream.hpp>
#include <util/XMLString.hpp>
#include <util/XMLExceptMsgs.hpp>
#include <util/Janitor.hpp>

//
// This define specifies the size of the buffer used to read chunks
// out of the URL input stream.
//

#define URLISBUFMAXSIZE        8192

//
// URL's, as per the standards, is essentially composed of just ASCII characters
// and hence converting it to a 'char *' requires just to drop the leading zero
// byte. However, the URL's have to be 'escaped', meaning that certain unsafe
// and reserved characters have to be escaped to their corresponding hex values.
//
// The input Unicode string is assumed to be 0 terminated.
// The caller is responsible to free the memory allocated to store the resultant
// 'char *' string.
//

static char* localTranscode(const XMLCh* latinStrInUnicode)
{
    unsigned int   lent = XMLString::stringLen(latinStrInUnicode);
    char*  retval = new char[lent + 1];
    unsigned int  i = 0;
    for (i = 0; i < lent; i++)
        retval[i] = (char) latinStrInUnicode[i]; // drop the leading byte.
    retval[lent] = 0;
    return retval;
}

UnixHTTPURLInputStream::UnixHTTPURLInputStream(const XMLURL& urlSource)
      : fSocket(0)
      , fBytesProcessed(0)
{
    const XMLCh*        uri = urlSource.getURLText();
    char*               uriAsCharStar = localTranscode(uri);
    ArrayJanitor<char>  janBuf(uriAsCharStar);
    const XMLCh*        hostName = urlSource.getHost();
    char*               hostNameAsCharStar = localTranscode(hostName);
    ArrayJanitor<char>  janBuf1(hostNameAsCharStar);
    struct hostent*     hostEntPtr = 0;
    struct sockaddr_in  sa;
    char                obuf[1024];  // URL's should be < 1018 bytes.

    if ((hostEntPtr = gethostbyname(hostNameAsCharStar)) == NULL)
    {
        unsigned long  numAddress = inet_addr(hostNameAsCharStar);
        if (numAddress < 0)
        {
            ThrowXML(NetAccessorException,
                     XMLExcepts::NetAcc_TargetResolution);
        }
        if ((hostEntPtr =
                gethostbyaddr((const char *) &numAddress,
                              sizeof(unsigned long), AF_INET)) == NULL)
        {
            ThrowXML(NetAccessorException,
                     XMLExcepts::NetAcc_TargetResolution);
        }
    }

    memcpy((void *) &sa.sin_addr,
           (const void *) hostEntPtr->h_addr, hostEntPtr->h_length);
    sa.sin_family = hostEntPtr->h_addrtype;
    sa.sin_port = htons(80);

    int s = socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0);
    if (s < 0)
    {
        ThrowXML(NetAccessorException,
                 XMLExcepts::NetAcc_CreateSocket);
    }

    if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
    {
        ThrowXML(NetAccessorException,
                 XMLExcepts::NetAcc_ConnSocket);
    }

    // Now you can simply read and write from/to the socket.

    sprintf(obuf, "GET %s\n\n", uriAsCharStar);
    int lent = strlen(obuf);
    int  aLent = 0;
    if ((aLent = write(s, (void *) obuf, lent)) != lent)
    {
        ThrowXML(NetAccessorException,
                 XMLExcepts::NetAcc_WriteSocket);
    }

    fSocket = s;

}

UnixHTTPURLInputStream::~UnixHTTPURLInputStream()
{
    shutdown(fSocket, 2);
    close(fSocket);
}

unsigned int UnixHTTPURLInputStream::readBytes(XMLByte* const    toFill
                                      , const unsigned int    maxToRead)
{
    unsigned int  retval = 0;

    int lent = read(fSocket, (void *) toFill, maxToRead);

    if (lent < 0)
    {
        ThrowXML(NetAccessorException, XMLExcepts::NetAcc_ReadSocket);
    }
    else
    {
        retval = lent;
        fBytesProcessed += retval;
    }

    return retval;
}
<commit_msg>Connect to the port specified in the URL, rather than the default one.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.3  2000/03/24 01:30:32  rahulj
 * Connect to the port specified in the URL, rather than the default
 * one.
 *
 * Revision 1.2  2000/03/22 00:58:11  rahulj
 * Now we throw exceptions when errors occur.
 * Simplified code based on assumption that calling
 * function will allocate enough storage to store the
 * incoming data.
 *
 * Revision 1.1  2000/03/20 23:48:51  rahulj
 * Added Socket based NetAccessor. This will enable one to
 * use HTTP URL's for system id's. Default build options do
 * not use this NetAccessor. Specify the '-n socket' option
 * to 'runConfigure' to configure Xerces-C to use this new
 * feature. The code works under Solaris 2.6, Linux, AIX
 * and HPUX 11 with aCC.
 * Todo's: enable proper error handling.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <memory.h>

#include <iostream.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>

#include <util/XMLNetAccessor.hpp>
#include <util/NetAccessors/Socket/UnixHTTPURLInputStream.hpp>
#include <util/XMLString.hpp>
#include <util/XMLExceptMsgs.hpp>
#include <util/Janitor.hpp>

//
// This define specifies the size of the buffer used to read chunks
// out of the URL input stream.
//

#define URLISBUFMAXSIZE        8192

//
// URL's, as per the standards, is essentially composed of just ASCII characters
// and hence converting it to a 'char *' requires just to drop the leading zero
// byte. However, the URL's have to be 'escaped', meaning that certain unsafe
// and reserved characters have to be escaped to their corresponding hex values.
//
// The input Unicode string is assumed to be 0 terminated.
// The caller is responsible to free the memory allocated to store the resultant
// 'char *' string.
//

static char* localTranscode(const XMLCh* latinStrInUnicode)
{
    unsigned int   lent = XMLString::stringLen(latinStrInUnicode);
    char*  retval = new char[lent + 1];
    unsigned int  i = 0;
    for (i = 0; i < lent; i++)
        retval[i] = (char) latinStrInUnicode[i]; // drop the leading byte.
    retval[lent] = 0;
    return retval;
}

UnixHTTPURLInputStream::UnixHTTPURLInputStream(const XMLURL& urlSource)
      : fSocket(0)
      , fBytesProcessed(0)
{
    const XMLCh*        uri = urlSource.getURLText();
    char*               uriAsCharStar = localTranscode(uri);
    ArrayJanitor<char>  janBuf(uriAsCharStar);
    const XMLCh*        hostName = urlSource.getHost();
    char*               hostNameAsCharStar = localTranscode(hostName);
    ArrayJanitor<char>  janBuf1(hostNameAsCharStar);
    unsigned short      portNumber = (unsigned short) urlSource.getPortNum();
    struct hostent*     hostEntPtr = 0;
    struct sockaddr_in  sa;
    char                obuf[1024];  // URL's should be < 1018 bytes.

    if ((hostEntPtr = gethostbyname(hostNameAsCharStar)) == NULL)
    {
        unsigned long  numAddress = inet_addr(hostNameAsCharStar);
        if (numAddress < 0)
        {
            ThrowXML(NetAccessorException,
                     XMLExcepts::NetAcc_TargetResolution);
        }
        if ((hostEntPtr =
                gethostbyaddr((const char *) &numAddress,
                              sizeof(unsigned long), AF_INET)) == NULL)
        {
            ThrowXML(NetAccessorException,
                     XMLExcepts::NetAcc_TargetResolution);
        }
    }

    memcpy((void *) &sa.sin_addr,
           (const void *) hostEntPtr->h_addr, hostEntPtr->h_length);
    sa.sin_family = hostEntPtr->h_addrtype;
    sa.sin_port = htons(portNumber);

    int s = socket(hostEntPtr->h_addrtype, SOCK_STREAM, 0);
    if (s < 0)
    {
        ThrowXML(NetAccessorException,
                 XMLExcepts::NetAcc_CreateSocket);
    }

    if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
    {
        ThrowXML(NetAccessorException,
                 XMLExcepts::NetAcc_ConnSocket);
    }

    // Now you can simply read and write from/to the socket.

    sprintf(obuf, "GET %s\n\n", uriAsCharStar);
    int lent = strlen(obuf);
    int  aLent = 0;
    if ((aLent = write(s, (void *) obuf, lent)) != lent)
    {
        ThrowXML(NetAccessorException,
                 XMLExcepts::NetAcc_WriteSocket);
    }

    fSocket = s;

}

UnixHTTPURLInputStream::~UnixHTTPURLInputStream()
{
    shutdown(fSocket, 2);
    close(fSocket);
}

unsigned int UnixHTTPURLInputStream::readBytes(XMLByte* const    toFill
                                      , const unsigned int    maxToRead)
{
    unsigned int  retval = 0;

    int lent = read(fSocket, (void *) toFill, maxToRead);

    if (lent < 0)
    {
        ThrowXML(NetAccessorException, XMLExcepts::NetAcc_ReadSocket);
    }
    else
    {
        retval = lent;
        fBytesProcessed += retval;
    }

    return retval;
}
<|endoftext|>


<commit_before>//
// Created by Axel Naumann on 09/12/15.
//

//#include "cling/Interpreter/Jupyter/Kernel.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"

#include <map>
#include <string>

namespace cling {
  namespace Jupyter {
    struct MIMEDataRef {
      const char* m_Data;
      const long m_Size;

      MIMEDataRef(const std::string& str):
      m_Data(str.c_str()), m_Size((long)str.length() + 1) {}
      MIMEDataRef(const char* str):
      MIMEDataRef(std::string(str)) {}
      MIMEDataRef(const char* data, long size):
      m_Data(data), m_Size(size) {}
    };

    /// Push MIME stuff to Jupyter. To be called from user code.
    ///\param contentDict - dictionary of MIME type versus content. E.g.
    /// {{"text/html", {"

", }}
    void pushOutput(const std::map<std::string, MIMEDataRef> contentDict) {
      FILE* outpipe = popen("???", "w");

      // Pipe sees (all numbers are longs, except for the first:
      // - num bytes in a long (sent as a single unsigned char!)
      // - num elements of the MIME dictionary; Jupyter selects one to display.
      // For each MIME dictionary element:
      //   - MIME type as 0-terminated string
      //   - size of MIME data buffer (including the terminating 0 for
      //     0-terminated strings)
      //   - MIME data buffer

      // Write number of dictionary elements (and the size of that number in a
      // char)
      unsigned char sizeLong = sizeof(long);
      fwrite(&sizeLong, 1, 1, outpipe);
      long dictSize = contentDict.size();
      fwrite(&dictSize, sizeof(long), 1, outpipe);

      for (auto iContent: contentDict) {
        const std::string& mimeType = iContent.first;
        fwrite(mimeType.c_str(), mimeType.size() + 1, 1, outpipe);
        const MIMEDataRef& mimeData = iContent.second;
        fwrite(&mimeData.m_Size, sizeof(long), 1, outpipe);
        fwrite(mimeData.m_Data, mimeData.m_Size, 1, outpipe);
      }

      pclose(outpipe);
    }
  } // namespace Jupyter
} // namespace cling

extern "C" {
///\{
///\name Cling4CTypes
/// The Python compatible view of cling

/// The Interpreter object cast to void*
using TheInterpreter = void ;

/// Create an interpreter object.
TheInterpreter*
cling_create(int argc, const char *argv[], const char* llvmdir) {
  auto interp = new cling::Interpreter(argc, argv, llvmdir);
  return interp;
}

/// Destroy the interpreter.
void cling_destroy(TheInterpreter *interpVP) {
  cling::Interpreter *interp = (cling::Interpreter *) interpVP;
  delete interp;
}

/// Evaluate a string of code. Returns 0 on success.
int cling_eval(TheInterpreter *interpVP, const char *code) {
  cling::Interpreter *interp = (cling::Interpreter *) interpVP;
  //cling::Value V;
  cling::Interpreter::CompilationResult Res = interp->process(code /*, V*/);
  if (Res != cling::Interpreter::kSuccess)
    return 1;
  cling::Jupyter::pushOutput({{"text/html", "You just executed C++ code!"}});
  return 0;
}

///\}

} // extern "C"
<commit_msg>Code completion interfaces (though no real implementation yet).<commit_after>//
// Created by Axel Naumann on 09/12/15.
//

//#include "cling/Interpreter/Jupyter/Kernel.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Value.h"

#include <map>
#include <string>

namespace cling {
  namespace Jupyter {
    struct MIMEDataRef {
      const char* m_Data;
      const long m_Size;

      MIMEDataRef(const std::string& str):
      m_Data(str.c_str()), m_Size((long)str.length() + 1) {}
      MIMEDataRef(const char* str):
      MIMEDataRef(std::string(str)) {}
      MIMEDataRef(const char* data, long size):
      m_Data(data), m_Size(size) {}
    };

    /// Push MIME stuff to Jupyter. To be called from user code.
    ///\param contentDict - dictionary of MIME type versus content. E.g.
    /// {{"text/html", {"

", }}
    void pushOutput(const std::map<std::string, MIMEDataRef> contentDict) {
      FILE* outpipe = popen("???", "w");

      // Pipe sees (all numbers are longs, except for the first:
      // - num bytes in a long (sent as a single unsigned char!)
      // - num elements of the MIME dictionary; Jupyter selects one to display.
      // For each MIME dictionary element:
      //   - MIME type as 0-terminated string
      //   - size of MIME data buffer (including the terminating 0 for
      //     0-terminated strings)
      //   - MIME data buffer

      // Write number of dictionary elements (and the size of that number in a
      // char)
      unsigned char sizeLong = sizeof(long);
      fwrite(&sizeLong, 1, 1, outpipe);
      long dictSize = contentDict.size();
      fwrite(&dictSize, sizeof(long), 1, outpipe);

      for (auto iContent: contentDict) {
        const std::string& mimeType = iContent.first;
        fwrite(mimeType.c_str(), mimeType.size() + 1, 1, outpipe);
        const MIMEDataRef& mimeData = iContent.second;
        fwrite(&mimeData.m_Size, sizeof(long), 1, outpipe);
        fwrite(mimeData.m_Data, mimeData.m_Size, 1, outpipe);
      }

      pclose(outpipe);
    }
  } // namespace Jupyter
} // namespace cling

extern "C" {
///\{
///\name Cling4CTypes
/// The Python compatible view of cling

/// The Interpreter object cast to void*
using TheInterpreter = void ;

/// Create an interpreter object.
TheInterpreter*
cling_create(int argc, const char *argv[], const char* llvmdir) {
  auto interp = new cling::Interpreter(argc, argv, llvmdir);
  return interp;
}

/// Destroy the interpreter.
void cling_destroy(TheInterpreter *interpVP) {
  cling::Interpreter *interp = (cling::Interpreter *) interpVP;
  delete interp;
}

/// Evaluate a string of code. Returns 0 on success.
int cling_eval(TheInterpreter *interpVP, const char *code) {
  cling::Interpreter *interp = (cling::Interpreter *) interpVP;
  //cling::Value V;
  cling::Interpreter::CompilationResult Res = interp->process(code /*, V*/);
  if (Res != cling::Interpreter::kSuccess)
    return 1;
  cling::Jupyter::pushOutput({{"text/html", "You just executed C++ code!"}});
  return 0;
}

/// Code completion interfaces.

/// Start completion of code. Returns a handle to be passed to
/// cling_complete_next() to iterate over the completion options. Returns nulptr
/// if no completions are known.
void* cling_complete_start(const char* code) {
  return new int(42);
}

/// Grab the next completion of some code. Returns nullptr if none is left.
const char* cling_complete_next(void* completionHandle) {
  int* counter = *(int*) completionHandle;
  if (++(*counter) > 43) {
    delete counter;
    return nullptr;
  }
  return "COMPLETE!";
}

///\}

} // extern "C"
<|endoftext|>


<commit_before>#include <iostream>

#include "../src/aggregator/compact_1_2.h"

void compact_1_2_regex_test() {
    std::string db_name = "/tmp/lv_db";

    for (const auto & name:{db_name, db_name + "_a", db_name + "_b"}) {
        if (LeviDB::IOEnv::fileExists(name)) {
            for (const std::string & child:LeviDB::IOEnv::getChildren(name)) {
                LeviDB::IOEnv::deleteFile((name + '/') += child);
            }
            LeviDB::IOEnv::deleteDir(name);
        }
    }

    typedef LeviDB::Regex::R R;
    auto r_obj = std::make_shared<R>(R("5") << R("0", "9", 0, INT_MAX));

    LeviDB::SeqGenerator seq_gen;
    LeviDB::Options options{};
    options.create_if_missing = true;
    auto db = std::make_unique<LeviDB::DBSingle>(db_name, options, &seq_gen);
    for (int i = 0; i < 100; ++i) {
        db->put(LeviDB::WriteOptions{}, std::to_string(i), std::to_string(i));
    }
    LeviDB::Compacting1To2DB compact_db(std::move(db), &seq_gen);
    assert(compact_db.immut_product_a()->canRelease());
    assert(compact_db.immut_product_b()->canRelease());
    {
        auto snapshot = compact_db.makeSnapshot();

        std::thread task([it = compact_db.makeRegexIterator(r_obj, std::make_unique<LeviDB::Snapshot>(
                snapshot->immut_seq_num()))]() noexcept {
            try {
                while (it->valid()) {
                    auto item = it->item();
                    assert(item.first == item.second && item.second[0] == '5');
                    it->next();
                }
            } catch (const LeviDB::Exception & e) {
                std::cout << e.toString() << std::endl;
            }
        });
        task.detach();

        for (int i = 40; i < 60; ++i) {
            compact_db.put(LeviDB::WriteOptions{}, std::to_string(i), "X");
        }

        {
            auto it = compact_db.makeRegexReversedIterator(r_obj,
                                                           std::make_unique<LeviDB::Snapshot>(
                                                                   snapshot->immut_seq_num()));
            while (it->valid()) {
                auto item = it->item();
                assert(item.first == item.second && item.second[0] == '5');
                it->next();
            }
        }

        {
            auto it = compact_db.makeRegexIterator(r_obj, compact_db.makeSnapshot());
            while (it->valid()) {
                auto item = it->item();
                if (item.first.size() == 1) {
                    assert(item.second == "5");
                } else {
                    assert(item.second == "X");
                }
                it->next();
            }
        }

        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::thread task_2([it = compact_db.makeRegexIterator(r_obj, std::make_unique<LeviDB::Snapshot>(
                snapshot->immut_seq_num()))]() noexcept {
            try {
                while (it->valid()) {
                    auto item = it->item();
                    assert(item.first == item.second && item.second[0] == '5');
                    it->next();
                }
            } catch (const LeviDB::Exception & e) {
                std::cout << e.toString() << std::endl;
            }
        });
        task_2.detach();
    }

    while (!compact_db.canRelease()) {
        compact_db.tryApplyPending();
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    {
        auto it = compact_db.makeRegexIterator(r_obj, compact_db.makeSnapshot());
        while (it->valid()) {
            auto item = it->item();
            if (item.first.size() == 1) {
                assert(item.second == "5");
            } else {
                assert(item.second == "X");
            }
            it->next();
        }
    }

    for (int i = 40; i < 60; ++i) {
        compact_db.put(LeviDB::WriteOptions{}, std::to_string(i), std::to_string(i));
    }
    compact_db.tryApplyPending();
    assert(compact_db.canRelease());

    std::cout << __FUNCTION__ << std::endl;
}<commit_msg>add more compact 1 to 2 iter tests<commit_after>#include <iostream>

#include "../src/aggregator/compact_1_2.h"

void compact_1_2_regex_test() {
    std::string db_name = "/tmp/lv_db";

    for (const auto & name:{db_name, db_name + "_a", db_name + "_b"}) {
        if (LeviDB::IOEnv::fileExists(name)) {
            for (const std::string & child:LeviDB::IOEnv::getChildren(name)) {
                LeviDB::IOEnv::deleteFile((name + '/') += child);
            }
            LeviDB::IOEnv::deleteDir(name);
        }
    }

    typedef LeviDB::Regex::R R;
    auto r_obj = std::make_shared<R>(R("5") << R("0", "9", 0, INT_MAX));

    LeviDB::SeqGenerator seq_gen;
    LeviDB::Options options{};
    options.create_if_missing = true;
    auto db = std::make_unique<LeviDB::DBSingle>(db_name, options, &seq_gen);
    for (int i = 0; i < 100; ++i) {
        db->put(LeviDB::WriteOptions{}, std::to_string(i), std::to_string(i));
    }
    LeviDB::Compacting1To2DB compact_db(std::move(db), &seq_gen);
    assert(compact_db.immut_product_a()->canRelease());
    assert(compact_db.immut_product_b()->canRelease());
    {
        auto snapshot = compact_db.makeSnapshot();

        std::thread task([it = compact_db.makeRegexIterator(r_obj, std::make_unique<LeviDB::Snapshot>(
                snapshot->immut_seq_num()))]() noexcept {
            try {
                while (it->valid()) {
                    auto item = it->item();
                    assert(item.first == item.second && item.second[0] == '5');
                    it->next();
                }
            } catch (const LeviDB::Exception & e) {
                std::cout << e.toString() << std::endl;
            }
        });
        task.detach();

        for (int i = 40; i < 60; ++i) {
            compact_db.put(LeviDB::WriteOptions{}, std::to_string(i), "X");
        }

        {
            auto it = compact_db.makeRegexIterator(r_obj, compact_db.makeSnapshot());
            while (it->valid()) {
                auto item = it->item();
                if (item.first.size() == 1) {
                    assert(item.second == "5");
                } else {
                    assert(item.second == "X");
                }
                it->next();
            }
        }

        {
            auto it = compact_db.makeRegexReversedIterator(r_obj,
                                                           std::make_unique<LeviDB::Snapshot>(
                                                                   snapshot->immut_seq_num()));
            while (it->valid()) {
                auto item = it->item();
                assert(item.first == item.second && item.second[0] == '5');
                it->next();
            }
        }

        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::thread task_2([it = compact_db.makeRegexIterator(r_obj, std::make_unique<LeviDB::Snapshot>(
                snapshot->immut_seq_num()))]() noexcept {
            try {
                while (it->valid()) {
                    auto item = it->item();
                    assert(item.first == item.second && item.second[0] == '5');
                    it->next();
                }
            } catch (const LeviDB::Exception & e) {
                std::cout << e.toString() << std::endl;
            }
        });
        task_2.detach();
    }

    while (!compact_db.canRelease()) {
        compact_db.tryApplyPending();
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    {
        auto it = compact_db.makeRegexIterator(r_obj, compact_db.makeSnapshot());
        while (it->valid()) {
            auto item = it->item();
            if (item.first.size() == 1) {
                assert(item.second == "5");
            } else {
                assert(item.second == "X");
            }
            it->next();
        }
    }

    for (int i = 40; i < 60; ++i) {
        compact_db.put(LeviDB::WriteOptions{}, std::to_string(i), std::to_string(i));
    }
    compact_db.tryApplyPending();
    assert(compact_db.canRelease());

    std::cout << __FUNCTION__ << std::endl;
}<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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 <sys/socket.h>
#include <errno.h>
#include <fd_map.hpp>
#include <tcp_fd.hpp>
#include <udp_fd.hpp>

int socket(int domain, int type, int protocol)
{
  // disallow strange domains, like ALG
  if (domain < 0 || domain > AF_INET6) { errno = EAFNOSUPPORT; return -1; }
  // disallow RAW etc
  if (type < 0 || type > SOCK_DGRAM) { errno = EINVAL; return -1; }
  // we are purposefully ignoring the protocol argument
  if (protocol < 0) { errno = EPROTONOSUPPORT; return -1; }

  return [](const int type)->int{
    switch(type)
    {
      case SOCK_STREAM:
        return FD_map::_open<TCP_FD>().get_id();
      case SOCK_DGRAM:
        return FD_map::_open<UDP_FD>().get_id();
      default:
        return -1;
    }
  }(type);
}

int connect(int socket, const struct sockaddr *address, socklen_t len)
{
  try {
    auto& fd = FD_map::_get(socket);
    return fd.connect(address, len);
  } catch (const FD_not_found&) {
    errno = EBADF;
    return -1;
  }
}

ssize_t send(int socket, const void *message, size_t len, int fmt)
{
  try {
    auto& fd = FD_map::_get(socket);
    return fd.send(message, len, fmt);
  } catch (const FD_not_found&) {
    errno = EBADF;
    return -1;
  }
}

int listen(int socket, int backlog)
{
  try {
    auto& fd = FD_map::_get(socket);
    return fd.listen(backlog);
  } catch (const FD_not_found&) {
    errno = EBADF;
    return -1;
  }
}

int bind(int socket, const struct sockaddr* address, socklen_t len)
{
  try {
    auto& fd = FD_map::_get(socket);
    return fd.bind(address, len);
  } catch (const FD_not_found&) {
    errno = EBADF;
    return -1;
  }
}
<commit_msg>posix: Add recv global function<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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 <sys/socket.h>
#include <errno.h>
#include <fd_map.hpp>
#include <tcp_fd.hpp>
#include <udp_fd.hpp>

int socket(int domain, int type, int protocol)
{
  // disallow strange domains, like ALG
  if (domain < 0 || domain > AF_INET6) { errno = EAFNOSUPPORT; return -1; }
  // disallow RAW etc
  if (type < 0 || type > SOCK_DGRAM) { errno = EINVAL; return -1; }
  // we are purposefully ignoring the protocol argument
  if (protocol < 0) { errno = EPROTONOSUPPORT; return -1; }

  return [](const int type)->int{
    switch(type)
    {
      case SOCK_STREAM:
        return FD_map::_open<TCP_FD>().get_id();
      case SOCK_DGRAM:
        return FD_map::_open<UDP_FD>().get_id();
      default:
        return -1;
    }
  }(type);
}

int connect(int socket, const struct sockaddr *address, socklen_t len)
{
  try {
    auto& fd = FD_map::_get(socket);
    return fd.connect(address, len);
  } catch (const FD_not_found&) {
    errno = EBADF;
    return -1;
  }
}

ssize_t send(int socket, const void *message, size_t len, int fmt)
{
  try {
    auto& fd = FD_map::_get(socket);
    return fd.send(message, len, fmt);
  } catch (const FD_not_found&) {
    errno = EBADF;
    return -1;
  }
}
ssize_t recv(int socket, void *buffer, size_t length, int flags)
{
  try {
    auto& fd = FD_map::_get(socket);
    return fd.recv(buffer, length, flags);
  } catch (const FD_not_found&) {
    errno = EBADF;
    return -1;
  }
}

int listen(int socket, int backlog)
{
  try {
    auto& fd = FD_map::_get(socket);
    return fd.listen(backlog);
  } catch (const FD_not_found&) {
    errno = EBADF;
    return -1;
  }
}

int bind(int socket, const struct sockaddr* address, socklen_t len)
{
  try {
    auto& fd = FD_map::_get(socket);
    return fd.bind(address, len);
  } catch (const FD_not_found&) {
    errno = EBADF;
    return -1;
  }
}
<|endoftext|>


<commit_before>#include "search.hpp"
#include "idastar.hpp"
#include "astar.hpp"
#include "astar-dump.hpp"
#include "wastar.hpp"
#include "greedy.hpp"
#include "bugsy.hpp"
#include "bugsy-slim.hpp"
#include "arastar.hpp"
#include "lsslrtastar2.hpp"
#include "fhatlrtastar.hpp"
#include "dtastar-dump.hpp"
#include "dtastar.hpp"
#include "monstar-dump.hpp"

/*
#include "rtastar.hpp"
#include "multilrtastar.hpp"
#include "lsslrtastar.hpp"
#include "flrtastar.hpp"
#include "flrtastar2.hpp"
#include "cautiouslrtastar.hpp"
#include "frankenlrtastar.hpp"
#include "wlrtastar.hpp"
#include "dflrtastar.hpp"
#include "mrastar.hpp"
#include "greedylrtastar.hpp"
#include "uclrtastar.hpp"
*/

#include <cstddef>
#include <cstdio>

// Functions for conveniently defining a new main
// function for a domain.

void dfheader(FILE*);
void dffooter(FILE*);
void dfpair(FILE *, const char *, const char *, ...);
void dfprocstatus(FILE*);
void fatal(const char*, ...);

template<class D> SearchAlgorithm<D> *getsearch(int argc, const char *argv[]);

template<class D> Result<D> search(D &d, int argc, const char *argv[]) {
	return searchGet(getsearch, d, argc, argv);
}

template<class D> Result<D> searchGet(SearchAlgorithm<D>*(*get)(int, const char *[]), D &d, int argc, const char *argv[]) {
	SearchAlgorithm<D> *srch = get(argc, argv);
	if (!srch && argc > 1)
		fatal("Unknow search algorithm: %s", argv[1]);
	if (!srch)
		fatal("Must specify a search algorithm");

	typename D::State s0 = d.initialstate();
	dfpair(stdout, "initial heuristic", "%f", (double) d.h(s0));
	dfpair(stdout, "initial distance", "%f", (double) d.d(s0));
	dfpair(stdout, "algorithm", argv[1]);

	try {
		srch->search(d, s0);
	} catch (std::bad_alloc&) {
		dfpair(stdout, "out of memory", "%s", "true");
		srch->res.path.clear();
		srch->res.ops.clear();
		srch->finish();
	}
	if (srch->res.path.size() > 0) {
		dfpair(stdout, "final sol cost", "%f",
			(double) d.pathcost(srch->res.path, srch->res.ops));
	} else {
		dfpair(stdout, "final sol cost", "%f", -1.0);
	}
	srch->output(stdout);

	Result<D> res = srch->res;
	delete srch;

	return res;
}

template<class D> SearchAlgorithm<D> *getsearch(int argc, const char *argv[]) {
	if (argc < 2)
		fatal("No algorithm specified");

	if (strcmp(argv[1], "idastar") == 0)
		return new Idastar<D>(argc, argv);
	else if (strcmp(argv[1], "astar") == 0)
		return new Astar<D>(argc, argv);
	else if (strcmp(argv[1], "astar-dump") == 0)
		return new Astar_dump<D>(argc, argv);
	else if (strcmp(argv[1], "wastar") == 0)
		return new Wastar<D>(argc, argv);
	else if (strcmp(argv[1], "greedy") == 0)
		return new Greedy<D>(argc, argv);
	else if (strcmp(argv[1], "speedy") == 0)
		return new Greedy<D, true>(argc, argv);
	else if (strcmp(argv[1], "bugsy") == 0)
		return new Bugsy<D>(argc, argv);
	else if (strcmp(argv[1], "bugsy-slim") == 0)
		return new Bugsy_slim<D>(argc, argv);
	else if (strcmp(argv[1], "arastar") == 0)
		return new Arastar<D>(argc, argv);
	else if (strcmp(argv[1], "arastarmon") == 0)
		return new ArastarMon<D>(argc, argv);
	else if (strcmp(argv[1], "dtastar-dump") == 0)
		return new Dtastar_dump<D>(argc, argv);
	else if (strcmp(argv[1], "lsslrtastar2") == 0)
		return new Lsslrtastar2<D>(argc, argv);
	else if (strcmp(argv[1], "fhatlrtastar") == 0)
		return new Fhatlrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "dtastar") == 0)
		return new Dtastar<D>(argc, argv);
	else if (strcmp(argv[1], "monstar-dump") == 0)
		return new Monstar_dump<D>(argc, argv);

/*
	else if (strcmp(argv[1], "mrastar") == 0)
		return new Mrastar<D>(argc, argv);
	else if (strcmp(argv[1], "dflrtastar") == 0)
		return new Dflrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "greedylrtastar") == 0)
		return new Greedylrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "uclrtastar") == 0)
		return new Uclrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "multilrtastar") == 0)
		return new Multilrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "cautiouslrtastar") == 0)
		return new Cautiouslrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "frankenlrtastar") == 0)
		return new Frankenlrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "wlrtastar") == 0)
		return new Wlrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "rtastar") == 0)
		return new Rtastar<D>(argc, argv);
	else if (strcmp(argv[1], "lsslrtastar") == 0)
		return new Lsslrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "flrtastar") == 0)
		return new Flrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "flrtastar2") == 0)
		return new Flrtastar2<D>(argc, argv);
*/

	fatal("Unknown algorithm: %s", argv[1]);
	return NULL;	// Unreachable
}
<commit_msg>search: reenable RTA*.<commit_after>#include "search.hpp"
#include "idastar.hpp"
#include "astar.hpp"
#include "astar-dump.hpp"
#include "wastar.hpp"
#include "greedy.hpp"
#include "bugsy.hpp"
#include "bugsy-slim.hpp"
#include "arastar.hpp"
#include "lsslrtastar2.hpp"
#include "fhatlrtastar.hpp"
#include "dtastar-dump.hpp"
#include "dtastar.hpp"
#include "monstar-dump.hpp"
#include "rtastar.hpp"

/*
#include "multilrtastar.hpp"
#include "lsslrtastar.hpp"
#include "flrtastar.hpp"
#include "flrtastar2.hpp"
#include "cautiouslrtastar.hpp"
#include "frankenlrtastar.hpp"
#include "wlrtastar.hpp"
#include "dflrtastar.hpp"
#include "mrastar.hpp"
#include "greedylrtastar.hpp"
#include "uclrtastar.hpp"
*/

#include <cstddef>
#include <cstdio>

// Functions for conveniently defining a new main
// function for a domain.

void dfheader(FILE*);
void dffooter(FILE*);
void dfpair(FILE *, const char *, const char *, ...);
void dfprocstatus(FILE*);
void fatal(const char*, ...);

template<class D> SearchAlgorithm<D> *getsearch(int argc, const char *argv[]);

template<class D> Result<D> search(D &d, int argc, const char *argv[]) {
	return searchGet(getsearch, d, argc, argv);
}

template<class D> Result<D> searchGet(SearchAlgorithm<D>*(*get)(int, const char *[]), D &d, int argc, const char *argv[]) {
	SearchAlgorithm<D> *srch = get(argc, argv);
	if (!srch && argc > 1)
		fatal("Unknow search algorithm: %s", argv[1]);
	if (!srch)
		fatal("Must specify a search algorithm");

	typename D::State s0 = d.initialstate();
	dfpair(stdout, "initial heuristic", "%f", (double) d.h(s0));
	dfpair(stdout, "initial distance", "%f", (double) d.d(s0));
	dfpair(stdout, "algorithm", argv[1]);

	try {
		srch->search(d, s0);
	} catch (std::bad_alloc&) {
		dfpair(stdout, "out of memory", "%s", "true");
		srch->res.path.clear();
		srch->res.ops.clear();
		srch->finish();
	}
	if (srch->res.path.size() > 0) {
		dfpair(stdout, "final sol cost", "%f",
			(double) d.pathcost(srch->res.path, srch->res.ops));
	} else {
		dfpair(stdout, "final sol cost", "%f", -1.0);
	}
	srch->output(stdout);

	Result<D> res = srch->res;
	delete srch;

	return res;
}

template<class D> SearchAlgorithm<D> *getsearch(int argc, const char *argv[]) {
	if (argc < 2)
		fatal("No algorithm specified");

	if (strcmp(argv[1], "idastar") == 0)
		return new Idastar<D>(argc, argv);
	else if (strcmp(argv[1], "astar") == 0)
		return new Astar<D>(argc, argv);
	else if (strcmp(argv[1], "astar-dump") == 0)
		return new Astar_dump<D>(argc, argv);
	else if (strcmp(argv[1], "wastar") == 0)
		return new Wastar<D>(argc, argv);
	else if (strcmp(argv[1], "greedy") == 0)
		return new Greedy<D>(argc, argv);
	else if (strcmp(argv[1], "speedy") == 0)
		return new Greedy<D, true>(argc, argv);
	else if (strcmp(argv[1], "bugsy") == 0)
		return new Bugsy<D>(argc, argv);
	else if (strcmp(argv[1], "bugsy-slim") == 0)
		return new Bugsy_slim<D>(argc, argv);
	else if (strcmp(argv[1], "arastar") == 0)
		return new Arastar<D>(argc, argv);
	else if (strcmp(argv[1], "arastarmon") == 0)
		return new ArastarMon<D>(argc, argv);
	else if (strcmp(argv[1], "dtastar-dump") == 0)
		return new Dtastar_dump<D>(argc, argv);
	else if (strcmp(argv[1], "lsslrtastar2") == 0)
		return new Lsslrtastar2<D>(argc, argv);
	else if (strcmp(argv[1], "fhatlrtastar") == 0)
		return new Fhatlrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "dtastar") == 0)
		return new Dtastar<D>(argc, argv);
	else if (strcmp(argv[1], "monstar-dump") == 0)
		return new Monstar_dump<D>(argc, argv);
	else if (strcmp(argv[1], "rtastar") == 0)
		return new Rtastar<D>(argc, argv);

/*
	else if (strcmp(argv[1], "mrastar") == 0)
		return new Mrastar<D>(argc, argv);
	else if (strcmp(argv[1], "dflrtastar") == 0)
		return new Dflrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "greedylrtastar") == 0)
		return new Greedylrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "uclrtastar") == 0)
		return new Uclrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "multilrtastar") == 0)
		return new Multilrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "cautiouslrtastar") == 0)
		return new Cautiouslrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "frankenlrtastar") == 0)
		return new Frankenlrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "wlrtastar") == 0)
		return new Wlrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "lsslrtastar") == 0)
		return new Lsslrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "flrtastar") == 0)
		return new Flrtastar<D>(argc, argv);
	else if (strcmp(argv[1], "flrtastar2") == 0)
		return new Flrtastar2<D>(argc, argv);
*/

	fatal("Unknown algorithm: %s", argv[1]);
	return NULL;	// Unreachable
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief Aql, query parser
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "Aql/Parser.h"
#include "Aql/AstNode.h"
#include "Aql/QueryResult.h"

using namespace triagens::aql;

// -----------------------------------------------------------------------------
// --SECTION--                                        constructors / destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief create the parser
////////////////////////////////////////////////////////////////////////////////

Parser::Parser (Query* query)
  : _query(query),
    _ast(nullptr),
    _scanner(nullptr),
    _buffer(query->queryString()),
    _remainingLength(query->queryLength()),
    _offset(0),
    _marker(nullptr),
    _stack() {

  _ast = new Ast(query, this);

  _stack.reserve(16);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destroy the parser
////////////////////////////////////////////////////////////////////////////////

Parser::~Parser () {
  if (_ast != nullptr) {
    delete _ast;
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                  public functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief set data for write queries
////////////////////////////////////////////////////////////////////////////////

bool Parser::configureWriteQuery (QueryType type,
                                  AstNode const* collectionNode,
                                  AstNode* optionNode) {
  TRI_ASSERT(type != AQL_QUERY_READ);

  // check if we currently are in a subquery
  if (_ast->isInSubQuery()) {
    // data modification not allowed in sub-queries
    _query->registerError(TRI_ERROR_QUERY_MODIFY_IN_SUBQUERY);
    return false;
  }

  // check current query type
  auto oldType = _query->type();

  if (oldType != AQL_QUERY_READ) {
    // already a data-modification query, cannot have two data-modification operations in one query
    _query->registerError(TRI_ERROR_QUERY_MULTI_MODIFY);
    return false;
  }

  // now track which collection is going to be modified
  _ast->setWriteCollection(collectionNode);

  if (optionNode != nullptr && ! optionNode->isConstant()) {
    _query->registerError(TRI_ERROR_QUERY_COMPILE_TIME_OPTIONS);
  }

  // register type
  _query->type(type);
  return true;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief parse the query
////////////////////////////////////////////////////////////////////////////////

QueryResult Parser::parse () {
  // start main scope
  auto scopes = _ast->scopes();
  scopes->start(AQL_SCOPE_MAIN);

  Aqllex_init(&_scanner);
  Aqlset_extra(this, _scanner);

  try {
    // parse the query string
    if (Aqlparse(this)) {
      // lexing/parsing failed
      THROW_ARANGO_EXCEPTION(TRI_ERROR_QUERY_PARSE);
    }

    Aqllex_destroy(_scanner);
  }
  catch (...) {
    Aqllex_destroy(_scanner);
    throw;
  }

  // end main scope
  scopes->endCurrent();

  TRI_ASSERT(scopes->numActive() == 0);

  QueryResult result;
  result.collectionNames = _query->collectionNames();
  result.bindParameters  = _ast->bindParameters();
  result.json            = _ast->toJson(TRI_UNKNOWN_MEM_ZONE, false);

  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief register a parse error, position is specified as line / column
////////////////////////////////////////////////////////////////////////////////

void Parser::registerParseError (int errorCode,
                                 char const* format,
                                 char const* data,
                                 int line,
                                 int column) {
  char buffer[512];
  snprintf(buffer,
           sizeof(buffer),
           format,
           data);

  return registerParseError(errorCode, buffer, line, column);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief register a parse error, position is specified as line / column
////////////////////////////////////////////////////////////////////////////////

void Parser::registerParseError (int errorCode,
                                 char const* data,
                                 int line,
                                 int column) {
  TRI_ASSERT(errorCode != TRI_ERROR_NO_ERROR);
  TRI_ASSERT(data != nullptr);

  // extract the query string part where the error happened
  std::string const region(_query->extractRegion(line, column));

  // note: line numbers reported by bison/flex start at 1, columns start at 0
  char buffer[512];
  snprintf(buffer,
           sizeof(buffer),
           "%s near '%s' at position %d:%d",
           data,
           region.c_str(),
           line,
           column + 1);

  registerError(errorCode, buffer);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief register a non-parse error
////////////////////////////////////////////////////////////////////////////////

void Parser::registerError (int errorCode,
                            char const* data) {
  _query->registerError(errorCode, data);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief push an AstNode into the list element on top of the stack
////////////////////////////////////////////////////////////////////////////////

void Parser::pushList (AstNode* node) {
  auto list = static_cast<AstNode*>(peekStack());
  TRI_ASSERT(list->type == NODE_TYPE_LIST);
  list->addMember(node);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief push an AstNode into the array element on top of the stack
////////////////////////////////////////////////////////////////////////////////

void Parser::pushArray (char const* attributeName,
                        AstNode* node) {
  auto array = static_cast<AstNode*>(peekStack());
  TRI_ASSERT(array->type == NODE_TYPE_ARRAY);
  auto element = _ast->createNodeArrayElement(attributeName, node);
  array->addMember(element);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief push a temporary value on the parser's stack
////////////////////////////////////////////////////////////////////////////////

void Parser::pushStack (void* value) {
  _stack.push_back(value);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief pop a temporary value from the parser's stack
////////////////////////////////////////////////////////////////////////////////

void* Parser::popStack () {
  TRI_ASSERT(! _stack.empty());

  void* result = _stack.back();
  _stack.pop_back();
  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief peek at a temporary value from the parser's stack
////////////////////////////////////////////////////////////////////////////////

void* Parser::peekStack () {
  TRI_ASSERT(! _stack.empty());

  return _stack.back();
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>Parser: when throwing parse exceptions add the query and a pointer to the actual indicated error to the message.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief Aql, query parser
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "Aql/Parser.h"
#include "Aql/AstNode.h"
#include "Aql/QueryResult.h"

using namespace triagens::aql;

// -----------------------------------------------------------------------------
// --SECTION--                                        constructors / destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief create the parser
////////////////////////////////////////////////////////////////////////////////

Parser::Parser (Query* query)
  : _query(query),
    _ast(nullptr),
    _scanner(nullptr),
    _buffer(query->queryString()),
    _remainingLength(query->queryLength()),
    _offset(0),
    _marker(nullptr),
    _stack() {

  _ast = new Ast(query, this);

  _stack.reserve(16);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destroy the parser
////////////////////////////////////////////////////////////////////////////////

Parser::~Parser () {
  if (_ast != nullptr) {
    delete _ast;
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                  public functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief set data for write queries
////////////////////////////////////////////////////////////////////////////////

bool Parser::configureWriteQuery (QueryType type,
                                  AstNode const* collectionNode,
                                  AstNode* optionNode) {
  TRI_ASSERT(type != AQL_QUERY_READ);

  // check if we currently are in a subquery
  if (_ast->isInSubQuery()) {
    // data modification not allowed in sub-queries
    _query->registerError(TRI_ERROR_QUERY_MODIFY_IN_SUBQUERY);
    return false;
  }

  // check current query type
  auto oldType = _query->type();

  if (oldType != AQL_QUERY_READ) {
    // already a data-modification query, cannot have two data-modification operations in one query
    _query->registerError(TRI_ERROR_QUERY_MULTI_MODIFY);
    return false;
  }

  // now track which collection is going to be modified
  _ast->setWriteCollection(collectionNode);

  if (optionNode != nullptr && ! optionNode->isConstant()) {
    _query->registerError(TRI_ERROR_QUERY_COMPILE_TIME_OPTIONS);
  }

  // register type
  _query->type(type);
  return true;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief parse the query
////////////////////////////////////////////////////////////////////////////////

QueryResult Parser::parse () {
  // start main scope
  auto scopes = _ast->scopes();
  scopes->start(AQL_SCOPE_MAIN);

  Aqllex_init(&_scanner);
  Aqlset_extra(this, _scanner);

  try {
    // parse the query string
    if (Aqlparse(this)) {
      // lexing/parsing failed
      THROW_ARANGO_EXCEPTION(TRI_ERROR_QUERY_PARSE);
    }

    Aqllex_destroy(_scanner);
  }
  catch (...) {
    Aqllex_destroy(_scanner);
    throw;
  }

  // end main scope
  scopes->endCurrent();

  TRI_ASSERT(scopes->numActive() == 0);

  QueryResult result;
  result.collectionNames = _query->collectionNames();
  result.bindParameters  = _ast->bindParameters();
  result.json            = _ast->toJson(TRI_UNKNOWN_MEM_ZONE, false);

  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief register a parse error, position is specified as line / column
////////////////////////////////////////////////////////////////////////////////

void Parser::registerParseError (int errorCode,
                                 char const* format,
                                 char const* data,
                                 int line,
                                 int column) {
  char buffer[512];
  snprintf(buffer,
           sizeof(buffer),
           format,
           data);

  return registerParseError(errorCode, buffer, line, column);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief register a parse error, position is specified as line / column
////////////////////////////////////////////////////////////////////////////////

void Parser::registerParseError (int errorCode,
                                 char const* data,
                                 int line,
                                 int column) {
  TRI_ASSERT(errorCode != TRI_ERROR_NO_ERROR);
  TRI_ASSERT(data != nullptr);

  // extract the query string part where the error happened
  std::string const region(_query->extractRegion(line, column));

  // create a neat pointer to the location of the error.
  auto arrowpointer = (char*) malloc (sizeof(char) * (column + 10) );
  size_t i;
  for (i = 0; i < (size_t) column; i++) {
    arrowpointer[i] = ' ';
  }
  if (i > 0) {
	i --;
	arrowpointer[i++] = '^';
  }

  arrowpointer[i++] = '^';
  arrowpointer[i++] = '^';
  arrowpointer[i++] = '\0';

  // note: line numbers reported by bison/flex start at 1, columns start at 0
  char buffer[512];
  snprintf(buffer,
           sizeof(buffer),
           "%s near '%s' at position %d:%d:\n%s\n%s\n",
           data,
           region.c_str(),
           line,
           column + 1,
           _query->queryString(),
           arrowpointer);

  free(arrowpointer);

  registerError(errorCode, buffer);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief register a non-parse error
////////////////////////////////////////////////////////////////////////////////

void Parser::registerError (int errorCode,
                            char const* data) {
  _query->registerError(errorCode, data);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief push an AstNode into the list element on top of the stack
////////////////////////////////////////////////////////////////////////////////

void Parser::pushList (AstNode* node) {
  auto list = static_cast<AstNode*>(peekStack());
  TRI_ASSERT(list->type == NODE_TYPE_LIST);
  list->addMember(node);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief push an AstNode into the array element on top of the stack
////////////////////////////////////////////////////////////////////////////////

void Parser::pushArray (char const* attributeName,
                        AstNode* node) {
  auto array = static_cast<AstNode*>(peekStack());
  TRI_ASSERT(array->type == NODE_TYPE_ARRAY);
  auto element = _ast->createNodeArrayElement(attributeName, node);
  array->addMember(element);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief push a temporary value on the parser's stack
////////////////////////////////////////////////////////////////////////////////

void Parser::pushStack (void* value) {
  _stack.push_back(value);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief pop a temporary value from the parser's stack
////////////////////////////////////////////////////////////////////////////////

void* Parser::popStack () {
  TRI_ASSERT(! _stack.empty());

  void* result = _stack.back();
  _stack.pop_back();
  return result;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief peek at a temporary value from the parser's stack
////////////////////////////////////////////////////////////////////////////////

void* Parser::peekStack () {
  TRI_ASSERT(! _stack.empty());

  return _stack.back();
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before><commit_msg>ppl: fix missing _<commit_after><|endoftext|>