<commit_before>// -*- mode:c++;coding:utf-8; -*- vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:enc=utf-8:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

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 "flusspferd/create.hpp"
#include "flusspferd/binary.hpp"
#include "flusspferd/tracer.hpp"
#include "flusspferd/modules.hpp"
#include "flusspferd/security.hpp"
#include "flusspferd/arguments.hpp"
#include "flusspferd/class_description.hpp"
#include "flusspferd/property_iterator.hpp"

#include <sstream>
#include <curl/curl.h>

#include <boost/ptr_container/ptr_unordered_map.hpp>
#include <boost/exception/get_error_info.hpp>
#include <boost/assign/ptr_map_inserter.hpp>
#include <boost/version.hpp>

#include <iostream>

using namespace flusspferd;

namespace {
	typedef boost::error_info<struct tag_curlcode, CURLcode> curlcode_info;

	struct exception
		: flusspferd::exception
	{
		exception(std::string const &what)
			: std::runtime_error(what), flusspferd::exception(what)
		{ }

		char const *what() const throw() {
#if BOOST_VERSION < 103900
			boost::shared_ptr<CURLcode const*> code;
#else
			CURLcode const *code;
#endif
			if( (code = ::boost::get_error_info<curlcode_info>(*this)) ) {
				std::string what_ = flusspferd::exception::what();
				what_ += ": ";
				what_ += curl_easy_strerror(*code);
				return what_.c_str();
			}
			else {
				return flusspferd::exception::what();
			}
		}
	};

  void global_init(long flags) {
    CURLcode ret = curl_global_init(flags);
		if(ret != 0) {
			throw flusspferd::exception(std::string("curl_global_init: ")
																	+ curl_easy_strerror(ret));
		}
  }

	class Easy;

	namespace {
		struct handle_option {
			virtual ~handle_option() =0;
			virtual value default_value() const { return value(); }
			virtual property_attributes default_attributes() const {
				return property_attributes();
			}
			virtual void handle(Easy &e, value const &v) const =0;
		};
		handle_option::~handle_option() { }

		typedef boost::ptr_unordered_map<std::string, handle_option> options_map_t;
		options_map_t const &get_options();
	}

	FLUSSPFERD_CLASS_DESCRIPTION
	(
	 EasyOpt,
	 (constructor_name, "EasyOpt")
	 (full_name, "cURL.Easy.EasyOpt")
	 (constructible, false)
	 )
	{
		Easy &parent;
	public:
		EasyOpt(flusspferd::object const &self, Easy &parent)
			: base_type(self), parent(parent)
		{	}

		static EasyOpt &create(Easy &p) {
			return flusspferd::create_native_object<EasyOpt>(object(), boost::ref(p));
		}
	protected:
		bool property_resolve(value const &id, unsigned access);
	};

  FLUSSPFERD_CLASS_DESCRIPTION
  (
   Easy,
   (constructor_name, "Easy")
   (full_name, "cURL.Easy")
   (methods,
    ("cleanup",  bind, cleanup)
    ("perform",  bind, perform)
    ("reset",    bind, reset)
    ("escape",   bind, escape)
    ("unescape", bind, unescape)
    ("valid",    bind, valid))
	 (properties,
		("options", getter, get_opt))
   )
  {
    CURL *handle;
		EasyOpt &opt;

		static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) {
			assert(stream);
			Easy &self = *reinterpret_cast<Easy*>(stream);
			byte_array data(object(),
											reinterpret_cast<byte_array::element_type*>(ptr),
											size*nmemb);
			arguments arg;
			arg.push_back(value(data));
			arg.push_back(value(size));
			object callback = self.opt.get_property("writeFunction").to_object();
			value v = callback.call(arg);
			return v.to_number();
		}

	protected:
		void trace(flusspferd::tracer &trc) {
			trc("options", opt);
		}

  public:
    CURL *data() { return handle; }
    bool valid() { return handle; }
    CURL *get() {
      if(!handle) {
        throw flusspferd::exception("CURL handle not valid!");
      }
      return handle;
    }
		EasyOpt &get_opt() {
			return opt;
		}

    Easy(flusspferd::object const &self, flusspferd::call_context&)
      : base_type(self), handle(curl_easy_init()), opt(EasyOpt::create(*this))
    {
      if(!handle) {
        throw flusspferd::exception("curl_easy_init");
      }
    }

    Easy(flusspferd::object const &self, CURL *hnd)
      : base_type(self), handle(hnd), opt(EasyOpt::create(*this))
    {
      assert(handle);
    }

    void cleanup() {
      if(handle) {
        curl_easy_cleanup(handle);
        handle = 0x0;
      }
    }
    ~Easy() { cleanup(); }

		/**
		 * Applies all options set in EasyOpt.
		 * This is called automatically.
		 * Shouldn't be necessary to call it manually!
		 *
		 * Not exported.
		 *
		 * Maybe this should be called by unwrap and be private ...
		 */
		void apply_options() {
			std::cout << "apply_options()\n";
			options_map_t const &options = get_options();
			for(property_iterator i = opt.begin();
					i != opt.end();
					++i)
			{
				std::cout << "\t" << i->to_std_string() << "\n";
				options_map_t::const_iterator option = options.find(i->to_std_string());
				if(option != options.end()) {
					option->second->handle(*this, opt.get_property(*i));
				}
			}
		}

    void perform() {
			apply_options();
			CURLcode res = curl_easy_perform(get());
			if(res != 0) {
				throw flusspferd::exception(std::string("curl_easy_perform: ") +
																		curl_easy_strerror(res));
			}
    }

    void reset() {
      curl_easy_reset(get());
    }

    std::string unescape(char const *input) {
      int len;
      char *const uesc = curl_easy_unescape(get(), input, 0, &len);
      if(!uesc) {
        throw flusspferd::exception("curl_easy_unescape");
      }
      std::string ret(uesc, len);
      curl_free(uesc);
      return ret;
    }

    std::string escape(char const *input) {
      char *const esc = curl_easy_escape(get(), input, 0);
      if(!esc) {
        throw flusspferd::exception("curl_easy_escape");
      }
      std::string ret(esc);
      curl_free(esc);
      return ret;
    }

    static Easy &create(CURL *hnd) {
      return flusspferd::create_native_object<Easy>(object(), hnd);
    }

		//private:
		template<typename T>
		void do_setopt(CURLoption what, T data) {
			std::cout << "setopt (" << (unsigned)what << ' ' << data << '\n'; // DEBUG
			CURLcode res = curl_easy_setopt(get(), what, data);
			if(res != 0) {
				throw flusspferd::exception(std::string("curl_easy_setopt: ") +
																		curl_easy_strerror(res));
			}
		}

		void do_setopt_function(CURLoption what, bool default_) {
			if(default_) {
				do_setopt(what, 0x0);
			}
			else {
				switch(what) {
				case CURLOPT_WRITEFUNCTION:
					do_setopt(CURLOPT_WRITEFUNCTION, &writefunction);
					do_setopt(CURLOPT_WRITEDATA, this);
					break;
				default:
					throw flusspferd::exception("unkown function option");
				};
			}
		}
  };
  Easy &wrap(CURL *hnd) {
    return Easy::create(hnd);
  }
  CURL *unwrap(Easy &c) {
    return c.data();
  }

	namespace {
		struct integer_option : handle_option {
			integer_option(CURLoption what) : what(what) { }
			value default_value() const { return value(0); }
			void handle(Easy &e, value const &v) const {
				e.do_setopt(what, v.to_number());
			}
  	private:
			CURLoption what;
		};

		struct string_option : handle_option {
			string_option(CURLoption what) : what(what) { }
			value default_value() const { return value(""); }
			void handle(Easy &e, value const &v) const {
				e.do_setopt(what, v.to_std_string().c_str()); // TODO this won't work! string needs to be stored.
			}
		private:
			CURLoption what;
		};

		struct function_option : handle_option {
			function_option(CURLoption what) : what(what) { }
			void handle(Easy &e, value const &v) const {
				e.do_setopt_function(what, v.is_undefined_or_null());
			}
		private:
			CURLoption what;
		};

		options_map_t const &get_options() {
			static options_map_t map;
			if(map.empty()) {
				boost::assign::ptr_map_insert<integer_option>(map)
					("verbose", CURLOPT_VERBOSE)
					("header", CURLOPT_HEADER)
					("noProgress", CURLOPT_NOPROGRESS)
					("noSignal", CURLOPT_NOSIGNAL);
				boost::assign::ptr_map_insert<function_option>(map)
					("writeFunction", CURLOPT_WRITEFUNCTION);
				boost::assign::ptr_map_insert<string_option>(map)
					("url", CURLOPT_URL);
			}
			return map;
		}
	}

	bool EasyOpt::property_resolve(value const &id, unsigned) {
		std::string const name = id.to_std_string();
		options_map_t::const_iterator const i = get_options().find(name);
		if(i != get_options().end()) {
			define_property(id.get_string(), i->second->default_value(),
											i->second->default_attributes());
			return true;
		}
		else {
			return false;
		}
	}

  FLUSSPFERD_LOADER_SIMPLE(cURL) {
    local_root_scope scope;

    cURL.define_property("GLOBAL_ALL", value(CURL_GLOBAL_ALL),
                         read_only_property | permanent_property);
    cURL.define_property("GLOBAL_SSL", value(CURL_GLOBAL_SSL),
                         read_only_property | permanent_property);
    cURL.define_property("GLOBAL_WIN32", value(CURL_GLOBAL_WIN32),
                         read_only_property | permanent_property);
    cURL.define_property("GLOBAL_NOTHING", value(CURL_GLOBAL_NOTHING),
                         read_only_property | permanent_property);
    create_native_function(cURL, "globalInit", &global_init);
    cURL.define_property("version", value(curl_version()),
                         read_only_property | permanent_property);
		load_class<EasyOpt>(cURL);
    load_class<Easy>(cURL);
  }
}
<commit_msg>curl: dropped support for older boost releases (see 637ce78350c85afb5a8f79ffb60e05c642772f79)<commit_after>// -*- mode:c++;coding:utf-8; -*- vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:enc=utf-8:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

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 "flusspferd/create.hpp"
#include "flusspferd/binary.hpp"
#include "flusspferd/tracer.hpp"
#include "flusspferd/modules.hpp"
#include "flusspferd/security.hpp"
#include "flusspferd/arguments.hpp"
#include "flusspferd/class_description.hpp"
#include "flusspferd/property_iterator.hpp"

#include <sstream>
#include <curl/curl.h>

#include <boost/ptr_container/ptr_unordered_map.hpp>
#include <boost/exception/get_error_info.hpp>
#include <boost/assign/ptr_map_inserter.hpp>
#include <boost/version.hpp>

#include <iostream>

using namespace flusspferd;

namespace {
	typedef boost::error_info<struct tag_curlcode, CURLcode> curlcode_info;

	struct exception
		: flusspferd::exception
	{
		exception(std::string const &what)
			: std::runtime_error(what), flusspferd::exception(what)
		{ }

		char const *what() const throw() {
			if(CURLcode const *code = ::boost::get_error_info<curlcode_info>(*this)) {
				std::string what_ = flusspferd::exception::what();
				what_ += ": ";
				what_ += curl_easy_strerror(*code);
				return what_.c_str();
			}
			else {
				return flusspferd::exception::what();
			}
		}
	};

  void global_init(long flags) {
    CURLcode ret = curl_global_init(flags);
		if(ret != 0) {
			throw flusspferd::exception(std::string("curl_global_init: ")
																	+ curl_easy_strerror(ret));
		}
  }

	class Easy;

	namespace {
		struct handle_option {
			virtual ~handle_option() =0;
			virtual value default_value() const { return value(); }
			virtual property_attributes default_attributes() const {
				return property_attributes();
			}
			virtual void handle(Easy &e, value const &v) const =0;
		};
		handle_option::~handle_option() { }

		typedef boost::ptr_unordered_map<std::string, handle_option> options_map_t;
		options_map_t const &get_options();
	}

	FLUSSPFERD_CLASS_DESCRIPTION
	(
	 EasyOpt,
	 (constructor_name, "EasyOpt")
	 (full_name, "cURL.Easy.EasyOpt")
	 (constructible, false)
	 )
	{
		Easy &parent;
	public:
		EasyOpt(flusspferd::object const &self, Easy &parent)
			: base_type(self), parent(parent)
		{	}

		static EasyOpt &create(Easy &p) {
			return flusspferd::create_native_object<EasyOpt>(object(), boost::ref(p));
		}
	protected:
		bool property_resolve(value const &id, unsigned access);
	};

  FLUSSPFERD_CLASS_DESCRIPTION
  (
   Easy,
   (constructor_name, "Easy")
   (full_name, "cURL.Easy")
   (methods,
    ("cleanup",  bind, cleanup)
    ("perform",  bind, perform)
    ("reset",    bind, reset)
    ("escape",   bind, escape)
    ("unescape", bind, unescape)
    ("valid",    bind, valid))
	 (properties,
		("options", getter, get_opt))
   )
  {
    CURL *handle;
		EasyOpt &opt;

		static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) {
			assert(stream);
			Easy &self = *reinterpret_cast<Easy*>(stream);
			byte_array data(object(),
											reinterpret_cast<byte_array::element_type*>(ptr),
											size*nmemb);
			arguments arg;
			arg.push_back(value(data));
			arg.push_back(value(size));
			object callback = self.opt.get_property("writeFunction").to_object();
			value v = callback.call(arg);
			return v.to_number();
		}

	protected:
		void trace(flusspferd::tracer &trc) {
			trc("options", opt);
		}

  public:
    CURL *data() { return handle; }
    bool valid() { return handle; }
    CURL *get() {
      if(!handle) {
        throw flusspferd::exception("CURL handle not valid!");
      }
      return handle;
    }
		EasyOpt &get_opt() {
			return opt;
		}

    Easy(flusspferd::object const &self, flusspferd::call_context&)
      : base_type(self), handle(curl_easy_init()), opt(EasyOpt::create(*this))
    {
      if(!handle) {
        throw flusspferd::exception("curl_easy_init");
      }
    }

    Easy(flusspferd::object const &self, CURL *hnd)
      : base_type(self), handle(hnd), opt(EasyOpt::create(*this))
    {
      assert(handle);
    }

    void cleanup() {
      if(handle) {
        curl_easy_cleanup(handle);
        handle = 0x0;
      }
    }
    ~Easy() { cleanup(); }

		/**
		 * Applies all options set in EasyOpt.
		 * This is called automatically.
		 * Shouldn't be necessary to call it manually!
		 *
		 * Not exported.
		 *
		 * Maybe this should be called by unwrap and be private ...
		 */
		void apply_options() {
			std::cout << "apply_options()\n";
			options_map_t const &options = get_options();
			for(property_iterator i = opt.begin();
					i != opt.end();
					++i)
			{
				std::cout << "\t" << i->to_std_string() << "\n";
				options_map_t::const_iterator option = options.find(i->to_std_string());
				if(option != options.end()) {
					option->second->handle(*this, opt.get_property(*i));
				}
			}
		}

    void perform() {
			apply_options();
			CURLcode res = curl_easy_perform(get());
			if(res != 0) {
				throw flusspferd::exception(std::string("curl_easy_perform: ") +
																		curl_easy_strerror(res));
			}
    }

    void reset() {
      curl_easy_reset(get());
    }

    std::string unescape(char const *input) {
      int len;
      char *const uesc = curl_easy_unescape(get(), input, 0, &len);
      if(!uesc) {
        throw flusspferd::exception("curl_easy_unescape");
      }
      std::string ret(uesc, len);
      curl_free(uesc);
      return ret;
    }

    std::string escape(char const *input) {
      char *const esc = curl_easy_escape(get(), input, 0);
      if(!esc) {
        throw flusspferd::exception("curl_easy_escape");
      }
      std::string ret(esc);
      curl_free(esc);
      return ret;
    }

    static Easy &create(CURL *hnd) {
      return flusspferd::create_native_object<Easy>(object(), hnd);
    }

		//private:
		template<typename T>
		void do_setopt(CURLoption what, T data) {
			std::cout << "setopt (" << (unsigned)what << ' ' << data << '\n'; // DEBUG
			CURLcode res = curl_easy_setopt(get(), what, data);
			if(res != 0) {
				throw flusspferd::exception(std::string("curl_easy_setopt: ") +
																		curl_easy_strerror(res));
			}
		}

		void do_setopt_function(CURLoption what, bool default_) {
			if(default_) {
				do_setopt(what, 0x0);
			}
			else {
				switch(what) {
				case CURLOPT_WRITEFUNCTION:
					do_setopt(CURLOPT_WRITEFUNCTION, &writefunction);
					do_setopt(CURLOPT_WRITEDATA, this);
					break;
				default:
					throw flusspferd::exception("unkown function option");
				};
			}
		}
  };
  Easy &wrap(CURL *hnd) {
    return Easy::create(hnd);
  }
  CURL *unwrap(Easy &c) {
    return c.data();
  }

	namespace {
		struct integer_option : handle_option {
			integer_option(CURLoption what) : what(what) { }
			value default_value() const { return value(0); }
			void handle(Easy &e, value const &v) const {
				e.do_setopt(what, v.to_number());
			}
  	private:
			CURLoption what;
		};

		struct string_option : handle_option {
			string_option(CURLoption what) : what(what) { }
			value default_value() const { return value(""); }
			void handle(Easy &e, value const &v) const {
				e.do_setopt(what, v.to_std_string().c_str()); // TODO this won't work! string needs to be stored.
			}
		private:
			CURLoption what;
		};

		struct function_option : handle_option {
			function_option(CURLoption what) : what(what) { }
			void handle(Easy &e, value const &v) const {
				e.do_setopt_function(what, v.is_undefined_or_null());
			}
		private:
			CURLoption what;
		};

		options_map_t const &get_options() {
			static options_map_t map;
			if(map.empty()) {
				boost::assign::ptr_map_insert<integer_option>(map)
					("verbose", CURLOPT_VERBOSE)
					("header", CURLOPT_HEADER)
					("noProgress", CURLOPT_NOPROGRESS)
					("noSignal", CURLOPT_NOSIGNAL);
				boost::assign::ptr_map_insert<function_option>(map)
					("writeFunction", CURLOPT_WRITEFUNCTION);
				boost::assign::ptr_map_insert<string_option>(map)
					("url", CURLOPT_URL);
			}
			return map;
		}
	}

	bool EasyOpt::property_resolve(value const &id, unsigned) {
		std::string const name = id.to_std_string();
		options_map_t::const_iterator const i = get_options().find(name);
		if(i != get_options().end()) {
			define_property(id.get_string(), i->second->default_value(),
											i->second->default_attributes());
			return true;
		}
		else {
			return false;
		}
	}

  FLUSSPFERD_LOADER_SIMPLE(cURL) {
    local_root_scope scope;

    cURL.define_property("GLOBAL_ALL", value(CURL_GLOBAL_ALL),
                         read_only_property | permanent_property);
    cURL.define_property("GLOBAL_SSL", value(CURL_GLOBAL_SSL),
                         read_only_property | permanent_property);
    cURL.define_property("GLOBAL_WIN32", value(CURL_GLOBAL_WIN32),
                         read_only_property | permanent_property);
    cURL.define_property("GLOBAL_NOTHING", value(CURL_GLOBAL_NOTHING),
                         read_only_property | permanent_property);
    create_native_function(cURL, "globalInit", &global_init);
    cURL.define_property("version", value(curl_version()),
                         read_only_property | permanent_property);
		load_class<EasyOpt>(cURL);
    load_class<Easy>(cURL);
  }
}
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "dump.hpp"

using namespace ckdb;

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include <unistd.h>

#include <kdberrors.h>
#include <kdblogger.h>

namespace dump
{

int serialise (std::ostream & os, ckdb::Key *, ckdb::KeySet * ks)
{
	ckdb::Key * cur;

	os << "kdbOpen 1" << std::endl;

	os << "ksNew " << ckdb::ksGetSize (ks) << std::endl;

	ckdb::KeySet * metacopies = ckdb::ksNew (0, KS_END);

	ksRewind (ks);
	while ((cur = ksNext (ks)) != nullptr)
	{
		size_t namesize = ckdb::keyGetNameSize (cur);
		size_t valuesize = ckdb::keyGetValueSize (cur);
		os << "keyNew " << namesize << " " << valuesize << std::endl;
		os.write (ckdb::keyName (cur), namesize);
		os.write (static_cast<const char *> (ckdb::keyValue (cur)), valuesize);
		os << std::endl;

		const ckdb::Key * meta;
		ckdb::keyRewindMeta (cur);
		while ((meta = ckdb::keyNextMeta (cur)) != nullptr)
		{
			std::stringstream ss;
			ss << "user/" << meta; // use the address of pointer as name

			ckdb::Key * search = ckdb::keyNew (ss.str ().c_str (), KEY_END);
			ckdb::Key * ret = ksLookup (metacopies, search, 0);

			if (!ret)
			{
				/* This metakey was not serialised up to now */
				size_t metanamesize = ckdb::keyGetNameSize (meta);
				size_t metavaluesize = ckdb::keyGetValueSize (meta);

				os << "keyMeta " << metanamesize << " " << metavaluesize << std::endl;
				os.write (ckdb::keyName (meta), metanamesize);
				os.write (static_cast<const char *> (ckdb::keyValue (meta)), metavaluesize);
				os << std::endl;

				std::stringstream ssv;
				ssv << namesize << " " << metanamesize << std::endl;
				ssv.write (ckdb::keyName (cur), namesize);
				ssv.write (ckdb::keyName (meta), metanamesize);
				ckdb::keySetRaw (search, ssv.str ().c_str (), ssv.str ().size ());

				ksAppendKey (metacopies, search);
			}
			else
			{
				/* Meta key already serialised, write out a reference to it */
				keyDel (search);

				os << "keyCopyMeta ";
				os.write (static_cast<const char *> (ckdb::keyValue (ret)), ckdb::keyGetValueSize (ret));
				os << std::endl;
			}
		}
		os << "keyEnd" << std::endl;
	}
	os << "ksEnd" << std::endl;

	ksDel (metacopies);

	return 1;
}

int unserialise (std::istream & is, ckdb::Key * errorKey, ckdb::KeySet * ks)
{
	ckdb::Key * cur = nullptr;

	std::vector<char> namebuffer (4048);
	std::vector<char> valuebuffer (4048);
	std::string line;
	std::string command;
	size_t nrKeys;
	size_t namesize;
	size_t valuesize;

	while (std::getline (is, line))
	{
		std::stringstream ss (line);
		ss >> command;

		if (command == "kdbOpen")
		{
			std::string version;
			ss >> version;
			if (version != "1")
			{
				ELEKTRA_SET_ERROR (50, errorKey, version.c_str ());
				return -1;
			}
		}
		else if (command == "ksNew")
		{
			ss >> nrKeys;

			ksClear (ks);
		}
		else if (command == "keyNew")
		{
			cur = ckdb::keyNew (nullptr);

			ss >> namesize;
			ss >> valuesize;

			if (namesize > namebuffer.size ()) namebuffer.resize (namesize + 1);
			is.read (&namebuffer[0], namesize);
			namebuffer[namesize] = 0;
			ckdb::keySetName (cur, &namebuffer[0]);

			if (valuesize > valuebuffer.size ()) valuebuffer.resize (valuesize + 1);
			is.read (&valuebuffer[0], valuesize);
			valuebuffer[valuesize] = 0;

			ckdb::keySetRaw (cur, &valuebuffer[0], valuesize);
			std::getline (is, line);
		}
		else if (command == "keyMeta")
		{
			ss >> namesize;
			ss >> valuesize;

			if (namesize > namebuffer.size ()) namebuffer.resize (namesize + 1);
			is.read (&namebuffer[0], namesize);
			namebuffer[namesize] = 0;

			if (valuesize > valuebuffer.size ()) valuebuffer.resize (valuesize + 1);
			is.read (&valuebuffer[0], valuesize);
			valuebuffer[valuesize] = 0;

			keySetMeta (cur, &namebuffer[0], &valuebuffer[0]);
			std::getline (is, line);
		}
		else if (command == "keyCopyMeta")
		{
			ss >> namesize;
			ss >> valuesize;

			if (namesize > namebuffer.size ()) namebuffer.resize (namesize + 1);
			is.read (&namebuffer[0], namesize);
			namebuffer[namesize] = 0;

			if (valuesize > valuebuffer.size ()) valuebuffer.resize (valuesize + 1);
			is.read (&valuebuffer[0], valuesize);
			valuebuffer[valuesize] = 0;

			ckdb::Key * search = ckdb::ksLookupByName (ks, &namebuffer[0], 0);
			ckdb::keyCopyMeta (cur, search, &valuebuffer[0]);
			std::getline (is, line);
		}
		else if (command == "keyEnd")
		{
			ckdb::ksAppendKey (ks, cur);
			cur = nullptr;
		}
		else if (command == "ksEnd")
		{
			break;
		}
		else
		{
			ELEKTRA_SET_ERRORF (49, errorKey, "found command %s", command.c_str ());
			return -1;
		}
	}
	return 1;
}

class pipebuf : public std::streambuf
{
	char * buffer_;
	int fd_;

public:
	pipebuf (int fd) : buffer_ (new char[4096]), fd_ (fd)
	{
	}
	~pipebuf ()
	{
		delete[] this->buffer_;
	}
	int underflow ()
	{
		if (this->gptr () == this->egptr ())
		{
			// read from the pipe directly into the buffer
			ssize_t r = read (fd_, buffer_, 4096);
			this->setg (this->buffer_, this->buffer_, this->buffer_ + r);
		}
		return this->gptr () == this->egptr () ? std::char_traits<char>::eof () :
							 std::char_traits<char>::to_int_type (*this->gptr ());
	}
};

} // namespace dump

extern "C" {

int elektraDumpGet (ckdb::Plugin *, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
	Key * root = ckdb::keyNew ("system/elektra/modules/dump", KEY_END);
	if (keyRel (root, parentKey) >= 0)
	{
		keyDel (root);
		KeySet * n = ksNew (50, keyNew ("system/elektra/modules/dump", KEY_VALUE, "dump plugin waits for your orders", KEY_END),
				    keyNew ("system/elektra/modules/dump/exports", KEY_END),
				    keyNew ("system/elektra/modules/dump/exports/get", KEY_FUNC, elektraDumpGet, KEY_END),
				    keyNew ("system/elektra/modules/dump/exports/set", KEY_FUNC, elektraDumpSet, KEY_END),
				    keyNew ("system/elektra/modules/dump/exports/serialise", KEY_FUNC, dump::serialise, KEY_END),
				    keyNew ("system/elektra/modules/dump/exports/unserialise", KEY_FUNC, dump::unserialise, KEY_END),
				    keyNew ("system/elektra/modules/dump/config/needs/fcrypt/textmode", KEY_VALUE, "0", KEY_END),
#include "readme_dump.c"
				    keyNew ("system/elektra/modules/dump/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
		ksAppend (returned, n);
		ksDel (n);
		return 1;
	}
	keyDel (root);
	int errnosave = errno;

	// We use dump for the pluginprocess library. Unfortunately on macOS reading from /dev/fd/<fd> via
	// ifstream fails, thus we read directly from unnamed pipes using a custom buffer and read
	const char pipe[] = "/dev/fd/";
	if (!strncmp (keyString (parentKey), pipe, strlen (pipe)))
	{
		int fd = std::stoi (std::string (keyString (parentKey) + strlen (pipe)));
		dump::pipebuf pipebuf (fd);
		std::istream is (&pipebuf);
		return dump::unserialise (is, parentKey, returned);
	}
	else
	{
		// ELEKTRA_LOG (ELEKTRA_LOG_MODULE_DUMP, "opening file %s", keyString (parentKey));
		std::ifstream is (keyString (parentKey), std::ios::binary);

		if (!is.is_open ())
		{
			ELEKTRA_SET_ERROR_GET (parentKey);
			errno = errnosave;
			return -1;
		}

		return dump::unserialise (is, parentKey, returned);
	}
}

int elektraDumpSet (ckdb::Plugin *, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
	int errnosave = errno;
	// ELEKTRA_LOG (ELEKTRA_LOG_MODULE_DUMP, "opening file %s", keyString (parentKey));
	std::ofstream ofs (keyString (parentKey), std::ios::binary);
	if (!ofs.is_open ())
	{
		ELEKTRA_SET_ERROR_SET (parentKey);
		errno = errnosave;
		return -1;
	}

	return dump::serialise (ofs, parentKey, returned);
}

ckdb::Plugin * ELEKTRA_PLUGIN_EXPORT (dump)
{
	// clang-format off
	return elektraPluginExport("dump",
		ELEKTRA_PLUGIN_GET,		&elektraDumpGet,
		ELEKTRA_PLUGIN_SET,		&elektraDumpSet,
		ELEKTRA_PLUGIN_END);
}

} // extern C

<commit_msg>Revert "dump: say which command was found"<commit_after>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "dump.hpp"

using namespace ckdb;

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include <unistd.h>

#include <kdberrors.h>
#include <kdblogger.h>

namespace dump
{

int serialise (std::ostream & os, ckdb::Key *, ckdb::KeySet * ks)
{
	ckdb::Key * cur;

	os << "kdbOpen 1" << std::endl;

	os << "ksNew " << ckdb::ksGetSize (ks) << std::endl;

	ckdb::KeySet * metacopies = ckdb::ksNew (0, KS_END);

	ksRewind (ks);
	while ((cur = ksNext (ks)) != nullptr)
	{
		size_t namesize = ckdb::keyGetNameSize (cur);
		size_t valuesize = ckdb::keyGetValueSize (cur);
		os << "keyNew " << namesize << " " << valuesize << std::endl;
		os.write (ckdb::keyName (cur), namesize);
		os.write (static_cast<const char *> (ckdb::keyValue (cur)), valuesize);
		os << std::endl;

		const ckdb::Key * meta;
		ckdb::keyRewindMeta (cur);
		while ((meta = ckdb::keyNextMeta (cur)) != nullptr)
		{
			std::stringstream ss;
			ss << "user/" << meta; // use the address of pointer as name

			ckdb::Key * search = ckdb::keyNew (ss.str ().c_str (), KEY_END);
			ckdb::Key * ret = ksLookup (metacopies, search, 0);

			if (!ret)
			{
				/* This metakey was not serialised up to now */
				size_t metanamesize = ckdb::keyGetNameSize (meta);
				size_t metavaluesize = ckdb::keyGetValueSize (meta);

				os << "keyMeta " << metanamesize << " " << metavaluesize << std::endl;
				os.write (ckdb::keyName (meta), metanamesize);
				os.write (static_cast<const char *> (ckdb::keyValue (meta)), metavaluesize);
				os << std::endl;

				std::stringstream ssv;
				ssv << namesize << " " << metanamesize << std::endl;
				ssv.write (ckdb::keyName (cur), namesize);
				ssv.write (ckdb::keyName (meta), metanamesize);
				ckdb::keySetRaw (search, ssv.str ().c_str (), ssv.str ().size ());

				ksAppendKey (metacopies, search);
			}
			else
			{
				/* Meta key already serialised, write out a reference to it */
				keyDel (search);

				os << "keyCopyMeta ";
				os.write (static_cast<const char *> (ckdb::keyValue (ret)), ckdb::keyGetValueSize (ret));
				os << std::endl;
			}
		}
		os << "keyEnd" << std::endl;
	}
	os << "ksEnd" << std::endl;

	ksDel (metacopies);

	return 1;
}

int unserialise (std::istream & is, ckdb::Key * errorKey, ckdb::KeySet * ks)
{
	ckdb::Key * cur = nullptr;

	std::vector<char> namebuffer (4048);
	std::vector<char> valuebuffer (4048);
	std::string line;
	std::string command;
	size_t nrKeys;
	size_t namesize;
	size_t valuesize;

	while (std::getline (is, line))
	{
		std::stringstream ss (line);
		ss >> command;

		if (command == "kdbOpen")
		{
			std::string version;
			ss >> version;
			if (version != "1")
			{
				ELEKTRA_SET_ERROR (50, errorKey, version.c_str ());
				return -1;
			}
		}
		else if (command == "ksNew")
		{
			ss >> nrKeys;

			ksClear (ks);
		}
		else if (command == "keyNew")
		{
			cur = ckdb::keyNew (nullptr);

			ss >> namesize;
			ss >> valuesize;

			if (namesize > namebuffer.size ()) namebuffer.resize (namesize + 1);
			is.read (&namebuffer[0], namesize);
			namebuffer[namesize] = 0;
			ckdb::keySetName (cur, &namebuffer[0]);

			if (valuesize > valuebuffer.size ()) valuebuffer.resize (valuesize + 1);
			is.read (&valuebuffer[0], valuesize);
			valuebuffer[valuesize] = 0;

			ckdb::keySetRaw (cur, &valuebuffer[0], valuesize);
			std::getline (is, line);
		}
		else if (command == "keyMeta")
		{
			ss >> namesize;
			ss >> valuesize;

			if (namesize > namebuffer.size ()) namebuffer.resize (namesize + 1);
			is.read (&namebuffer[0], namesize);
			namebuffer[namesize] = 0;

			if (valuesize > valuebuffer.size ()) valuebuffer.resize (valuesize + 1);
			is.read (&valuebuffer[0], valuesize);
			valuebuffer[valuesize] = 0;

			keySetMeta (cur, &namebuffer[0], &valuebuffer[0]);
			std::getline (is, line);
		}
		else if (command == "keyCopyMeta")
		{
			ss >> namesize;
			ss >> valuesize;

			if (namesize > namebuffer.size ()) namebuffer.resize (namesize + 1);
			is.read (&namebuffer[0], namesize);
			namebuffer[namesize] = 0;

			if (valuesize > valuebuffer.size ()) valuebuffer.resize (valuesize + 1);
			is.read (&valuebuffer[0], valuesize);
			valuebuffer[valuesize] = 0;

			ckdb::Key * search = ckdb::ksLookupByName (ks, &namebuffer[0], 0);
			ckdb::keyCopyMeta (cur, search, &valuebuffer[0]);
			std::getline (is, line);
		}
		else if (command == "keyEnd")
		{
			ckdb::ksAppendKey (ks, cur);
			cur = nullptr;
		}
		else if (command == "ksEnd")
		{
			break;
		}
		else
		{
			ELEKTRA_SET_ERROR (49, errorKey, command.c_str ());
			return -1;
		}
	}
	return 1;
}

class pipebuf : public std::streambuf
{
	char * buffer_;
	int fd_;

public:
	pipebuf (int fd) : buffer_ (new char[4096]), fd_ (fd)
	{
	}
	~pipebuf ()
	{
		delete[] this->buffer_;
	}
	int underflow ()
	{
		if (this->gptr () == this->egptr ())
		{
			// read from the pipe directly into the buffer
			ssize_t r = read (fd_, buffer_, 4096);
			this->setg (this->buffer_, this->buffer_, this->buffer_ + r);
		}
		return this->gptr () == this->egptr () ? std::char_traits<char>::eof () :
							 std::char_traits<char>::to_int_type (*this->gptr ());
	}
};

} // namespace dump

extern "C" {

int elektraDumpGet (ckdb::Plugin *, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
	Key * root = ckdb::keyNew ("system/elektra/modules/dump", KEY_END);
	if (keyRel (root, parentKey) >= 0)
	{
		keyDel (root);
		KeySet * n = ksNew (50, keyNew ("system/elektra/modules/dump", KEY_VALUE, "dump plugin waits for your orders", KEY_END),
				    keyNew ("system/elektra/modules/dump/exports", KEY_END),
				    keyNew ("system/elektra/modules/dump/exports/get", KEY_FUNC, elektraDumpGet, KEY_END),
				    keyNew ("system/elektra/modules/dump/exports/set", KEY_FUNC, elektraDumpSet, KEY_END),
				    keyNew ("system/elektra/modules/dump/exports/serialise", KEY_FUNC, dump::serialise, KEY_END),
				    keyNew ("system/elektra/modules/dump/exports/unserialise", KEY_FUNC, dump::unserialise, KEY_END),
				    keyNew ("system/elektra/modules/dump/config/needs/fcrypt/textmode", KEY_VALUE, "0", KEY_END),
#include "readme_dump.c"
				    keyNew ("system/elektra/modules/dump/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
		ksAppend (returned, n);
		ksDel (n);
		return 1;
	}
	keyDel (root);
	int errnosave = errno;

	// We use dump for the pluginprocess library. Unfortunately on macOS reading from /dev/fd/<fd> via
	// ifstream fails, thus we read directly from unnamed pipes using a custom buffer and read
	const char pipe[] = "/dev/fd/";
	if (!strncmp (keyString (parentKey), pipe, strlen (pipe)))
	{
		int fd = std::stoi (std::string (keyString (parentKey) + strlen (pipe)));
		dump::pipebuf pipebuf (fd);
		std::istream is (&pipebuf);
		return dump::unserialise (is, parentKey, returned);
	}
	else
	{
		// ELEKTRA_LOG (ELEKTRA_LOG_MODULE_DUMP, "opening file %s", keyString (parentKey));
		std::ifstream is (keyString (parentKey), std::ios::binary);

		if (!is.is_open ())
		{
			ELEKTRA_SET_ERROR_GET (parentKey);
			errno = errnosave;
			return -1;
		}

		return dump::unserialise (is, parentKey, returned);
	}
}

int elektraDumpSet (ckdb::Plugin *, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
	int errnosave = errno;
	// ELEKTRA_LOG (ELEKTRA_LOG_MODULE_DUMP, "opening file %s", keyString (parentKey));
	std::ofstream ofs (keyString (parentKey), std::ios::binary);
	if (!ofs.is_open ())
	{
		ELEKTRA_SET_ERROR_SET (parentKey);
		errno = errnosave;
		return -1;
	}

	return dump::serialise (ofs, parentKey, returned);
}

ckdb::Plugin * ELEKTRA_PLUGIN_EXPORT (dump)
{
	// clang-format off
	return elektraPluginExport("dump",
		ELEKTRA_PLUGIN_GET,		&elektraDumpGet,
		ELEKTRA_PLUGIN_SET,		&elektraDumpSet,
		ELEKTRA_PLUGIN_END);
}

} // extern C

<|endoftext|>


<commit_before>/**
* Copyright (C) Mellanox Technologies Ltd. 2001-2015.  ALL RIGHTS RESERVED.
*
* $COPYRIGHT$
* $HEADER$
*/

#include "uct_test.h"
#include "ud_base.h"
extern "C" {
#include <ucs/time/time.h>
#include <ucs/datastruct/queue.h>
#include <uct/ib/ud/base/ud_ep.h>
#include <uct/ib/ud/base/ud_iface.h>
};

class test_ud_pending : public ud_base_test {
public:
    uct_pending_req_t m_r[64];

    void dispatch_req(uct_pending_req_t *r) {
        EXPECT_UCS_OK(tx(m_e1));
    }

    void post_pending_reqs(void)
    {
        int i;

        req_count = 0;
        me = this;
        m_e1->connect_to_iface(0, *m_e2);
        set_tx_win(m_e1, UCT_UD_CA_MAX_WINDOW);
        /* ep is not connected yet */
        EXPECT_EQ(UCS_ERR_NO_RESOURCE, tx(m_e1));

        /* queuee some work */
        for(i = 0; i < N; i++) {
            m_r[i].func = pending_cb_dispatch;
            EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &m_r[i]));
        }
    }

    void check_pending_reqs(void)
    {
        /* all work should be complete */
        EXPECT_EQ(N, req_count);
        uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
    }

    static const int N;
    static const int W;
    static int req_count;
    static test_ud_pending *me;

    static ucs_status_t pending_cb_dispatch(uct_pending_req_t *r)
    {
        req_count++;
        me->dispatch_req(r);
        return UCS_OK;
    }

    static ucs_status_t pending_cb(uct_pending_req_t *r)
    {
        req_count++;
        return UCS_OK;
    }

    static void purge_cb(uct_pending_req_t *r, void *arg)
    {
        req_count++;
    }

    static ucs_status_t pending_cb_busy(uct_pending_req_t *r)
    {
        return UCS_ERR_BUSY;
    }

};

const int test_ud_pending::N = 13;
const int test_ud_pending::W = 6;
int test_ud_pending::req_count = 0;
test_ud_pending *test_ud_pending::me = 0;

/* add/purge requests */
UCS_TEST_P(test_ud_pending, async_progress) {
    uct_pending_req_t r[N];
    int i;

    req_count = 0;
    connect();

    set_tx_win(m_e1, 2);
    EXPECT_UCS_OK(tx(m_e1));

    for(i = 0; i < N; i++) {
        EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &r[i]));
    }
    twait(300);
    /* requests must not be dispatched from async progress */
    EXPECT_EQ(0, req_count);
    uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
    EXPECT_EQ(N, req_count);
}

UCS_TEST_P(test_ud_pending, sync_progress) {
    uct_pending_req_t r[N];
    int i;

    req_count = 0;
    connect();

    set_tx_win(m_e1, 2);
    EXPECT_UCS_OK(tx(m_e1));

    for(i = 0; i < N; i++) {
        r[i].func = pending_cb;
        EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &r[i]));
    }
    short_progress_loop();
    /* requests must be dispatched from progress */
    EXPECT_EQ(N, req_count);
    uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
    EXPECT_EQ(N, req_count);
}

UCS_TEST_P(test_ud_pending, err_busy) {
    uct_pending_req_t r[N];
    int i;

    req_count = 0;
    connect();

    set_tx_win(m_e1, 2);
    EXPECT_UCS_OK(tx(m_e1));

    for(i = 0; i < N; i++) {
        r[i].func = pending_cb_busy;
        EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &r[i]));
    }
    short_progress_loop();
    /* requests will not be dispatched from progress */
    EXPECT_EQ(0, req_count);
    uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
    EXPECT_EQ(N, req_count);
}

UCS_TEST_P(test_ud_pending, connect)
{
    disable_async(m_e1);
    disable_async(m_e2);
    post_pending_reqs();
    short_progress_loop(TEST_UD_PROGRESS_TIMEOUT);
    check_pending_reqs();
}

UCS_TEST_P(test_ud_pending, flush)
{
    disable_async(m_e1);
    disable_async(m_e2);
    post_pending_reqs();
    flush();
    check_pending_reqs();
}

UCS_TEST_P(test_ud_pending, window)
{
    int i;
    uct_pending_req_t r;
    req_count = 0;
    me = this;
    connect();
    set_tx_win(m_e1, W+1);
    for (i = 0; i < W; i ++) {
        EXPECT_UCS_OK(tx(m_e1));
    }
    EXPECT_EQ(UCS_ERR_NO_RESOURCE, tx(m_e1));
    r.func = pending_cb_dispatch;
    EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &r));
    short_progress_loop();
    EXPECT_EQ(1, req_count);
    uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
}

UCS_TEST_P(test_ud_pending, tx_wqe)
{
    int i;
    uct_pending_req_t r;
    ucs_status_t status;
    req_count = 0;
    me = this;
    disable_async(m_e1);
    disable_async(m_e2);
    connect();
    /* set big window */
    set_tx_win(m_e1, 8192);
    i = 0;
    do {
       status = tx(m_e1);
       i++;
    } while (status == UCS_OK);

    r.func = pending_cb_dispatch;
    EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &r));
    short_progress_loop();
    EXPECT_EQ(1, req_count);
    short_progress_loop();
    uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
}

_UCT_INSTANTIATE_TEST_CASE(test_ud_pending, ud)
_UCT_INSTANTIATE_TEST_CASE(test_ud_pending, ud_mlx5)

<commit_msg>TEST/UD: Wait for pending to be sent.<commit_after>/**
* Copyright (C) Mellanox Technologies Ltd. 2001-2015.  ALL RIGHTS RESERVED.
*
* $COPYRIGHT$
* $HEADER$
*/

#include "uct_test.h"
#include "ud_base.h"
extern "C" {
#include <ucs/time/time.h>
#include <ucs/datastruct/queue.h>
#include <uct/ib/ud/base/ud_ep.h>
#include <uct/ib/ud/base/ud_iface.h>
};

class test_ud_pending : public ud_base_test {
public:
    uct_pending_req_t m_r[64];

    void dispatch_req(uct_pending_req_t *r) {
        EXPECT_UCS_OK(tx(m_e1));
    }

    void post_pending_reqs(void)
    {
        int i;

        req_count = 0;
        me = this;
        m_e1->connect_to_iface(0, *m_e2);
        set_tx_win(m_e1, UCT_UD_CA_MAX_WINDOW);
        /* ep is not connected yet */
        EXPECT_EQ(UCS_ERR_NO_RESOURCE, tx(m_e1));

        /* queuee some work */
        for(i = 0; i < N; i++) {
            m_r[i].func = pending_cb_dispatch;
            EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &m_r[i]));
        }
    }

    void check_pending_reqs(bool wait)
    {
        /* wait for all work to be complete */
        while (wait && (req_count < N)) {
            progress();
        }
        EXPECT_EQ(N, req_count);
        uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
    }

    static const int N;
    static const int W;
    static int req_count;
    static test_ud_pending *me;

    static ucs_status_t pending_cb_dispatch(uct_pending_req_t *r)
    {
        req_count++;
        me->dispatch_req(r);
        return UCS_OK;
    }

    static ucs_status_t pending_cb(uct_pending_req_t *r)
    {
        req_count++;
        return UCS_OK;
    }

    static void purge_cb(uct_pending_req_t *r, void *arg)
    {
        req_count++;
    }

    static ucs_status_t pending_cb_busy(uct_pending_req_t *r)
    {
        return UCS_ERR_BUSY;
    }

};

const int test_ud_pending::N = 13;
const int test_ud_pending::W = 6;
int test_ud_pending::req_count = 0;
test_ud_pending *test_ud_pending::me = 0;

/* add/purge requests */
UCS_TEST_P(test_ud_pending, async_progress) {
    uct_pending_req_t r[N];
    int i;

    req_count = 0;
    connect();

    set_tx_win(m_e1, 2);
    EXPECT_UCS_OK(tx(m_e1));

    for(i = 0; i < N; i++) {
        EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &r[i]));
    }
    twait(300);
    /* requests must not be dispatched from async progress */
    EXPECT_EQ(0, req_count);
    uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
    EXPECT_EQ(N, req_count);
}

UCS_TEST_P(test_ud_pending, sync_progress) {
    uct_pending_req_t r[N];
    int i;

    req_count = 0;
    connect();

    set_tx_win(m_e1, 2);
    EXPECT_UCS_OK(tx(m_e1));

    for(i = 0; i < N; i++) {
        r[i].func = pending_cb;
        EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &r[i]));
    }
    short_progress_loop();
    /* requests must be dispatched from progress */
    EXPECT_EQ(N, req_count);
    uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
    EXPECT_EQ(N, req_count);
}

UCS_TEST_P(test_ud_pending, err_busy) {
    uct_pending_req_t r[N];
    int i;

    req_count = 0;
    connect();

    set_tx_win(m_e1, 2);
    EXPECT_UCS_OK(tx(m_e1));

    for(i = 0; i < N; i++) {
        r[i].func = pending_cb_busy;
        EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &r[i]));
    }
    short_progress_loop();
    /* requests will not be dispatched from progress */
    EXPECT_EQ(0, req_count);
    uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
    EXPECT_EQ(N, req_count);
}

UCS_TEST_P(test_ud_pending, connect)
{
    disable_async(m_e1);
    disable_async(m_e2);
    post_pending_reqs();
    check_pending_reqs(true);
}

UCS_TEST_P(test_ud_pending, flush)
{
    disable_async(m_e1);
    disable_async(m_e2);
    post_pending_reqs();
    flush();
    check_pending_reqs(false);
}

UCS_TEST_P(test_ud_pending, window)
{
    int i;
    uct_pending_req_t r;
    req_count = 0;
    me = this;
    connect();
    set_tx_win(m_e1, W+1);
    for (i = 0; i < W; i ++) {
        EXPECT_UCS_OK(tx(m_e1));
    }
    EXPECT_EQ(UCS_ERR_NO_RESOURCE, tx(m_e1));
    r.func = pending_cb_dispatch;
    EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &r));
    short_progress_loop();
    EXPECT_EQ(1, req_count);
    uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
}

UCS_TEST_P(test_ud_pending, tx_wqe)
{
    int i;
    uct_pending_req_t r;
    ucs_status_t status;
    req_count = 0;
    me = this;
    disable_async(m_e1);
    disable_async(m_e2);
    connect();
    /* set big window */
    set_tx_win(m_e1, 8192);
    i = 0;
    do {
       status = tx(m_e1);
       i++;
    } while (status == UCS_OK);

    r.func = pending_cb_dispatch;
    EXPECT_EQ(UCS_OK, uct_ep_pending_add(m_e1->ep(0), &r));
    short_progress_loop();
    EXPECT_EQ(1, req_count);
    short_progress_loop();
    uct_ep_pending_purge(m_e1->ep(0), purge_cb, NULL);
}

_UCT_INSTANTIATE_TEST_CASE(test_ud_pending, ud)
_UCT_INSTANTIATE_TEST_CASE(test_ud_pending, ud_mlx5)

<|endoftext|>


<commit_before>#include "ofp/unittest.h"
#include "ofp/yaml/decoder.h"

using namespace ofp;
using namespace ofp::yaml;

static void testDecodeFail(const char *hex, const char *err) {
  auto s = HexToRawData(hex);

  MessageInfo msgInfo;
  Message msg{s.data(), s.size()};
  msg.setInfo(&msgInfo);
  msg.transmogrify();

  log::debug("msg=", msg);

  Decoder decoder{&msg};

  EXPECT_EQ(err, decoder.error());
  EXPECT_EQ("", decoder.result());
}

TEST(decoderfail, malformed_port_desc_v1) {
  testDecodeFail("011500189C3CBB55000D00000000000089A6001000080000",
                 "Range element size overruns end");
}

TEST(decoderfail, malformed_port_desc_v2) {
  testDecodeFail("021700189C3CBB55000D00000000000089A6001000080000",
                 "Range element size overruns end");
}
<commit_msg>Add copyright.<commit_after>// Copyright 2015-present Bill Fisher. All rights reserved.

#include "ofp/unittest.h"
#include "ofp/yaml/decoder.h"

using namespace ofp;
using namespace ofp::yaml;

static void testDecodeFail(const char *hex, const char *err) {
  auto s = HexToRawData(hex);

  MessageInfo msgInfo;
  Message msg{s.data(), s.size()};
  msg.setInfo(&msgInfo);
  msg.transmogrify();

  log::debug("msg=", msg);

  Decoder decoder{&msg};

  EXPECT_EQ(err, decoder.error());
  EXPECT_EQ("", decoder.result());
}

TEST(decoderfail, malformed_port_desc_v1) {
  testDecodeFail("011500189C3CBB55000D00000000000089A6001000080000",
                 "Range element size overruns end");
}

TEST(decoderfail, malformed_port_desc_v2) {
  testDecodeFail("021700189C3CBB55000D00000000000089A6001000080000",
                 "Range element size overruns end");
}
<|endoftext|>


<commit_before>#include <v8.h>
#include <node.h>
#include <node_buffer.h>

#include <sstream>
#include <cstring>
#include <string>

#include "BoyerMoore.h"

using namespace v8;
using namespace node;

namespace {

// this is an application of the Curiously Recurring Template Pattern
template <class Derived> struct UnaryAction {
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope);

	Handle<Value> operator()(const Arguments& args) {
		HandleScope scope;

		Local<Object> self = args.This();
		if (!Buffer::HasInstance(self)) {
			return ThrowException(Exception::TypeError(String::New(
					"Argument should be a buffer object.")));
		}

		return static_cast<Derived*>(this)->apply(self, args, scope);
	}
};

template <class Derived> struct BinaryAction {
	Handle<Value> apply(Handle<Object>& buffer, const char* data, size_t size, const Arguments& args, HandleScope& scope);

	Handle<Value> operator()(const Arguments& args) {
		HandleScope scope;

		Local<Object> self = args.This();
		if (!Buffer::HasInstance(self)) {
			return ThrowException(Exception::TypeError(String::New(
					"Argument should be a buffer object.")));
		}

		if (args[0]->IsString()) {
			String::Utf8Value s(args[0]->ToString());
			return static_cast<Derived*>(this)->apply(self, *s, s.length(), args, scope);
		}
		if (Buffer::HasInstance(args[0])) {
			Local<Object> other = args[0]->ToObject();
			return static_cast<Derived*>(this)->apply(
					self, Buffer::Data(other), Buffer::Length(other), args, scope);
		}

		static Persistent<String> illegalArgumentException = Persistent<String>::New(String::New(
				"Second argument must be a string or a buffer."));
		return ThrowException(Exception::TypeError(illegalArgumentException));
	}
};

//
// helper functions
//
Handle<Value> clear(Handle<Object>& buffer, int c) {
	size_t length = Buffer::Length(buffer);
	char* data = Buffer::Data(buffer);
	memset(data, c, length);
	return buffer;
}

Handle<Value> fill(Handle<Object>& buffer, void* pattern, size_t size) {
	size_t length = Buffer::Length(buffer);
	char* data = Buffer::Data(buffer);

	if (size >= length) {
		memcpy(data, pattern, length);
	} else {
		const int n_copies = length / size;
		const int remainder = length % size;
		for (int i = 0; i < n_copies; i++) {
			memcpy(data + size * i, pattern, size);
		}
		memcpy(data + size * n_copies, pattern, remainder);
	}

	return buffer;
}

int compare(Handle<Object>& buffer, const char* data2, size_t length2) {
	size_t length = Buffer::Length(buffer);
	if (length != length2) {
		return length > length2 ? 1 : -1;
	}

	char* data = Buffer::Data(buffer);
	return memcmp(data, data2, length);
}

//
// actions
//
struct ClearAction: UnaryAction<ClearAction> {
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope) {
		return clear(buffer, 0);
	}
};

struct FillAction: UnaryAction<FillAction> {
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope) {
		if (args[0]->IsInt32()) {
			int c = args[0]->ToInt32()->Int32Value();
			return clear(buffer, c);
		}

		if (args[0]->IsString()) {
			String::Utf8Value s(args[0]->ToString());
			return fill(buffer, *s, s.length());
		}

		if (Buffer::HasInstance(args[0])) {
			Handle<Object> other = args[0]->ToObject();
			size_t length = Buffer::Length(other);
			char* data = Buffer::Data(other);
			return fill(buffer, data, length);
		}

		static Persistent<String> illegalArgumentException = Persistent<String>::New(String::New(
				"Second argument should be either a string, a buffer or an integer."));
		return ThrowException(Exception::TypeError(illegalArgumentException));
	}
};

struct ReverseAction: UnaryAction<ReverseAction> {
	// O(n/2) for all cases which is okay, might be optimized some more with whole-word swaps
	// XXX won't this trash the L1 cache something awful?
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope) {
		char* head = Buffer::Data(buffer);
		char* tail = head + Buffer::Length(buffer) - 1;

		// xor swap, just because I can
		while (head < tail) *head ^= *tail, *tail ^= *head, *head ^= *tail, ++head, --tail;

		return buffer;
	}
};

struct EqualsAction: BinaryAction<EqualsAction> {
	Handle<Value> apply(Handle<Object>& buffer, const char* data, size_t size, const Arguments& args, HandleScope& scope) {
		return compare(buffer, data, size) == 0 ? True() : False();
	}
};

struct CompareAction: BinaryAction<CompareAction> {
	Handle<Value> apply(Handle<Object>& buffer, const char* data, size_t size, const Arguments& args, HandleScope& scope) {
		return scope.Close(Integer::New(compare(buffer, data, size)));
	}
};

struct IndexOfAction: BinaryAction<IndexOfAction> {
	Handle<Value> apply(Handle<Object>& buffer, const char* data2, size_t size2, const Arguments& args, HandleScope& scope) {
		const char* data = Buffer::Data(buffer);
		size_t size = Buffer::Length(buffer);

		const char* p = boyermoore_search(data, size, data2, size2);
		const ptrdiff_t offset = p ? (p - data) : -1;

		return scope.Close(Integer::New(offset));
	}
};

static char toHexTable[] = "0123456789abcdef";

// CHECKME is this cache efficient?
static char fromHexTable[] = {
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,
		10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
};

inline Handle<Value> decodeHex(const char* data, size_t size, const Arguments& args, HandleScope& scope) {
	if (size & 1) {
		return ThrowException(Exception::Error(String::New(
				"Odd string length, this is not hexadecimal data.")));
	}

	if (size == 0) {
		return String::Empty();
	}

	Handle<Object>& buffer = Buffer::New(size / 2)->handle_;
	for (char* s = Buffer::Data(buffer); size > 0; size -= 2) {
		int a = fromHexTable[*data++];
		int b = fromHexTable[*data++];

		if (a == -1 || b == -1) {
			return ThrowException(Exception::Error(String::New(
					"This is not hexadecimal data.")));
		}

		*s++ = b | (a << 4);
	}

	return buffer;
}

struct FromHexAction: UnaryAction<FromHexAction> {
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope) {
		const char* data = Buffer::Data(buffer);
		size_t length = Buffer::Length(buffer);
		return decodeHex(data, length, args, scope);
	}
};

struct ToHexAction: UnaryAction<ToHexAction> {
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope) {
		const size_t size = Buffer::Length(buffer);
		const char* data = Buffer::Data(buffer);

		if (size == 0) {
			return String::Empty();
		}

		std::string s(size * 2, 0);
		for (size_t i = 0; i < size; ++i) {
			const int c = data[i];
			s[i * 2] = toHexTable[c >> 4];
			s[i * 2 + 1] = toHexTable[c & 15];
		}

		return scope.Close(String::New(s.c_str(), s.size()));
	}
};

//
// V8 function callbacks
//
Handle<Value> Clear(const Arguments& args) {
	return ClearAction()(args);
}

Handle<Value> Fill(const Arguments& args) {
	return FillAction()(args);
}

Handle<Value> Reverse(const Arguments& args) {
	return ReverseAction()(args);
}

Handle<Value> Equals(const Arguments& args) {
	return EqualsAction()(args);
}

Handle<Value> Compare(const Arguments& args) {
	return CompareAction()(args);
}

Handle<Value> IndexOf(const Arguments& args) {
	return IndexOfAction()(args);
}

Handle<Value> FromHex(const Arguments& args) {
	return FromHexAction()(args);
}

Handle<Value> ToHex(const Arguments& args) {
	return ToHexAction()(args);
}

Handle<Value> Concat(const Arguments& args) {
	HandleScope scope;

	size_t size = 0;
	for (int index = 0, length = args.Length(); index < length; ++index) {
		Local<Value> arg = args[index];
		if (arg->IsString()) {
			// Utf8Length() because we need the length in bytes, not characters
			size += arg->ToString()->Utf8Length();
		}
		else if (Buffer::HasInstance(arg)) {
			size += Buffer::Length(arg->ToObject());
		}
		else {
			std::stringstream s;
			s << "Argument #" << index << " is neither a string nor a buffer object.";
			const char* message = s.str().c_str();
			return ThrowException(Exception::TypeError(String::New(message)));
		}
	}

	Buffer& dst = *Buffer::New(size);
	char* s = Buffer::Data(dst.handle_);

	for (int index = 0, length = args.Length(); index < length; ++index) {
		Local<Value> arg = args[index];
		if (arg->IsString()) {
			String::Utf8Value v(arg->ToString());
			memcpy(s, *v, v.length());
			s += v.length();
		}
		else if (Buffer::HasInstance(arg)) {
			Local<Object> b = arg->ToObject();
			const char* data = Buffer::Data(b);
			size_t length = Buffer::Length(b);
			memcpy(s, data, length);
			s += length;
		}
		else {
			return ThrowException(Exception::Error(String::New(
					"Congratulations! You have run into a bug: argument is neither a string nor a buffer object. "
					"Please make the world a better place and report it.")));
		}
	}

	return scope.Close(dst.handle_);
}

void RegisterModule(Handle<Object> target) {
	target->Set(String::NewSymbol("concat"),  FunctionTemplate::New(Concat)->GetFunction());
	target->Set(String::NewSymbol("fill"),    FunctionTemplate::New(Fill)->GetFunction());
	target->Set(String::NewSymbol("clear"),   FunctionTemplate::New(Clear)->GetFunction());
	target->Set(String::NewSymbol("reverse"), FunctionTemplate::New(Reverse)->GetFunction());
	target->Set(String::NewSymbol("equals"),  FunctionTemplate::New(Equals)->GetFunction());
	target->Set(String::NewSymbol("compare"), FunctionTemplate::New(Compare)->GetFunction());
	target->Set(String::NewSymbol("indexOf"), FunctionTemplate::New(IndexOf)->GetFunction());
	target->Set(String::NewSymbol("fromHex"), FunctionTemplate::New(FromHex)->GetFunction());
	target->Set(String::NewSymbol("toHex"),   FunctionTemplate::New(ToHex)->GetFunction());
}

} // anonymous namespace

NODE_MODULE(buffertools, RegisterModule);
<commit_msg>Fixed a lookup table overflow with node.js 0.5.0-pre.<commit_after>#include <v8.h>
#include <node.h>
#include <node_buffer.h>

#include <sstream>
#include <cstring>
#include <string>

#include "BoyerMoore.h"

using namespace v8;
using namespace node;

namespace {

// this is an application of the Curiously Recurring Template Pattern
template <class Derived> struct UnaryAction {
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope);

	Handle<Value> operator()(const Arguments& args) {
		HandleScope scope;

		Local<Object> self = args.This();
		if (!Buffer::HasInstance(self)) {
			return ThrowException(Exception::TypeError(String::New(
					"Argument should be a buffer object.")));
		}

		return static_cast<Derived*>(this)->apply(self, args, scope);
	}
};

template <class Derived> struct BinaryAction {
	Handle<Value> apply(Handle<Object>& buffer, const char* data, size_t size, const Arguments& args, HandleScope& scope);

	Handle<Value> operator()(const Arguments& args) {
		HandleScope scope;

		Local<Object> self = args.This();
		if (!Buffer::HasInstance(self)) {
			return ThrowException(Exception::TypeError(String::New(
					"Argument should be a buffer object.")));
		}

		if (args[0]->IsString()) {
			String::Utf8Value s(args[0]->ToString());
			return static_cast<Derived*>(this)->apply(self, *s, s.length(), args, scope);
		}
		if (Buffer::HasInstance(args[0])) {
			Local<Object> other = args[0]->ToObject();
			return static_cast<Derived*>(this)->apply(
					self, Buffer::Data(other), Buffer::Length(other), args, scope);
		}

		static Persistent<String> illegalArgumentException = Persistent<String>::New(String::New(
				"Second argument must be a string or a buffer."));
		return ThrowException(Exception::TypeError(illegalArgumentException));
	}
};

//
// helper functions
//
Handle<Value> clear(Handle<Object>& buffer, int c) {
	size_t length = Buffer::Length(buffer);
	char* data = Buffer::Data(buffer);
	memset(data, c, length);
	return buffer;
}

Handle<Value> fill(Handle<Object>& buffer, void* pattern, size_t size) {
	size_t length = Buffer::Length(buffer);
	char* data = Buffer::Data(buffer);

	if (size >= length) {
		memcpy(data, pattern, length);
	} else {
		const int n_copies = length / size;
		const int remainder = length % size;
		for (int i = 0; i < n_copies; i++) {
			memcpy(data + size * i, pattern, size);
		}
		memcpy(data + size * n_copies, pattern, remainder);
	}

	return buffer;
}

int compare(Handle<Object>& buffer, const char* data2, size_t length2) {
	size_t length = Buffer::Length(buffer);
	if (length != length2) {
		return length > length2 ? 1 : -1;
	}

	char* data = Buffer::Data(buffer);
	return memcmp(data, data2, length);
}

//
// actions
//
struct ClearAction: UnaryAction<ClearAction> {
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope) {
		return clear(buffer, 0);
	}
};

struct FillAction: UnaryAction<FillAction> {
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope) {
		if (args[0]->IsInt32()) {
			int c = args[0]->ToInt32()->Int32Value();
			return clear(buffer, c);
		}

		if (args[0]->IsString()) {
			String::Utf8Value s(args[0]->ToString());
			return fill(buffer, *s, s.length());
		}

		if (Buffer::HasInstance(args[0])) {
			Handle<Object> other = args[0]->ToObject();
			size_t length = Buffer::Length(other);
			char* data = Buffer::Data(other);
			return fill(buffer, data, length);
		}

		static Persistent<String> illegalArgumentException = Persistent<String>::New(String::New(
				"Second argument should be either a string, a buffer or an integer."));
		return ThrowException(Exception::TypeError(illegalArgumentException));
	}
};

struct ReverseAction: UnaryAction<ReverseAction> {
	// O(n/2) for all cases which is okay, might be optimized some more with whole-word swaps
	// XXX won't this trash the L1 cache something awful?
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope) {
		char* head = Buffer::Data(buffer);
		char* tail = head + Buffer::Length(buffer) - 1;

		// xor swap, just because I can
		while (head < tail) *head ^= *tail, *tail ^= *head, *head ^= *tail, ++head, --tail;

		return buffer;
	}
};

struct EqualsAction: BinaryAction<EqualsAction> {
	Handle<Value> apply(Handle<Object>& buffer, const char* data, size_t size, const Arguments& args, HandleScope& scope) {
		return compare(buffer, data, size) == 0 ? True() : False();
	}
};

struct CompareAction: BinaryAction<CompareAction> {
	Handle<Value> apply(Handle<Object>& buffer, const char* data, size_t size, const Arguments& args, HandleScope& scope) {
		return scope.Close(Integer::New(compare(buffer, data, size)));
	}
};

struct IndexOfAction: BinaryAction<IndexOfAction> {
	Handle<Value> apply(Handle<Object>& buffer, const char* data2, size_t size2, const Arguments& args, HandleScope& scope) {
		const char* data = Buffer::Data(buffer);
		size_t size = Buffer::Length(buffer);

		const char* p = boyermoore_search(data, size, data2, size2);
		const ptrdiff_t offset = p ? (p - data) : -1;

		return scope.Close(Integer::New(offset));
	}
};

static char toHexTable[] = "0123456789abcdef";

// CHECKME is this cache efficient?
static char fromHexTable[] = {
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,
		10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
		-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
};

inline Handle<Value> decodeHex(const char* data, size_t size, const Arguments& args, HandleScope& scope) {
	if (size & 1) {
		return ThrowException(Exception::Error(String::New(
				"Odd string length, this is not hexadecimal data.")));
	}

	if (size == 0) {
		return String::Empty();
	}

	Handle<Object>& buffer = Buffer::New(size / 2)->handle_;
	for (char* s = Buffer::Data(buffer); size > 0; size -= 2) {
		int a = fromHexTable[*data++];
		int b = fromHexTable[*data++];

		if (a == -1 || b == -1) {
			return ThrowException(Exception::Error(String::New(
					"This is not hexadecimal data.")));
		}

		*s++ = b | (a << 4);
	}

	return buffer;
}

struct FromHexAction: UnaryAction<FromHexAction> {
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope) {
		const char* data = Buffer::Data(buffer);
		size_t length = Buffer::Length(buffer);
		return decodeHex(data, length, args, scope);
	}
};

struct ToHexAction: UnaryAction<ToHexAction> {
	Handle<Value> apply(Handle<Object>& buffer, const Arguments& args, HandleScope& scope) {
		const size_t size = Buffer::Length(buffer);
		const char* data = Buffer::Data(buffer);

		if (size == 0) {
			return String::Empty();
		}

		std::string s(size * 2, 0);
		for (size_t i = 0; i < size; ++i) {
			const int c = data[i];
			s[i * 2] = toHexTable[(c >> 4) & 15];
			s[i * 2 + 1] = toHexTable[c & 15];
		}

		return scope.Close(String::New(s.c_str(), s.size()));
	}
};

//
// V8 function callbacks
//
Handle<Value> Clear(const Arguments& args) {
	return ClearAction()(args);
}

Handle<Value> Fill(const Arguments& args) {
	return FillAction()(args);
}

Handle<Value> Reverse(const Arguments& args) {
	return ReverseAction()(args);
}

Handle<Value> Equals(const Arguments& args) {
	return EqualsAction()(args);
}

Handle<Value> Compare(const Arguments& args) {
	return CompareAction()(args);
}

Handle<Value> IndexOf(const Arguments& args) {
	return IndexOfAction()(args);
}

Handle<Value> FromHex(const Arguments& args) {
	return FromHexAction()(args);
}

Handle<Value> ToHex(const Arguments& args) {
	return ToHexAction()(args);
}

Handle<Value> Concat(const Arguments& args) {
	HandleScope scope;

	size_t size = 0;
	for (int index = 0, length = args.Length(); index < length; ++index) {
		Local<Value> arg = args[index];
		if (arg->IsString()) {
			// Utf8Length() because we need the length in bytes, not characters
			size += arg->ToString()->Utf8Length();
		}
		else if (Buffer::HasInstance(arg)) {
			size += Buffer::Length(arg->ToObject());
		}
		else {
			std::stringstream s;
			s << "Argument #" << index << " is neither a string nor a buffer object.";
			const char* message = s.str().c_str();
			return ThrowException(Exception::TypeError(String::New(message)));
		}
	}

	Buffer& dst = *Buffer::New(size);
	char* s = Buffer::Data(dst.handle_);

	for (int index = 0, length = args.Length(); index < length; ++index) {
		Local<Value> arg = args[index];
		if (arg->IsString()) {
			String::Utf8Value v(arg->ToString());
			memcpy(s, *v, v.length());
			s += v.length();
		}
		else if (Buffer::HasInstance(arg)) {
			Local<Object> b = arg->ToObject();
			const char* data = Buffer::Data(b);
			size_t length = Buffer::Length(b);
			memcpy(s, data, length);
			s += length;
		}
		else {
			return ThrowException(Exception::Error(String::New(
					"Congratulations! You have run into a bug: argument is neither a string nor a buffer object. "
					"Please make the world a better place and report it.")));
		}
	}

	return scope.Close(dst.handle_);
}

void RegisterModule(Handle<Object> target) {
	target->Set(String::NewSymbol("concat"),  FunctionTemplate::New(Concat)->GetFunction());
	target->Set(String::NewSymbol("fill"),    FunctionTemplate::New(Fill)->GetFunction());
	target->Set(String::NewSymbol("clear"),   FunctionTemplate::New(Clear)->GetFunction());
	target->Set(String::NewSymbol("reverse"), FunctionTemplate::New(Reverse)->GetFunction());
	target->Set(String::NewSymbol("equals"),  FunctionTemplate::New(Equals)->GetFunction());
	target->Set(String::NewSymbol("compare"), FunctionTemplate::New(Compare)->GetFunction());
	target->Set(String::NewSymbol("indexOf"), FunctionTemplate::New(IndexOf)->GetFunction());
	target->Set(String::NewSymbol("fromHex"), FunctionTemplate::New(FromHex)->GetFunction());
	target->Set(String::NewSymbol("toHex"),   FunctionTemplate::New(ToHex)->GetFunction());
}

} // anonymous namespace

NODE_MODULE(buffertools, RegisterModule);
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// File contains modifications by: The Gulden developers
// All modifications:
// Copyright (c) 2017-2018 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@webmail.co.za)
// Distributed under the GULDEN software license, see the accompanying
// file COPYING

#include "warningoverlay.h"
#include "ui_warningoverlay.h"

#include "guiutil.h"

#include "chainparams.h"

#include <QResizeEvent>
#include <QPropertyAnimation>

#include "_Gulden/GuldenGUI.h"
#include "validation/validation.h"

WarningOverlay::WarningOverlay(QWidget *parent)
: QWidget(parent)
, ui(new Ui::WarningOverlay)
, layerIsVisible(false)
, userClosed(false)
{
    ui->setupUi(this);
    connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(closeClicked()));
    if (parent)
    {
        parent->installEventFilter(this);
        raise();
    }

    setVisible(false);

    ui->verticalLayout->setSpacing(0);
    ui->verticalLayout->setContentsMargins(0,0,0,0);

    ui->warningOverlayInfoText->setContentsMargins(0,0,0,0);
    ui->warningOverlayInfoText->setIndent(0);

    ui->closeButton->setContentsMargins(0,0,0,0);
    ui->closeButton->setCursor(Qt::PointingHandCursor);
}

WarningOverlay::~WarningOverlay()
{
    delete ui;
}

bool WarningOverlay::eventFilter(QObject * obj, QEvent * ev)
{
    if (obj == parent())
    {
        if (ev->type() == QEvent::Resize)
        {
            QResizeEvent * rev = static_cast<QResizeEvent*>(ev);
            resize(rev->size());
            if (!layerIsVisible)
                setGeometry(0, height(), width(), height());

        }
        else if (ev->type() == QEvent::ChildAdded) {
            raise();
        }
    }
    return QWidget::eventFilter(obj, ev);
}

//! Tracks parent widget changes
bool WarningOverlay::event(QEvent* ev)
{
    if (ev->type() == QEvent::ParentAboutToChange)
    {
        if (parent()) parent()->removeEventFilter(this);
    }
    else if (ev->type() == QEvent::ParentChange)
    {
        if (parent())
        {
            parent()->installEventFilter(this);
            raise();
        }
    }
    return QWidget::event(ev);
}

void WarningOverlay::toggleVisibility()
{
    showHide(layerIsVisible, true);
    if (!layerIsVisible)
        userClosed = true;
}

void WarningOverlay::showHide(bool hide, bool userRequested)
{
    if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))
        return;

    if (!isVisible() && !hide)
        setVisible(true);

    setGeometry(0, hide ? 0 : height(), width(), height());

    QPropertyAnimation* animation = new QPropertyAnimation(this, "pos");
    animation->setDuration(3500);
    animation->setStartValue(QPoint(0, hide ? 0 : this->height()));
    animation->setEndValue(QPoint(0, hide ? this->height() : 0));
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->start(QAbstractAnimation::DeleteWhenStopped);
    layerIsVisible = !hide;
}

void WarningOverlay::closeClicked()
{
    showHide(true);
    userClosed = true;
}

void WarningOverlay::setWarning(const QString& icon, const QString& title, const QString& warning)
{
    ui->warningOverlayHeading->setText(icon + " " + title);
    QString finalWarning = warning;
    finalWarning.replace("\n", "
");
    ui->warningOverlayInfoText->setText(finalWarning);
}
<commit_msg>Warning overlay, add ability to place clickable URLs in warning messages.<commit_after>// Copyright (c) 2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// File contains modifications by: The Gulden developers
// All modifications:
// Copyright (c) 2017-2018 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@webmail.co.za)
// Distributed under the GULDEN software license, see the accompanying
// file COPYING

#include "warningoverlay.h"
#include "ui_warningoverlay.h"

#include "guiutil.h"

#include "chainparams.h"

#include <QResizeEvent>
#include <QPropertyAnimation>

#include "_Gulden/GuldenGUI.h"
#include "validation/validation.h"

WarningOverlay::WarningOverlay(QWidget *parent)
: QWidget(parent)
, ui(new Ui::WarningOverlay)
, layerIsVisible(false)
, userClosed(false)
{
    ui->setupUi(this);
    connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(closeClicked()));
    if (parent)
    {
        parent->installEventFilter(this);
        raise();
    }

    setVisible(false);

    ui->verticalLayout->setSpacing(0);
    ui->verticalLayout->setContentsMargins(0,0,0,0);

    ui->warningOverlayInfoText->setContentsMargins(0,0,0,0);
    ui->warningOverlayInfoText->setIndent(0);

    // Make URLS clickable (e.g. for updates)
    ui->warningOverlayInfoText->setTextInteractionFlags(Qt::TextBrowserInteraction);
    ui->warningOverlayInfoText->setOpenExternalLinks(true);

    ui->closeButton->setContentsMargins(0,0,0,0);
    ui->closeButton->setCursor(Qt::PointingHandCursor);
}

WarningOverlay::~WarningOverlay()
{
    delete ui;
}

bool WarningOverlay::eventFilter(QObject * obj, QEvent * ev)
{
    if (obj == parent())
    {
        if (ev->type() == QEvent::Resize)
        {
            QResizeEvent * rev = static_cast<QResizeEvent*>(ev);
            resize(rev->size());
            if (!layerIsVisible)
                setGeometry(0, height(), width(), height());

        }
        else if (ev->type() == QEvent::ChildAdded) {
            raise();
        }
    }
    return QWidget::eventFilter(obj, ev);
}

//! Tracks parent widget changes
bool WarningOverlay::event(QEvent* ev)
{
    if (ev->type() == QEvent::ParentAboutToChange)
    {
        if (parent()) parent()->removeEventFilter(this);
    }
    else if (ev->type() == QEvent::ParentChange)
    {
        if (parent())
        {
            parent()->installEventFilter(this);
            raise();
        }
    }
    return QWidget::event(ev);
}

void WarningOverlay::toggleVisibility()
{
    showHide(layerIsVisible, true);
    if (!layerIsVisible)
        userClosed = true;
}

void WarningOverlay::showHide(bool hide, bool userRequested)
{
    if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested))
        return;

    if (!isVisible() && !hide)
        setVisible(true);

    setGeometry(0, hide ? 0 : height(), width(), height());

    QPropertyAnimation* animation = new QPropertyAnimation(this, "pos");
    animation->setDuration(3500);
    animation->setStartValue(QPoint(0, hide ? 0 : this->height()));
    animation->setEndValue(QPoint(0, hide ? this->height() : 0));
    animation->setEasingCurve(QEasingCurve::OutQuad);
    animation->start(QAbstractAnimation::DeleteWhenStopped);
    layerIsVisible = !hide;
}

void WarningOverlay::closeClicked()
{
    showHide(true);
    userClosed = true;
}

void WarningOverlay::setWarning(const QString& icon, const QString& title, const QString& warning)
{
    ui->warningOverlayHeading->setText(icon + "  " + title);
    QString finalWarning = warning;
    finalWarning.replace("\n", "
");
    ui->warningOverlayInfoText->setText(finalWarning);
}
<|endoftext|>


<commit_before>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <globals.h>
#include <pthread.h>
#include <iostream.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>           // DT: 3/97 needed for time function
#include "../rtstuff/heap/heap.h"
#include "../rtstuff/rtdefs.h"
#include "../H/dbug.h"

#define XTBUG
#define XALLBUG

extern "C" {
  void rtsendsamps(void);
  void rtsendzeros(int);
  void rtreportstats(void);
  int rtcloseout(void);
  void rtgetsamps(void);         // DT:  for use with real-time audio input
  void close_audio_ports(void);
}

double baseTime;
long elapsed;

IBusClass checkClass(BusSlot *slot) {
  if (slot == NULL)
	return UNKNOWN;
  if ((slot->auxin_count > 0) && (slot->auxout_count > 0))
	return AUX_TO_AUX;
  if ((slot->auxout_count > 0) && (slot->out_count > 0))
	return TO_AUX_AND_OUT;
  if (slot->auxout_count > 0)
	return TO_AUX;
  if (slot->out_count > 0)
	return TO_OUT;
  return UNKNOWN;
}

extern "C" {
  void *inTraverse()
  {
    short rtInst;
    short playEm;
    int i,j,chunksamps;
    int heapSize,rtQSize,allQSize;
    int offset,endsamp;
    int keepGoing;
    int dummy;
	short bus_q_offset;

    Instrument *Iptr;

    unsigned long bufEndSamp;
    unsigned long chunkStart;
    unsigned long heapChunkStart;

    struct timeval tv;
    struct timezone tz;
    double sec,usec;

	Bool aux_pb_done,frame_done;
	short bus,bus_count,play_bus,busq,endbus;
	IBusClass bus_class,qStatus;
	BusType bus_type;

    // cout << "ENTERING inTraverse() FUNCTION *****\n";

    // Wait for the ok to go ahead
    if (!audio_config) {
      cout << "inTraverse():  waiting for audio_config . . . ";
    }

    while (!audio_config) {
      // Do nothing
    }

    if (audio_config && rtInteractive) {
      cout << "audio set.\n\n";
    }

    gettimeofday(&tv, &tz);
    sec = (double)tv.tv_sec;
    usec = (double)tv.tv_usec;
    baseTime = (sec * 1e6) + usec;

    // Initialize everything

    bufStartSamp = 0;  // current end sample for buffer
    bufEndSamp = RTBUFSAMPS;
    chunkStart = 0;
    heapSize = 0;
    chunkStart = 0;
    elapsed = 0;
    rtInst = 0;
    playEm = 0;

    // printf("ENTERING inTraverse() FUNCTION\n");

    // NOTE: audioin, aux and output buffers are zero'd during allocation

    // read in an input buffer (if audio input is active)
    if (audio_on) {
      rtgetsamps();
      rtsendzeros(0);  // send a buffer of zeros to audio device
    }

    if (rtsetparams_called)         // otherwise, disk-based only
      playEm = 1;

    while(playEm) { // the big loop ==========================================

      pthread_mutex_lock(&heapLock);
      heapSize = rtHeap.getSize();
      if (heapSize > 0) {
		heapChunkStart = rtHeap.getTop();
      }
      pthread_mutex_unlock(&heapLock);

      // Pop elements off rtHeap and insert into rtQueue ----------------------
      while ((heapChunkStart < bufEndSamp) && (heapSize > 0)) {
        rtInst = 1;
        pthread_mutex_lock(&heapLock);
		Iptr = rtHeap.deleteMin();  // get next instrument off heap
		pthread_mutex_unlock(&heapLock);
		if (!Iptr)
		  break;

		// DJT Now we push things onto different queues
		bus_class = checkClass(Iptr->bus_config);
		switch (bus_class) {
		case TO_AUX:
		  bus_count = Iptr->bus_config->auxout_count;
		  bus_q_offset = 0;
		  for(i=0;i<bus_count;i++) {
			bus = Iptr->bus_config->auxout[i];
			busq = bus+bus_q_offset;
#ifdef TBUG
			cout << "Pushing on TO_AUX[" << busq << "] rtQueue\n";
#endif
			rtQueue[busq].push(Iptr,heapChunkStart);
		  }
		  break;
		case AUX_TO_AUX:
		  bus_count = Iptr->bus_config->auxout_count;
		  bus_q_offset = MAXBUS;
		  for(i=0;i<bus_count;i++) {
			bus = Iptr->bus_config->auxout[i];
			busq = bus+bus_q_offset;
#ifdef TBUG
			cout << "Pushing on AUX_TO_AUX[" << busq << "] rtQueue\n";
#endif
			rtQueue[busq].push(Iptr,heapChunkStart);
		  }
		  break;
		case TO_OUT:
		  bus_count = Iptr->bus_config->out_count;
		  bus_q_offset = MAXBUS*2;
		  for(i=0;i<bus_count;i++) {
			bus = Iptr->bus_config->out[i];
			busq = bus+bus_q_offset;
#ifdef TBUG
			cout << "Pushing on TO_OUT[" << busq << "] rtQueue\n";
#endif
			rtQueue[busq].push(Iptr,heapChunkStart);
		  }
		  break;
		case TO_AUX_AND_OUT:
		  bus_count = Iptr->bus_config->out_count;
		  bus_q_offset = MAXBUS;
		  for(i=0;i<bus_count;i++) {
			bus = Iptr->bus_config->out[i];
			busq = bus+bus_q_offset;
#ifdef TBUG
			cout << "Pushing on TO_OUT2[" << busq << "] rtQueue\n";
#endif
			rtQueue[busq].push(Iptr,heapChunkStart);
		  }
		  bus_count = Iptr->bus_config->auxout_count;
		  bus_q_offset = 2*MAXBUS;
		  for(i=0;i<bus_count;i++) {
			bus = Iptr->bus_config->auxout[i];
			busq = bus+bus_q_offset;
#ifdef TBUG
			cout << "Pushing on TO_AUX2[" << busq << "] rtQueue\n";
#endif
			rtQueue[busq].push(Iptr,heapChunkStart);
		  }
		  break;
		default:
		  cout << "ERROR (intraverse): unknown bus_class\n";
		  break;
		}

		pthread_mutex_lock(&heapLock);
		heapSize = rtHeap.getSize();
		if (heapSize > 0)
		  heapChunkStart = rtHeap.getTop();
        pthread_mutex_unlock(&heapLock);
	  }

	  qStatus = TO_AUX;
	  play_bus = 0;
	  aux_pb_done = NO;
	  allQSize = 0;

	  // rtQueue[] playback shuffling ----------------------------------------
	  while (!aux_pb_done) {

		switch (qStatus) {
		case TO_AUX:
		  bus_q_offset = 0;
		  bus_type = BUS_AUX_OUT;
		  bus = ToAuxPlayList[play_bus++];
		  break;
		case AUX_TO_AUX:
		  bus_q_offset = MAXBUS;
		  bus = AuxToAuxPlayList[play_bus++];
		  bus_type = BUS_AUX_OUT;
		  break;
		case TO_OUT:
		  bus_q_offset = MAXBUS*2;
		  bus = ToOutPlayList[play_bus++];
		  bus_type = BUS_OUT;
		  break;
		default:
		  cout << "ERROR (intraverse): unknown bus_class\n";
		  break;
		}

		if (bus != -1)
		  busq = bus+bus_q_offset;
		else
		  busq = bus;
		if (bus == -1) {
		  switch (qStatus) {
		  case TO_AUX:
			qStatus = AUX_TO_AUX;
			play_bus = 0;
			break;
		  case AUX_TO_AUX:
			qStatus = TO_OUT;
			play_bus = 0;
			break;
		  case TO_OUT:
#ifdef TBUG
			cout << "aux_pb_done\n";
#endif
			aux_pb_done = YES;
			break;
		  default:
			cout << "ERROR (intraverse): unknown bus_class\n";
			break;
		  }
		}
#ifdef TBUG
		cout << "bus: " << bus << endl;
		cout << "busq:  " << busq << endl;
#endif
		if (busq != -1) {
		  rtQSize = rtQueue[busq].getSize();
		  if (rtQSize > 0) {
			chunkStart = rtQueue[busq].nextChunk();
		  }
		}
		// Play elements on queue (insert back in if needed) - - - - - - - -
		while ((rtQSize > 0) && (chunkStart < bufEndSamp) && (bus != -1)) {

#ifdef ALLBUG
		  cout << "Begin iteration==========\n";
		  cout << "Q-chunkStart:  " << chunkStart << endl;
		  cout << "bufEndSamp:  " << bufEndSamp << endl;
		  cout << "RTBUFSAMPS:  " << RTBUFSAMPS << endl;
#endif
		  Iptr = rtQueue[busq].pop();  // get next instrument off queue

		  endsamp = Iptr->getendsamp();

		  // difference in sample start (countdown)
		  offset = chunkStart - bufStartSamp;

		  if (offset < 0) { // BGG: added this trap for robustness
			cout << "WARNING: the scheduler is behind the queue!" << endl;
			offset = 0;
		  }

		  Iptr->set_output_offset(offset);

		  if (endsamp < bufEndSamp) {  // compute # of samples to write
			chunksamps = endsamp-chunkStart;
		  }
		  else {
			chunksamps = bufEndSamp-chunkStart;
		  }

		  Iptr->setchunk(chunksamps);  // set "chunksamps"
#ifdef TBUG
		  cout << "Iptr->exec(" << bus_type << "," << bus << ")\n";
#endif
		  Iptr->exec(bus_type, bus);    // write the samples * * * * * * * * *

		  switch (qStatus) {
		  case TO_AUX:
			bus_count = Iptr->bus_config->auxout_count;
			endbus = ToAuxPlayList[bus_count-1];
			break;
		  case AUX_TO_AUX:
			bus_count = Iptr->bus_config->auxout_count;
			endbus = ToAuxPlayList[bus_count-1];
			break;
		  case TO_OUT:
			bus_count = Iptr->bus_config->out_count;
			endbus = ToOutPlayList[bus_count-1];
			break;
		  default:
			cout << "ERROR (intraverse): unknown bus_class\n";
			break;
		  }

#ifdef TBUG
		  cout << "endbus " << endbus << endl;
#endif
		  // ReQueue or delete - - - - - - - - - - - - - - - - - - -
		  if (endsamp > bufEndSamp) {
#ifdef ALLBUG
			cout << "inTraverse():  re queueing instrument\n";
#endif
			rtQueue[busq].push(Iptr,chunkStart+chunksamps);   // put back onto queue
		  }
		  else if (bus == endbus) {
 			delete Iptr;
 		  }

		  // DJT:  not sure this check before new chunkStart is necessary
		  rtQSize = rtQueue[busq].getSize();
		  if (rtQSize) {
			chunkStart = rtQueue[busq].nextChunk();
			allQSize += rtQSize;
		  }
#ifdef TBUG
		  cout << "rtQSize: " << rtQSize << endl;
		  cout << "chunkStart:  " << chunkStart << endl;
		  cout << "chunksamps:  " << chunksamps << endl;
		  cout << "Iteration done==========\n";
#endif
		}
	  }

	  // Write buf to audio device -------------------------------------------
	  if ((chunkStart >= bufEndSamp) && (aux_pb_done)) {
#ifdef ALLBUG
		cout << "Writing samples----------\n";
		cout << "Q-chunkStart:  " << chunkStart << endl;
		cout << "bufEndSamp:  " << bufEndSamp << endl;
#endif

		rtsendsamps();

		// zero the buffers
		clear_aux_buffers();
		clear_output_buffers();

		// read in an input buffer (if audio input is active)
		if (audio_on) {
		  // cout << "Reading data from audio port\n";
		  rtgetsamps();
		}

		gettimeofday(&tv, &tz);
		sec = (double)tv.tv_sec;
		usec = (double)tv.tv_usec;
		baseTime = (sec * 1e6) + usec;
		elapsed += RTBUFSAMPS;
		bufStartSamp += RTBUFSAMPS;
		bufEndSamp += RTBUFSAMPS;
	  }

	  // Some checks for the next case v v v v v v v v v v v v
	  pthread_mutex_lock(&heapLock);
	  heapSize = rtHeap.getSize();
	  if (heapSize > 0) {
		heapChunkStart = rtHeap.getTop();
	  }
	  pthread_mutex_unlock(&heapLock);

	  // Nothing on the queue and nothing on the heap for playing -------------
	  // write zeros
	  if ((heapChunkStart > bufEndSamp) || ((heapSize == 0) && (allQSize == 0))) {

		// FIXME: old comment -- still valid?  -JGG
		// Write audio buffer to file
		// ***FIXME: this writes extra MAXBUF zeros to end of file
		// ***need to make intraverse aware of what it's doing (e.g, server?)

#ifdef TBUG
		cout << "Queue and Heap empty ----------\n";
		cout << "rtQSize: " << rtQSize << endl;
		cout << "chunkStart:  " << chunkStart << endl;
		cout << "chunksamps:  " << chunksamps << endl;
#endif

		rtsendsamps();
		if (rtInst)
		 rtsendzeros(1);   // send zeros to audio device and to file

		// zero the buffers
		clear_aux_buffers();
		clear_output_buffers();

		// Increment time
		gettimeofday(&tv, &tz);
		sec = (double)tv.tv_sec;
		usec = (double)tv.tv_usec;
		baseTime = (sec * 1e6) + usec;
		elapsed += RTBUFSAMPS;
		bufStartSamp += RTBUFSAMPS;
		bufEndSamp += RTBUFSAMPS;
      }

      if (!rtInteractive) {  // Ending condition
		if ((heapSize == 0) && (allQSize == 0)) {
#ifdef TBUG
		  cout << "heapSize:  " << heapSize << endl;
		  cout << "rtQSize:  " << rtQSize << endl;
		  cout << "PLAYEM = 0\n";
		  cout << "The end\n\n";
#endif
		  playEm = 0;
		}
      }
    } // end playEm =========================================================

	if (rtsetparams_called) {
	  if (play_audio) {             // Play zero'd buffers to avoid clicks
		int count = NCHANS * 2;  // DJT:  clicks on my box with 2
		for (j = 0; j < count; j++)
		  rtsendzeros(0);
      }
	  close_audio_ports();
	  rtreportstats();
	  rtcloseout();
	}

	cout << "\n";
	// cout << "EXITING inTraverse() FUNCTION *****\n";
	// exit(1);
  }

} /* extern "C" */
<commit_msg>Fixed conditions for sample writing.  Simpler and better now.<commit_after>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <globals.h>
#include <pthread.h>
#include <iostream.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>           // DT: 3/97 needed for time function
#include "../rtstuff/heap/heap.h"
#include "../rtstuff/rtdefs.h"
#include "../H/dbug.h"

#define TBUG
#define ALLBUG

extern "C" {
  void rtsendsamps(void);
  void rtsendzeros(int);
  void rtreportstats(void);
  int rtcloseout(void);
  void rtgetsamps(void);         // DT:  for use with real-time audio input
  void close_audio_ports(void);
}

double baseTime;
long elapsed;

IBusClass checkClass(BusSlot *slot) {
  if (slot == NULL)
	return UNKNOWN;
  if ((slot->auxin_count > 0) && (slot->auxout_count > 0))
	return AUX_TO_AUX;
  if ((slot->auxout_count > 0) && (slot->out_count > 0))
	return TO_AUX_AND_OUT;
  if (slot->auxout_count > 0)
	return TO_AUX;
  if (slot->out_count > 0)
	return TO_OUT;
  return UNKNOWN;
}

extern "C" {
  void *inTraverse()
  {
    short rtInst;
    short playEm;
    int i,j,chunksamps;
    int heapSize,rtQSize,allQSize;
    int offset,endsamp;
    int keepGoing;
    int dummy;
	short bus_q_offset;

    Instrument *Iptr;

    unsigned long bufEndSamp;
    unsigned long chunkStart;
    unsigned long heapChunkStart;

    struct timeval tv;
    struct timezone tz;
    double sec,usec;

	Bool aux_pb_done,frame_done;
	short bus,bus_count,play_bus,busq,endbus;
	IBusClass bus_class,qStatus;
	BusType bus_type;

    // cout << "ENTERING inTraverse() FUNCTION *****\n";

    // Wait for the ok to go ahead
    if (!audio_config) {
      cout << "inTraverse():  waiting for audio_config . . . ";
    }

    while (!audio_config) {
      // Do nothing
    }

    if (audio_config && rtInteractive) {
      cout << "audio set.\n\n";
    }

    gettimeofday(&tv, &tz);
    sec = (double)tv.tv_sec;
    usec = (double)tv.tv_usec;
    baseTime = (sec * 1e6) + usec;

    // Initialize everything

    bufStartSamp = 0;  // current end sample for buffer
    bufEndSamp = RTBUFSAMPS;
    chunkStart = 0;
    heapSize = 0;
    chunkStart = 0;
    elapsed = 0;
    rtInst = 0;
    playEm = 0;

    // printf("ENTERING inTraverse() FUNCTION\n");

    // NOTE: audioin, aux and output buffers are zero'd during allocation

    // read in an input buffer (if audio input is active)
    if (audio_on) {
      rtgetsamps();
      rtsendzeros(0);  // send a buffer of zeros to audio device
    }

    if (rtsetparams_called)         // otherwise, disk-based only
      playEm = 1;

    while(playEm) { // the big loop ==========================================

      pthread_mutex_lock(&heapLock);
      heapSize = rtHeap.getSize();
      if (heapSize > 0) {
		heapChunkStart = rtHeap.getTop();
      }
      pthread_mutex_unlock(&heapLock);

      // Pop elements off rtHeap and insert into rtQueue ----------------------
      while ((heapChunkStart < bufEndSamp) && (heapSize > 0)) {
        rtInst = 1;
        pthread_mutex_lock(&heapLock);
		Iptr = rtHeap.deleteMin();  // get next instrument off heap
		pthread_mutex_unlock(&heapLock);
		if (!Iptr)
		  break;

		// DJT Now we push things onto different queues
		bus_class = checkClass(Iptr->bus_config);
		switch (bus_class) {
		case TO_AUX:
		  bus_count = Iptr->bus_config->auxout_count;
		  bus_q_offset = 0;
		  for(i=0;i<bus_count;i++) {
			bus = Iptr->bus_config->auxout[i];
			busq = bus+bus_q_offset;
#ifdef TBUG
			cout << "Pushing on TO_AUX[" << busq << "] rtQueue\n";
#endif
			rtQueue[busq].push(Iptr,heapChunkStart);
		  }
		  break;
		case AUX_TO_AUX:
		  bus_count = Iptr->bus_config->auxout_count;
		  bus_q_offset = MAXBUS;
		  for(i=0;i<bus_count;i++) {
			bus = Iptr->bus_config->auxout[i];
			busq = bus+bus_q_offset;
#ifdef TBUG
			cout << "Pushing on AUX_TO_AUX[" << busq << "] rtQueue\n";
#endif
			rtQueue[busq].push(Iptr,heapChunkStart);
		  }
		  break;
		case TO_OUT:
		  bus_count = Iptr->bus_config->out_count;
		  bus_q_offset = MAXBUS*2;
		  for(i=0;i<bus_count;i++) {
			bus = Iptr->bus_config->out[i];
			busq = bus+bus_q_offset;
#ifdef TBUG
			cout << "Pushing on TO_OUT[" << busq << "] rtQueue\n";
#endif
			rtQueue[busq].push(Iptr,heapChunkStart);
		  }
		  break;
		case TO_AUX_AND_OUT:
		  bus_count = Iptr->bus_config->out_count;
		  bus_q_offset = MAXBUS;
		  for(i=0;i<bus_count;i++) {
			bus = Iptr->bus_config->out[i];
			busq = bus+bus_q_offset;
#ifdef TBUG
			cout << "Pushing on TO_OUT2[" << busq << "] rtQueue\n";
#endif
			rtQueue[busq].push(Iptr,heapChunkStart);
		  }
		  bus_count = Iptr->bus_config->auxout_count;
		  bus_q_offset = 2*MAXBUS;
		  for(i=0;i<bus_count;i++) {
			bus = Iptr->bus_config->auxout[i];
			busq = bus+bus_q_offset;
#ifdef TBUG
			cout << "Pushing on TO_AUX2[" << busq << "] rtQueue\n";
#endif
			rtQueue[busq].push(Iptr,heapChunkStart);
		  }
		  break;
		default:
		  cout << "ERROR (intraverse): unknown bus_class\n";
		  break;
		}

		pthread_mutex_lock(&heapLock);
		heapSize = rtHeap.getSize();
		if (heapSize > 0)
		  heapChunkStart = rtHeap.getTop();
        pthread_mutex_unlock(&heapLock);
	  }

	  qStatus = TO_AUX;
	  play_bus = 0;
	  aux_pb_done = NO;
	  allQSize = 0;

	  // rtQueue[] playback shuffling ----------------------------------------
	  while (!aux_pb_done) {

		switch (qStatus) {
		case TO_AUX:
		  bus_q_offset = 0;
		  bus_type = BUS_AUX_OUT;
		  bus = ToAuxPlayList[play_bus++];
		  break;
		case AUX_TO_AUX:
		  bus_q_offset = MAXBUS;
		  bus = AuxToAuxPlayList[play_bus++];
		  bus_type = BUS_AUX_OUT;
		  break;
		case TO_OUT:
		  bus_q_offset = MAXBUS*2;
		  bus = ToOutPlayList[play_bus++];
		  bus_type = BUS_OUT;
		  break;
		default:
		  cout << "ERROR (intraverse): unknown bus_class\n";
		  break;
		}

		if (bus != -1)
		  busq = bus+bus_q_offset;
		else
		  busq = bus;
		if (bus == -1) {
		  switch (qStatus) {
		  case TO_AUX:
			qStatus = AUX_TO_AUX;
			play_bus = 0;
			break;
		  case AUX_TO_AUX:
			qStatus = TO_OUT;
			play_bus = 0;
			break;
		  case TO_OUT:
#ifdef TBUG
			cout << "aux_pb_done\n";
#endif
			aux_pb_done = YES;
			break;
		  default:
			cout << "ERROR (intraverse): unknown bus_class\n";
			break;
		  }
		}
#ifdef TBUG
		cout << "bus: " << bus << endl;
		cout << "busq:  " << busq << endl;
#endif
		if (busq != -1) {
		  rtQSize = rtQueue[busq].getSize();
		  if (rtQSize > 0) {
			chunkStart = rtQueue[busq].nextChunk();
		  }
		}
		// Play elements on queue (insert back in if needed) - - - - - - - -
		while ((rtQSize > 0) && (chunkStart < bufEndSamp) && (bus != -1)) {

#ifdef ALLBUG
		  cout << "Begin iteration==========\n";
		  cout << "Q-chunkStart:  " << chunkStart << endl;
		  cout << "bufEndSamp:  " << bufEndSamp << endl;
		  cout << "RTBUFSAMPS:  " << RTBUFSAMPS << endl;
#endif
		  Iptr = rtQueue[busq].pop();  // get next instrument off queue

		  endsamp = Iptr->getendsamp();

		  // difference in sample start (countdown)
		  offset = chunkStart - bufStartSamp;

		  if (offset < 0) { // BGG: added this trap for robustness
			cout << "WARNING: the scheduler is behind the queue!" << endl;
			offset = 0;
		  }

		  Iptr->set_output_offset(offset);

		  if (endsamp < bufEndSamp) {  // compute # of samples to write
			chunksamps = endsamp-chunkStart;
		  }
		  else {
			chunksamps = bufEndSamp-chunkStart;
		  }

		  Iptr->setchunk(chunksamps);  // set "chunksamps"
#ifdef TBUG
		  cout << "Iptr->exec(" << bus_type << "," << bus << ")\n";
#endif
		  Iptr->exec(bus_type, bus);    // write the samples * * * * * * * * *

		  switch (qStatus) {
		  case TO_AUX:
			bus_count = Iptr->bus_config->auxout_count;
			endbus = ToAuxPlayList[bus_count-1];
			break;
		  case AUX_TO_AUX:
			bus_count = Iptr->bus_config->auxout_count;
			endbus = ToAuxPlayList[bus_count-1];
			break;
		  case TO_OUT:
			bus_count = Iptr->bus_config->out_count;
			endbus = ToOutPlayList[bus_count-1];
			break;
		  default:
			cout << "ERROR (intraverse): unknown bus_class\n";
			break;
		  }

#ifdef TBUG
		  cout << "endbus " << endbus << endl;
#endif
		  // ReQueue or delete - - - - - - - - - - - - - - - - - - -
		  if (endsamp > bufEndSamp) {
#ifdef ALLBUG
			cout << "inTraverse():  re queueing instrument\n";
#endif
			rtQueue[busq].push(Iptr,chunkStart+chunksamps);   // put back onto queue
		  }
		  else if (bus == endbus) {
 			delete Iptr;
 		  }

		  // DJT:  not sure this check before new chunkStart is necessary
		  rtQSize = rtQueue[busq].getSize();
		  if (rtQSize) {
			chunkStart = rtQueue[busq].nextChunk();
			allQSize += rtQSize;
		  }
#ifdef TBUG
		  cout << "rtQSize: " << rtQSize << endl;
		  cout << "chunkStart:  " << chunkStart << endl;
		  cout << "chunksamps:  " << chunksamps << endl;
		  cout << "Iteration done==========\n";
#endif
		}
	  }

	  // Write buf to audio device -------------------------------------------
#ifdef ALLBUG
	  cout << "Writing samples----------\n";
	  cout << "Q-chunkStart:  " << chunkStart << endl;
	  cout << "bufEndSamp:  " << bufEndSamp << endl;
#endif

	  rtsendsamps();

	  // zero the buffers
	  clear_aux_buffers();
	  clear_output_buffers();

	  // read in an input buffer (if audio input is active)
	  if (audio_on) {
		// cout << "Reading data from audio port\n";
		rtgetsamps();
	  }

	  gettimeofday(&tv, &tz);
	  sec = (double)tv.tv_sec;
	  usec = (double)tv.tv_usec;
	  baseTime = (sec * 1e6) + usec;
	  elapsed += RTBUFSAMPS;
	  bufStartSamp += RTBUFSAMPS;
	  bufEndSamp += RTBUFSAMPS;

      if (!rtInteractive) {  // Ending condition
		if ((heapSize == 0) && (allQSize == 0)) {
#ifdef TBUG
		  cout << "heapSize:  " << heapSize << endl;
		  cout << "rtQSize:  " << rtQSize << endl;
		  cout << "PLAYEM = 0\n";
		  cout << "The end\n\n";
#endif
		  playEm = 0;
		}
      }
    } // end playEm =========================================================

	if (rtsetparams_called) {
	  if (play_audio) {             // Play zero'd buffers to avoid clicks
		int count = NCHANS * 4;  // DJT:  clicks on my box with 2
		for (j = 0; j < count; j++)
		  rtsendzeros(0);
      }
	  close_audio_ports();
	  rtreportstats();
	  rtcloseout();
	}

	cout << "\n";
	// cout << "EXITING inTraverse() FUNCTION *****\n";
	// exit(1);
  }

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