<commit_before>/*
 * Copyright (C) 2013 Vaclav Slavik <vslavik@gmail.com>
 * All Rights Reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the schemaation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of the Author nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

// xmlwrapp includes
#include "xmlwrapp/errors.h"

#include "utility.h"
#include "errors_impl.h"

#include <cstring>
#include <sstream>

namespace xml
{

error_handler_ignore_errors              ignore_errors;
error_handler_throw_on_error             throw_on_error;
error_handler_throw_on_error_or_warning  throw_on_error_or_warning;

// ------------------------------------------------------------------------
// xml::error_messages
// ------------------------------------------------------------------------

void error_messages::on_error(const std::string& msg)
{
    messages_.push_back(error_message(msg, error_message::type_error));
    has_errors_ = true;
}

void error_messages::on_warning(const std::string& msg)
{
    messages_.push_back(error_message(msg, error_message::type_warning));
    has_warnings_ = true;
}

std::string error_messages::print() const
{
    std::string buffer;

    for (const auto& msg : messages_)
    {
        if (!buffer.empty())
            buffer += "\n";
        buffer += format_for_print(msg);
    }

    return buffer;
}

std::string error_messages::format_for_print(const error_message& msg) const
{
    switch (msg.type())
    {
        case error_message::type_error:
            return "error: " + msg.message();
        case error_message::type_warning:
            return "warning: " + msg.message();
    }

    return msg.message(); // silence bogus gcc warning
}

// ------------------------------------------------------------------------
// libxml2 callbacks interface
// ------------------------------------------------------------------------

namespace impl
{

// Notice that these callbacks are called from C code, not C++. Although
// throwing exceptions through C code does work in some implementations, it
// is not guaranteed to. We therefore need to make sure no exception
// propagates outside of the callbacks by catching them.
//
// This is also the reason for errors_collector's existence: we cannot safely
// call error_handler's methods, because they may throw (it is in fact often
// desirable). So we collect the errors and "replay" them after returning from
// C code.

std::string build_message(const std::string& what, const xmlError& error)
{
    std::ostringstream oss;

    // We currently don't decode domain and code to their symbolic
    // representation as it doesn't seem to be worth it in practice, the error
    // message is usually clear enough, while these numbers can be used for
    // automatic classification of messages.
    oss << "XML " << what << " " << error.domain << "." << error.code << ": "
        << error.message;

    if (error.file)
    {
        oss << " at " << error.file;
        if (error.line)
        {
            oss << ":" << error.line;

            // Column information, if available, is passed in the second int
            // field (first one is used with the first string field, see below).
            if (error.int2)
            {
                oss << "," << error.int2;
            }
        }
    }

    if (error.str1)
    {
        oss << " while processing \"" << error.str1 << "\"";
        if (error.int1)
        {
            oss << " at position " << error.int1;
        }
    }

    return oss.str();
}

bool treat_warning_as_error(const xmlError& error)
{
    // Currently we only handle warnings with this error code as errors.
    if (error.code != XML_IO_LOAD_ERROR)
        return false;

    // But even warnings using this error code are not always errors, as we
    // also get them when a DTD referenced in the file being parsed can't be
    // opened -- which is really just a warning.
    //
    // So check that the warning is really about the file itself by checking
    // the error message, which always references the file in this case. Be
    // careful to not suppose that either file or str1 fields are set, as
    // "file" field is NULL and the XML file path is in "str1" for the warnings
    // concerning the file itself while warnings about loading DTD contain DTD
    // itself in "str1" and the XML file being processed is in "file".
    std::string load_error = "failed to load external entity \"";
    load_error += error.file ? error.file : error.str1 ? error.str1 : "";
    load_error += "\"";

    if (error.message != load_error)
        return false;

    // We really failed to open the file being processed, this is definitely an
    // error.
    return true;
}

extern "C" void cb_messages_structured_error(void *out, xmlErrorPtr error)
{
    try
    {
        // This is not supposed to happen, but don't crash if it ever does.
        if (!error)
            return;

        // Chop the trailing new line, if any, it's worse than useless when not
        // sending the output directly to the terminal.
        if (error->message)
        {
            const std::size_t len = std::strlen(error->message);
            if (len && error->message[len - 1] == '\n')
                error->message[len - 1] = '\0';
        }

        error_messages* const messages = static_cast<error_messages*>(out);

        switch (error->level)
        {
            case XML_ERR_NONE:
                break;

            case XML_ERR_WARNING:
                // Some libxml warnings are pretty fatal errors, e.g. failing
                // to open the input file is reported as a warning with code
                // XML_IO_LOAD_ERROR, so treat them as such.
                if (!treat_warning_as_error(*error))
                {
                    messages->on_warning(build_message("warning", *error));
                    return;
                }
                // fallthrough

            case XML_ERR_ERROR:
                messages->on_error(build_message("error", *error));
                return;

            case XML_ERR_FATAL:
                messages->on_error(build_message("fatal error", *error));
                return;
        }

        // This is not supposed to happen neither, but at least warn about it
        // if it does, in case there is anything useful in the message.
        std::ostringstream oss;
        oss << "message of unknown level " << error->level;

        messages->on_warning(build_message(oss.str(), *error));
    }
    catch (...) {}
}

extern "C" void cb_messages_warning_v(void *out, const char *message, va_list ap)
{
    try
    {
        error_messages *err = static_cast<error_messages*>(out);

        std::string text;
        printf2string(text, message, ap);
        err->on_warning(text);
    }
    catch (...) {}
}

extern "C" void cb_messages_error_v(void *out, const char *message, va_list ap)
{
    try
    {
        error_messages *err = static_cast<error_messages*>(out);

        std::string text;
        printf2string(text, message, ap);
        err->on_error(text);
    }
    catch (...) {}
}

extern "C" void cb_messages_warning(void *out, const char *message, ...)
{
    CALL_CB_MESSAGES_WARNING(out, message);
}

extern "C" void cb_messages_error(void *out, const char *message, ...)
{
    CALL_CB_MESSAGES_ERROR(out, message);
}

void errors_collector::replay(error_handler& dest)
{
    for (const auto& msg : messages())
    {
        switch (msg.type())
        {
            case error_message::type_error:
                dest.on_error(msg.message());
                break;
            case error_message::type_warning:
                dest.on_warning(msg.message());
                break;
        }
    }
}

std::string errors_collector::format_for_print(const error_message& msg) const
{
    // The errors_collector class is also used to provide backward
    // compatibility errors reporting in tree_parser and xslt::stylesheet. The
    // "error: " prefix wasn't included there, so don't add it now either so
    // that we don't break user UI output. On the other hand, include "warning:
    // " to make it clear these aren't errors.

    switch (msg.type())
    {
        case error_message::type_error:
            return msg.message();
        case error_message::type_warning:
            return "warning: " + msg.message();
    }

    return msg.message(); // silence bogus gcc warning
}

// ----------------------------------------------------------------------------
// global_errors_installer
// ----------------------------------------------------------------------------

global_errors_installer::global_errors_installer(error_messages& on_error) :
    xml_generic_error_orig_(xmlGenericError),
    xml_generic_error_context_orig_(xmlGenericErrorContext),
    xml_structured_error_orig_(xmlStructuredError),
    xml_structured_error_context_orig_(xmlStructuredErrorContext)
{
    // We need to set both structured and generic error callbacks: structured
    // one because it gives us more information and does it in atomic way,
    // instead of splitting a single error message in multiple parts and
    // overrides generic for normal XML errors, but also generic one to catch
    // errors from e.g. XML saving code which doesn't use structured error
    // callback at all and would just silently (!) lose data if any errors
    // happen during encoding without this.
    xmlSetStructuredErrorFunc(&on_error, cb_messages_structured_error);
    xmlSetGenericErrorFunc(&on_error, cb_messages_error);
}

global_errors_installer::~global_errors_installer()
{
    xmlSetGenericErrorFunc(xml_generic_error_context_orig_, xml_generic_error_orig_);
    xmlSetStructuredErrorFunc(xml_structured_error_context_orig_, xml_structured_error_orig_);
}

} // namespace impl

} // namespace xml
<commit_msg>Use emplace_back() instead of push_back()<commit_after>/*
 * Copyright (C) 2013 Vaclav Slavik <vslavik@gmail.com>
 * All Rights Reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the schemaation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of the Author nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

// xmlwrapp includes
#include "xmlwrapp/errors.h"

#include "utility.h"
#include "errors_impl.h"

#include <cstring>
#include <sstream>

namespace xml
{

error_handler_ignore_errors              ignore_errors;
error_handler_throw_on_error             throw_on_error;
error_handler_throw_on_error_or_warning  throw_on_error_or_warning;

// ------------------------------------------------------------------------
// xml::error_messages
// ------------------------------------------------------------------------

void error_messages::on_error(const std::string& msg)
{
    messages_.emplace_back(msg, error_message::type_error);
    has_errors_ = true;
}

void error_messages::on_warning(const std::string& msg)
{
    messages_.emplace_back(msg, error_message::type_warning);
    has_warnings_ = true;
}

std::string error_messages::print() const
{
    std::string buffer;

    for (const auto& msg : messages_)
    {
        if (!buffer.empty())
            buffer += "\n";
        buffer += format_for_print(msg);
    }

    return buffer;
}

std::string error_messages::format_for_print(const error_message& msg) const
{
    switch (msg.type())
    {
        case error_message::type_error:
            return "error: " + msg.message();
        case error_message::type_warning:
            return "warning: " + msg.message();
    }

    return msg.message(); // silence bogus gcc warning
}

// ------------------------------------------------------------------------
// libxml2 callbacks interface
// ------------------------------------------------------------------------

namespace impl
{

// Notice that these callbacks are called from C code, not C++. Although
// throwing exceptions through C code does work in some implementations, it
// is not guaranteed to. We therefore need to make sure no exception
// propagates outside of the callbacks by catching them.
//
// This is also the reason for errors_collector's existence: we cannot safely
// call error_handler's methods, because they may throw (it is in fact often
// desirable). So we collect the errors and "replay" them after returning from
// C code.

std::string build_message(const std::string& what, const xmlError& error)
{
    std::ostringstream oss;

    // We currently don't decode domain and code to their symbolic
    // representation as it doesn't seem to be worth it in practice, the error
    // message is usually clear enough, while these numbers can be used for
    // automatic classification of messages.
    oss << "XML " << what << " " << error.domain << "." << error.code << ": "
        << error.message;

    if (error.file)
    {
        oss << " at " << error.file;
        if (error.line)
        {
            oss << ":" << error.line;

            // Column information, if available, is passed in the second int
            // field (first one is used with the first string field, see below).
            if (error.int2)
            {
                oss << "," << error.int2;
            }
        }
    }

    if (error.str1)
    {
        oss << " while processing \"" << error.str1 << "\"";
        if (error.int1)
        {
            oss << " at position " << error.int1;
        }
    }

    return oss.str();
}

bool treat_warning_as_error(const xmlError& error)
{
    // Currently we only handle warnings with this error code as errors.
    if (error.code != XML_IO_LOAD_ERROR)
        return false;

    // But even warnings using this error code are not always errors, as we
    // also get them when a DTD referenced in the file being parsed can't be
    // opened -- which is really just a warning.
    //
    // So check that the warning is really about the file itself by checking
    // the error message, which always references the file in this case. Be
    // careful to not suppose that either file or str1 fields are set, as
    // "file" field is NULL and the XML file path is in "str1" for the warnings
    // concerning the file itself while warnings about loading DTD contain DTD
    // itself in "str1" and the XML file being processed is in "file".
    std::string load_error = "failed to load external entity \"";
    load_error += error.file ? error.file : error.str1 ? error.str1 : "";
    load_error += "\"";

    if (error.message != load_error)
        return false;

    // We really failed to open the file being processed, this is definitely an
    // error.
    return true;
}

extern "C" void cb_messages_structured_error(void *out, xmlErrorPtr error)
{
    try
    {
        // This is not supposed to happen, but don't crash if it ever does.
        if (!error)
            return;

        // Chop the trailing new line, if any, it's worse than useless when not
        // sending the output directly to the terminal.
        if (error->message)
        {
            const std::size_t len = std::strlen(error->message);
            if (len && error->message[len - 1] == '\n')
                error->message[len - 1] = '\0';
        }

        error_messages* const messages = static_cast<error_messages*>(out);

        switch (error->level)
        {
            case XML_ERR_NONE:
                break;

            case XML_ERR_WARNING:
                // Some libxml warnings are pretty fatal errors, e.g. failing
                // to open the input file is reported as a warning with code
                // XML_IO_LOAD_ERROR, so treat them as such.
                if (!treat_warning_as_error(*error))
                {
                    messages->on_warning(build_message("warning", *error));
                    return;
                }
                // fallthrough

            case XML_ERR_ERROR:
                messages->on_error(build_message("error", *error));
                return;

            case XML_ERR_FATAL:
                messages->on_error(build_message("fatal error", *error));
                return;
        }

        // This is not supposed to happen neither, but at least warn about it
        // if it does, in case there is anything useful in the message.
        std::ostringstream oss;
        oss << "message of unknown level " << error->level;

        messages->on_warning(build_message(oss.str(), *error));
    }
    catch (...) {}
}

extern "C" void cb_messages_warning_v(void *out, const char *message, va_list ap)
{
    try
    {
        error_messages *err = static_cast<error_messages*>(out);

        std::string text;
        printf2string(text, message, ap);
        err->on_warning(text);
    }
    catch (...) {}
}

extern "C" void cb_messages_error_v(void *out, const char *message, va_list ap)
{
    try
    {
        error_messages *err = static_cast<error_messages*>(out);

        std::string text;
        printf2string(text, message, ap);
        err->on_error(text);
    }
    catch (...) {}
}

extern "C" void cb_messages_warning(void *out, const char *message, ...)
{
    CALL_CB_MESSAGES_WARNING(out, message);
}

extern "C" void cb_messages_error(void *out, const char *message, ...)
{
    CALL_CB_MESSAGES_ERROR(out, message);
}

void errors_collector::replay(error_handler& dest)
{
    for (const auto& msg : messages())
    {
        switch (msg.type())
        {
            case error_message::type_error:
                dest.on_error(msg.message());
                break;
            case error_message::type_warning:
                dest.on_warning(msg.message());
                break;
        }
    }
}

std::string errors_collector::format_for_print(const error_message& msg) const
{
    // The errors_collector class is also used to provide backward
    // compatibility errors reporting in tree_parser and xslt::stylesheet. The
    // "error: " prefix wasn't included there, so don't add it now either so
    // that we don't break user UI output. On the other hand, include "warning:
    // " to make it clear these aren't errors.

    switch (msg.type())
    {
        case error_message::type_error:
            return msg.message();
        case error_message::type_warning:
            return "warning: " + msg.message();
    }

    return msg.message(); // silence bogus gcc warning
}

// ----------------------------------------------------------------------------
// global_errors_installer
// ----------------------------------------------------------------------------

global_errors_installer::global_errors_installer(error_messages& on_error) :
    xml_generic_error_orig_(xmlGenericError),
    xml_generic_error_context_orig_(xmlGenericErrorContext),
    xml_structured_error_orig_(xmlStructuredError),
    xml_structured_error_context_orig_(xmlStructuredErrorContext)
{
    // We need to set both structured and generic error callbacks: structured
    // one because it gives us more information and does it in atomic way,
    // instead of splitting a single error message in multiple parts and
    // overrides generic for normal XML errors, but also generic one to catch
    // errors from e.g. XML saving code which doesn't use structured error
    // callback at all and would just silently (!) lose data if any errors
    // happen during encoding without this.
    xmlSetStructuredErrorFunc(&on_error, cb_messages_structured_error);
    xmlSetGenericErrorFunc(&on_error, cb_messages_error);
}

global_errors_installer::~global_errors_installer()
{
    xmlSetGenericErrorFunc(xml_generic_error_context_orig_, xml_generic_error_orig_);
    xmlSetStructuredErrorFunc(xml_structured_error_context_orig_, xml_structured_error_orig_);
}

} // namespace impl

} // namespace xml
<|endoftext|>


<commit_before>#include "audio_source_position.h"
#include "halley/core/api/audio_api.h"

using namespace Halley;

AudioSourcePosition::AudioSourcePosition()
	: isUI(true)
	, isPannable(false)
{
}

AudioSourcePosition::AudioSourcePosition(Vector3f pos, bool isUI, bool isPannable)
	: pos(pos)
	, isUI(isUI)
	, isPannable(isPannable)
{
}

AudioSourcePosition AudioSourcePosition::makeUI(float pan)
{
	return AudioSourcePosition(Vector3f(pan, 0, 0), true, true);
}

AudioSourcePosition AudioSourcePosition::makePositional(Vector3f pos)
{
	return AudioSourcePosition(pos, false, true);
}

AudioSourcePosition AudioSourcePosition::makeFixed()
{
	return AudioSourcePosition(Vector3f(), true, false);
}

static float gain2DPan(float srcPan, float dstPan)
{
	return std::max(0.0f, 1.0f - std::abs(srcPan - dstPan));
}

void AudioSourcePosition::setMix(size_t nSrcChannels, gsl::span<const AudioChannelData> dstChannels, gsl::span<float, 16> dst, float gain, const AudioListenerData& listener) const
{
	const size_t nDstChannels = size_t(dstChannels.size());

	if (isPannable) {
		// Pannable (mono) sounds
		Expects(nSrcChannels == 1);
		if (isUI) {
			for (size_t i = 0; i < nDstChannels; ++i) {
				dst[i] = gain2DPan(pos.x, dstChannels[i].pan) * gain;
			}
		} else {
			// TODO: do some proper computation, use falloff, etc
			for (size_t i = 0; i < nDstChannels; ++i) {
				auto delta = pos - listener.position;
				float pan = clamp(delta.x * 0.005f + 0.5f, 0.0f, 1.0f);
				float len = delta.length();

				const float fallOffNear = 200.0f;
				const float fallOffFar = 400.0f;

				float fallOff = 1.0f - clamp((len - fallOffNear) / (fallOffFar - fallOffNear), 0.0f, 1.0f);

				dst[i] = gain2DPan(pan, dstChannels[i].pan) * gain * fallOff;
			}
		}
	} else {
		// Non-pannable (stereo) sounds
		Expects(nSrcChannels == 2);
		for (size_t i = 0; i < nSrcChannels; ++i) {
			float srcPan = i == 0 ? 0.0f : 1.0f;
			for (size_t j = 0; j < nDstChannels; ++j) {
				dst[i * nSrcChannels + j] = gain2DPan(srcPan, dstChannels[j].pan) * gain;
			}
		}
	}
}
<commit_msg>Move code out of loop. (ops)<commit_after>#include "audio_source_position.h"
#include "halley/core/api/audio_api.h"

using namespace Halley;

AudioSourcePosition::AudioSourcePosition()
	: isUI(true)
	, isPannable(false)
{
}

AudioSourcePosition::AudioSourcePosition(Vector3f pos, bool isUI, bool isPannable)
	: pos(pos)
	, isUI(isUI)
	, isPannable(isPannable)
{
}

AudioSourcePosition AudioSourcePosition::makeUI(float pan)
{
	return AudioSourcePosition(Vector3f(pan, 0, 0), true, true);
}

AudioSourcePosition AudioSourcePosition::makePositional(Vector3f pos)
{
	return AudioSourcePosition(pos, false, true);
}

AudioSourcePosition AudioSourcePosition::makeFixed()
{
	return AudioSourcePosition(Vector3f(), true, false);
}

static float gain2DPan(float srcPan, float dstPan)
{
	return std::max(0.0f, 1.0f - std::abs(srcPan - dstPan));
}

void AudioSourcePosition::setMix(size_t nSrcChannels, gsl::span<const AudioChannelData> dstChannels, gsl::span<float, 16> dst, float gain, const AudioListenerData& listener) const
{
	const size_t nDstChannels = size_t(dstChannels.size());

	if (isPannable) {
		// Pannable (mono) sounds
		Expects(nSrcChannels == 1);
		if (isUI) {
			// UI sound
			for (size_t i = 0; i < nDstChannels; ++i) {
				dst[i] = gain2DPan(pos.x, dstChannels[i].pan) * gain;
			}
		} else {
			// In-world sound
			// TODO: read falloff parameters from elsewhere
			auto delta = pos - listener.position;
			float pan = clamp(delta.x * 0.005f + 0.5f, 0.0f, 1.0f);
			float len = delta.length();

			const float fallOffNear = 200.0f;
			const float fallOffFar = 400.0f;

			float fallOff = 1.0f - clamp((len - fallOffNear) / (fallOffFar - fallOffNear), 0.0f, 1.0f);

			for (size_t i = 0; i < nDstChannels; ++i) {
				dst[i] = gain2DPan(pan, dstChannels[i].pan) * gain * fallOff;
			}
		}
	} else {
		// Non-pannable (stereo) sounds
		Expects(nSrcChannels == 2);
		for (size_t i = 0; i < nSrcChannels; ++i) {
			float srcPan = i == 0 ? 0.0f : 1.0f;
			for (size_t j = 0; j < nDstChannels; ++j) {
				dst[i * nSrcChannels + j] = gain2DPan(srcPan, dstChannels[j].pan) * gain;
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
 *  Copyright (C) 2004 Steve Harris, Uwe Koloska
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2.1 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  $Id$
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>

#include "lo/lo.h"
using namespace std;

int done = 0;

struct member {
    int pid;
    string hostname;
    lo_timetag timetag;
};

vector<member> members;

int memberCompare(member a, member b);

void error(int num, const char *m, const char *path);

int ping_handler(const char *path, const char *types, lo_arg ** argv,
                int argc, void *data, void *user_data);

int quit_handler(const char *path, const char *types, lo_arg ** argv,
                 int argc, void *data, void *user_data);

int main()
{
    /* make address for multicast ip
     * pick a port number for you by passing NULL as the last argument */

    lo_address t = lo_address_new("224.0.0.1", "7770");
    // lo_server multi = lo_server_new_multicast("drone", "7771", error);
    /* start a new server on port 7770 */
    lo_server_thread st = lo_server_thread_new_multicast("224.0.0.1", "7770", error);

    /* add method that will match the path /foo/bar, with two numbers, coerced
     * to float and int */
    lo_server_thread_add_method(st, "/ping", "is", ping_handler, NULL);

    /* add method that will match the path /quit with no args */
    lo_server_thread_add_method(st, "/quit", "", quit_handler, NULL);

    lo_server_thread_start(st);

    while (!done) {
#ifdef WIN32
        Sleep(1);
#else
        usleep(1500000);
#endif
        char hostname[128] = "";

        gethostname(hostname, sizeof(hostname));

        int pid = getpid();
        // cerr << "pid: " << pid << " || hostname : " << hostname << endl;
        lo_send(t, "/ping", "is", pid, hostname);
    }

    lo_server_thread_free(st);

    return 0;
}

int memberCompare(member a, member b)
{
    int name = strcmp(a.hostname.c_str(), b.hostname.c_str());
    if(name == -1)
    {
        return 1;
    }
    else if (name == 1)
    {
        return 0;
    }
    return a.pid < b.pid;
};

void error(int num, const char *msg, const char *path)
{
    printf("liblo server error %d in path %s: %s\n", num, path, msg);
    fflush(stdout);
}

/* catch any incoming messages and display them. returning 1 means that the
 * message has not been fully handled and the server should try other methods */
int ping_handler(const char *path, const char *types, lo_arg ** argv,
                int argc, void *data, void *user_data)
{
    member messageSender;
    messageSender.pid = argv[0]->i;
    char *address = (char *)argv[1];
    messageSender.hostname = address;

    lo_timetag_now(&messageSender.timetag);
    if(!std::binary_search(members.begin(), members.end(), messageSender, memberCompare))
    {
        members.push_back(messageSender);
        sort(members.begin(), members.end(), memberCompare);
        cerr << "NEW NODE ~ PID: " << messageSender.pid << " || path : " <<  messageSender.hostname << " || timestamp : " << messageSender.timetag.sec << endl;
    }

    fflush(stdout);

    return 0;
}

int quit_handler(const char *path, const char *types, lo_arg ** argv,
                 int argc, void *data, void *user_data)
{
    done = 1;
    printf("quiting\n\n");
    fflush(stdout);

    return 0;
}

/* vi:set ts=8 sts=4 sw=4: */
<commit_msg>Fixed it<commit_after>/*
 *  Copyright (C) 2004 Steve Harris, Uwe Koloska
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2.1 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  $Id$
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>

#include "lo/lo.h"
using namespace std;

int done = 0;

struct member {
    int pid;
    string hostname;
    lo_timetag timetag;
};

vector<member> members;

int memberCompare(member a, member b);

void memberCleanup(vector<member> checkMems);

void error(int num, const char *m, const char *path);

int ping_handler(const char *path, const char *types, lo_arg ** argv,
                int argc, void *data, void *user_data);

int quit_handler(const char *path, const char *types, lo_arg ** argv,
                 int argc, void *data, void *user_data);

int main()
{
    /* make address for multicast ip
     * pick a port number for you by passing NULL as the last argument */

    lo_address t = lo_address_new("224.0.0.1", "7770");
    // lo_server multi = lo_server_new_multicast("drone", "7771", error);
    /* start a new server on port 7770 */
    lo_server_thread st = lo_server_thread_new_multicast("224.0.0.1", "7770", error);

    /* add method that will match the path /foo/bar, with two numbers, coerced
     * to float and int */
    lo_server_thread_add_method(st, "/ping", "is", ping_handler, NULL);

    /* add method that will match the path /quit with no args */
    lo_server_thread_add_method(st, "/quit", "", quit_handler, NULL);

    lo_server_thread_start(st);

    while (!done) {
#ifdef WIN32
        Sleep(1);
#else
        usleep(1500000);
#endif
        char hostname[128] = "";

        gethostname(hostname, sizeof(hostname));

        int pid = getpid();
        // cerr << "pid: " << pid << " || hostname : " << hostname << endl;
        lo_send(t, "/ping", "is", pid, hostname);
        // memberCleanup(members);
    }

    lo_server_thread_free(st);

    return 0;
}

int memberCompare(member a, member b)
{
    int name = strcmp(a.hostname.c_str(), b.hostname.c_str());
    if(name == -1)
    {
        return 1;
    }
    else if (name == 1)
    {
        return 0;
    }
    return a.pid < b.pid;
};

void memberCleanup(vector<member> checkMems)
{
    vector<member>::iterator checkMemIter;
    lo_timetag now;
    lo_timetag_now(&now);
    for (checkMemIter = checkMems.begin();
            checkMemIter != checkMems.end();
            checkMemIter++)
    {
        if ((now.sec - checkMemIter->timetag.sec) > 3)
        {
            cerr << "DISCONNECTED ~ PID: " << checkMemIter->pid << " || HOSTNAME: " << checkMemIter->hostname << endl;
            checkMemIter = checkMems.erase(checkMemIter);

        }
    }
}

void error(int num, const char *msg, const char *path)
{
    printf("liblo server error %d in path %s: %s\n", num, path, msg);
    fflush(stdout);
}

/* catch any incoming messages and display them. returning 1 means that the
 * message has not been fully handled and the server should try other methods */
int ping_handler(const char *path, const char *types, lo_arg ** argv,
                int argc, void *data, void *user_data)
{
    member messageSender;
    messageSender.pid = argv[0]->i;
    char *address = (char *)argv[1];
    messageSender.hostname = address;

    lo_timetag_now(&messageSender.timetag);
    if(!std::binary_search(members.begin(), members.end(), messageSender, memberCompare))
    {
        members.push_back(messageSender);
        sort(members.begin(), members.end(), memberCompare);
        cerr << "CONNECTED ~ PID: " << messageSender.pid << " || path : " <<  messageSender.hostname << " || timestamp : " << messageSender.timetag.sec << endl;
    }

    fflush(stdout);

    return 0;
}

int quit_handler(const char *path, const char *types, lo_arg ** argv,
                 int argc, void *data, void *user_data)
{
    done = 1;
    printf("quiting\n\n");
    fflush(stdout);

    return 0;
}

/* vi:set ts=8 sts=4 sw=4: */
<|endoftext|>


<commit_before>#include "Configuration.h"
#include <stdio.h>
#include <direct.h>

std::string Configuration::get( std::string key )
{
    return this->config[key];
}

Configuration::Configuration()
{
    char path[512] = { 0 };
    auto p = _getcwd( path , 512 );

    FILE* file;
    fopen_s( &file , "maraton.conf" , "r" );

    if ( file == NULL )
    {
        Logger::error( "can't not open maraton.conf" );
        return;
    }

    fseek( file , 0 , SEEK_END );
    int len = ftell( file ) ;
    fseek( file , 0 , SEEK_SET );

    char* json_string = new char[len+1];
    memset( json_string , 0 , len + 1 );
    fread( json_string , 1 , len , file );
    fclose( file );

    this->config = nlohmann::json::parse( json_string );

    delete json_string;
}
<commit_msg>try fix compiling errors on linux<commit_after>#include "Configuration.h"
#include <stdio.h>
#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif

std::string Configuration::get( std::string key )
{
    return this->config[key];
}

Configuration::Configuration()
{
    char path[512] = { 0 };
    auto p = _getcwd( path , 512 );

    FILE* file;
    fopen_s( &file , "maraton.conf" , "r" );

    if ( file == NULL )
    {
        Logger::error( "can't not open maraton.conf" );
        return;
    }

    fseek( file , 0 , SEEK_END );
    int len = ftell( file ) ;
    fseek( file , 0 , SEEK_SET );

    char* json_string = new char[len+1];
    memset( json_string , 0 , len + 1 );
    fread( json_string , 1 , len , file );
    fclose( file );

    this->config = nlohmann::json::parse( json_string );

    delete json_string;
}
<|endoftext|>


<commit_before>/// @file socket_interface.cpp
///
/// @brief Implementation of socket_interface.hpp
///
/// @author Thomas Vanderbruggen <thomas@koheron.com>
/// @date 15/08/2015
///
/// (c) Koheron 2014-2015

#include "socket_interface.hpp"

extern "C" {
  #include <arpa/inet.h>
}

#include "kserver_defs.hpp"

namespace kserver {

#define SEND_SPECIALIZE_IMPL(sock_interf)                           \
    template<>                                                      \
    int sock_interf::Send<std::string>(const std::string& str)      \
    {                                                               \
        return SendCstr(str.c_str());                               \
    }                                                               \
                                                                    \
    template<>                                                      \
    int sock_interf::Send<uint32_t>(const uint32_t& val)            \
    {                                                               \
        return SendArray<uint32_t>(&val, 1);                        \
    }                                                               \
                                                                    \
    template<>                                                      \
    int sock_interf::Send<uint64_t>(const uint64_t& val)            \
    {                                                               \
        return SendArray<uint64_t>(&val, 1);                        \
    }                                                               \
                                                                    \
    template<>                                                      \
    int sock_interf::Send<float>(const float& val)                  \
    {                                                               \
        return SendArray<float>(&val, 1);                           \
    }

// -----------------------------------------------
// TCP
// -----------------------------------------------

#if KSERVER_HAS_TCP

SEND_SPECIALIZE_IMPL(TCPSocketInterface)

int TCPSocketInterface::init(void) {return 0;}
int TCPSocketInterface::exit(void) {return 0;}

int TCPSocketInterface::read_data(char *buff_str, char *remain_str)
{
    bzero(buff_str, 2*KSERVER_READ_STR_LEN);
    bzero(read_str, KSERVER_READ_STR_LEN);

    int nb_bytes_rcvd = read(comm_fd, read_str, KSERVER_READ_STR_LEN);

    // Check reception ...
    if(nb_bytes_rcvd < 0) {
        kserver->syslog.print(SysLog::CRITICAL, "Read error\n");
        return -1;
    }

    if(nb_bytes_rcvd == KSERVER_READ_STR_LEN) {
        kserver->syslog.print(SysLog::CRITICAL, "Read buffer overflow\n");
        return -1;
    }

    if(nb_bytes_rcvd == 0) {
        return 1; // Connection closed by client
    }

    kserver->syslog.print(SysLog::DEBUG, "[R@%u] [%d bytes]\n",
                          id, nb_bytes_rcvd);

    // Need a copy here for buffers concatenation (needed?)
    //
    // XXX snprintf maybe not the fastest solution (but very safe)
    // --> Consider using strlen + memcpy
    int ret = snprintf(buff_str, 2*KSERVER_READ_STR_LEN, "%s%s",
                       remain_str, read_str);
    bzero(read_str, KSERVER_READ_STR_LEN);

    if(ret < 0) {
        kserver->syslog.print(SysLog::CRITICAL, "Format error\n");
    	return -1;
    }

    if(ret >= 2*KSERVER_READ_STR_LEN) {
        kserver->syslog.print(SysLog::CRITICAL, "Buffer buff_str overflow\n");
        return -1;
    }

    return 0;
}

int TCPSocketInterface::RcvDataBuffer(uint32_t n_bytes)
{
    uint32_t bytes_read = 0;

    while (bytes_read < n_bytes) {
        int result = read(comm_fd, recv_data_buff + bytes_read,
                          n_bytes-bytes_read);
        // Check reception ...
        if(result < -1) {
            kserver->syslog.print(SysLog::ERROR, "Read error\n");
            return -1;
        }

        if(result == 0) {
            kserver->syslog.print(SysLog::WARNING,
                                  "Connection closed by client\n");
            return -1;
        }

        bytes_read += result;

        if(bytes_read > KSERVER_RECV_DATA_BUFF_LEN) {
            kserver->syslog.print(SysLog::CRITICAL,
                                  "Receive data buffer overflow\n");
            return -1;
        }
    }

    assert(bytes_read == n_bytes);

    return bytes_read;
}

const uint32_t* TCPSocketInterface::RcvHandshake(uint32_t buff_size)
{
    // Handshaking
    if(Send<uint32_t>(htonl(buff_size)) < 0) {
        kserver->syslog.print(SysLog::ERROR, "Cannot send buffer size\n");
        return nullptr;
    }

    uint32_t n_bytes_received =
        static_cast<uint32_t>(RcvDataBuffer(sizeof(uint32_t)*buff_size));

    if(n_bytes_received < 0) {
        return nullptr;
    }

    kserver->syslog.print(SysLog::DEBUG, "[R@%u] [%u bytes]\n",
                          id, n_bytes_received);

    return reinterpret_cast<const uint32_t*>(recv_data_buff);
}

int TCPSocketInterface::SendCstr(const char *string)
{
    int bytes_send = strlen(string) + 1;
    int err = write(comm_fd, string, bytes_send);

    if(err < 0) {
        kserver->syslog.print(SysLog::ERROR,
                              "SendCstr: Can't write to client\n");
        return -1;
    }

    return bytes_send;
}

#endif // KSERVER_HAS_TCP

// -----------------------------------------------
// WebSocket
// -----------------------------------------------

#if KSERVER_HAS_WEBSOCKET

SEND_SPECIALIZE_IMPL(WebSocketInterface)

int WebSocketInterface::init(void)
{
    websock.set_id(comm_fd);

    if(websock.authenticate() < 0) {
        kserver->syslog.print(SysLog::CRITICAL,
                              "Cannot connect websocket to client\n");
        return -1;
    }

	return 0;
}

int WebSocketInterface::exit(void) {return 0;}

int WebSocketInterface::read_data(char *buff_str, char *remain_str)
{
    bzero(buff_str, 2*KSERVER_READ_STR_LEN);

    if(websock.receive() < 0) {
        if(websock.is_closed())
            return 1; // Connection closed by client
        else
            return -1;
    }

    if(websock.get_payload(buff_str, 2*KSERVER_READ_STR_LEN) < 0) {
        return -1;
    }

    return 0;
}

const uint32_t* WebSocketInterface::RcvHandshake(uint32_t buff_size)
{
    // Handshaking
    if(Send<uint32_t>(buff_size) < 0) {
        kserver->syslog.print(SysLog::ERROR, "Error sending the buffer size\n");
        return nullptr;
    }

    int payload_size = websock.receive();

    if(payload_size < 0) {
        return nullptr;
    }

    if(static_cast<uint32_t>(payload_size) != sizeof(uint32_t)*buff_size) {
        kserver->syslog.print(SysLog::ERROR, "Invalid data size received\n");
        return nullptr;
    }

    if(websock.get_payload(recv_data_buff, KSERVER_RECV_DATA_BUFF_LEN) < 0) {
        return nullptr;
    }

    return reinterpret_cast<const uint32_t*>(recv_data_buff);
}

int WebSocketInterface::SendCstr(const char *string)
{
    int err = websock.send(std::string(string));

    if(err < 0) {
        kserver->syslog.print(SysLog::ERROR,
                              "SendCstr: Can't write to client\n");
        return -1;
    }

    return strlen(string) + 1;
}

#endif // KSERVER_HAS_WEBSOCKET

} // namespace kserver
<commit_msg>style<commit_after>/// @file socket_interface.cpp
///
/// @brief Implementation of socket_interface.hpp
///
/// @author Thomas Vanderbruggen <thomas@koheron.com>
/// @date 15/08/2015
///
/// (c) Koheron 2014-2015

#include "socket_interface.hpp"

extern "C" {
  #include <arpa/inet.h>
}

#include "kserver_defs.hpp"

namespace kserver {

#define SEND_SPECIALIZE_IMPL(sock_interf)                           \
    template<>                                                      \
    int sock_interf::Send<std::string>(const std::string& str)      \
    {                                                               \
        return SendCstr(str.c_str());                               \
    }                                                               \
                                                                    \
    template<>                                                      \
    int sock_interf::Send<uint32_t>(const uint32_t& val)            \
    {                                                               \
        return SendArray<uint32_t>(&val, 1);                        \
    }                                                               \
                                                                    \
    template<>                                                      \
    int sock_interf::Send<uint64_t>(const uint64_t& val)            \
    {                                                               \
        return SendArray<uint64_t>(&val, 1);                        \
    }                                                               \
                                                                    \
    template<>                                                      \
    int sock_interf::Send<float>(const float& val)                  \
    {                                                               \
        return SendArray<float>(&val, 1);                           \
    }

// -----------------------------------------------
// TCP
// -----------------------------------------------

#if KSERVER_HAS_TCP

SEND_SPECIALIZE_IMPL(TCPSocketInterface)

int TCPSocketInterface::init(void) {return 0;}
int TCPSocketInterface::exit(void) {return 0;}

int TCPSocketInterface::read_data(char *buff_str, char *remain_str)
{
    bzero(buff_str, 2*KSERVER_READ_STR_LEN);
    bzero(read_str, KSERVER_READ_STR_LEN);

    int nb_bytes_rcvd = read(comm_fd, read_str, KSERVER_READ_STR_LEN);

    // Check reception ...
    if (nb_bytes_rcvd < 0) {
        kserver->syslog.print(SysLog::CRITICAL, "Read error\n");
        return -1;
    }

    if (nb_bytes_rcvd == KSERVER_READ_STR_LEN) {
        kserver->syslog.print(SysLog::CRITICAL, "Read buffer overflow\n");
        return -1;
    }

    if (nb_bytes_rcvd == 0)
        return 1; // Connection closed by client

    kserver->syslog.print(SysLog::DEBUG, "[R@%u] [%d bytes]\n",
                          id, nb_bytes_rcvd);

    // Need a copy here for buffers concatenation (needed?)
    //
    // XXX snprintf maybe not the fastest solution (but very safe)
    // --> Consider using strlen + memcpy
    int ret = snprintf(buff_str, 2*KSERVER_READ_STR_LEN, "%s%s",
                       remain_str, read_str);
    bzero(read_str, KSERVER_READ_STR_LEN);

    if (ret < 0) {
        kserver->syslog.print(SysLog::CRITICAL, "Format error\n");
    	return -1;
    }

    if (ret >= 2*KSERVER_READ_STR_LEN) {
        kserver->syslog.print(SysLog::CRITICAL, "Buffer buff_str overflow\n");
        return -1;
    }

    return 0;
}

int TCPSocketInterface::RcvDataBuffer(uint32_t n_bytes)
{
    uint32_t bytes_read = 0;

    while (bytes_read < n_bytes) {
        int result = read(comm_fd, recv_data_buff + bytes_read,
                          n_bytes-bytes_read);
        // Check reception ...
        if (result < -1) {
            kserver->syslog.print(SysLog::ERROR, "Read error\n");
            return -1;
        }

        if (result == 0) {
            kserver->syslog.print(SysLog::WARNING,
                                  "Connection closed by client\n");
            return -1;
        }

        bytes_read += result;

        if (bytes_read > KSERVER_RECV_DATA_BUFF_LEN) {
            kserver->syslog.print(SysLog::CRITICAL,
                                  "Receive data buffer overflow\n");
            return -1;
        }
    }

    assert(bytes_read == n_bytes);
    return bytes_read;
}

const uint32_t* TCPSocketInterface::RcvHandshake(uint32_t buff_size)
{
    // Handshaking
    if (Send<uint32_t>(htonl(buff_size)) < 0) {
        kserver->syslog.print(SysLog::ERROR, "Cannot send buffer size\n");
        return nullptr;
    }

    uint32_t n_bytes_received =
        static_cast<uint32_t>(RcvDataBuffer(sizeof(uint32_t)*buff_size));

    if (n_bytes_received < 0)
        return nullptr;

    kserver->syslog.print(SysLog::DEBUG, "[R@%u] [%u bytes]\n",
                          id, n_bytes_received);

    return reinterpret_cast<const uint32_t*>(recv_data_buff);
}

int TCPSocketInterface::SendCstr(const char *string)
{
    int bytes_send = strlen(string) + 1;
    int err = write(comm_fd, string, bytes_send);

    if (err < 0) {
        kserver->syslog.print(SysLog::ERROR,
                              "SendCstr: Can't write to client\n");
        return -1;
    }

    return bytes_send;
}

#endif // KSERVER_HAS_TCP

// -----------------------------------------------
// WebSocket
// -----------------------------------------------

#if KSERVER_HAS_WEBSOCKET

SEND_SPECIALIZE_IMPL(WebSocketInterface)

int WebSocketInterface::init(void)
{
    websock.set_id(comm_fd);

    if (websock.authenticate() < 0) {
        kserver->syslog.print(SysLog::CRITICAL,
                              "Cannot connect websocket to client\n");
        return -1;
    }

    return 0;
}

int WebSocketInterface::exit(void) {return 0;}

int WebSocketInterface::read_data(char *buff_str, char *remain_str)
{
    bzero(buff_str, 2*KSERVER_READ_STR_LEN);

    if (websock.receive() < 0) {
        if (websock.is_closed())
            return 1; // Connection closed by client
        else
            return -1;
    }

    if (websock.get_payload(buff_str, 2*KSERVER_READ_STR_LEN) < 0)
        return -1;

    return 0;
}

const uint32_t* WebSocketInterface::RcvHandshake(uint32_t buff_size)
{
    // Handshaking
    if (Send<uint32_t>(buff_size) < 0) {
        kserver->syslog.print(SysLog::ERROR, "Error sending the buffer size\n");
        return nullptr;
    }

    int payload_size = websock.receive();

    if (payload_size < 0)
        return nullptr;

    if (static_cast<uint32_t>(payload_size) != sizeof(uint32_t)*buff_size) {
        kserver->syslog.print(SysLog::ERROR, "Invalid data size received\n");
        return nullptr;
    }

    if (websock.get_payload(recv_data_buff, KSERVER_RECV_DATA_BUFF_LEN) < 0)
        return nullptr;

    return reinterpret_cast<const uint32_t*>(recv_data_buff);
}

int WebSocketInterface::SendCstr(const char *string)
{
    int err = websock.send(std::string(string));

    if (err < 0) {
        kserver->syslog.print(SysLog::ERROR,
                              "SendCstr: Can't write to client\n");
        return -1;
    }

    return strlen(string) + 1;
}

#endif // KSERVER_HAS_WEBSOCKET

} // namespace kserver
<|endoftext|>


<commit_before>#include <Bull/Core/FileSystem/Win32/FileSystemImpl.hpp>
#include <Bull/Core/Support/Win32/Windows.hpp>

namespace Bull
{
    namespace prv
    {
        Path FileSystemImpl::getRoot()
        {
            char buffer[255] = {0};
            GetEnvironmentVariable("systemdrive", buffer, 255);

            return Path(buffer).toAbsolute();
        }

        Path FileSystemImpl::getHome()
        {
            char buffer[255] = {0};
            GetEnvironmentVariable("homepath", buffer, 255);

            return getRoot().resolve(buffer);
        }

        Path FileSystemImpl::getTempPath()
        {
            return getHome().resolve("AppData").resolve("Local").resolve("Temp");
        }

        bool FileSystemImpl::setCurrentDirectory(const Path& path)
        {
            return SetCurrentDirectory(path.toString().getBuffer()) == TRUE;
        }

        FileSystemInfo FileSystemImpl::getFileSystemInfo(const Path& base)
        {
            ULARGE_INTEGER free, total, totalFree;
            FileSystemInfo fileSystemInfo = {0, 0, 0};

            if(GetDiskFreeSpaceEx(base.toString().getBuffer(), &free, &total, &totalFree))
            {
                fileSystemInfo.free      = totalFree.QuadPart;
                fileSystemInfo.available = free.QuadPart;
                fileSystemInfo.capacity  = total.QuadPart;
            }

			return fileSystemInfo;
        }

        bool FileSystemImpl::createLink(const Path& target, const String& link)
        {
			return CreateSymbolicLink(link.getBuffer(), target.toString().getBuffer(), target.isDirectory() ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) != 0;
        }
    }
}
<commit_msg>[Core/FileSystemImplWin32] Fix getRoot method<commit_after>#include <Bull/Core/FileSystem/Win32/FileSystemImpl.hpp>
#include <Bull/Core/Support/Win32/Windows.hpp>

namespace Bull
{
    namespace prv
    {
        Path FileSystemImpl::getRoot()
        {
            char buffer[255] = {0};
            GetEnvironmentVariable("systemdrive", buffer, 255);

            return Path(buffer);
        }

        Path FileSystemImpl::getHome()
        {
            char buffer[255] = {0};
            GetEnvironmentVariable("homepath", buffer, 255);

            return getRoot().resolve(buffer);
        }

        Path FileSystemImpl::getTempPath()
        {
            return getHome().resolve("AppData").resolve("Local").resolve("Temp");
        }

        bool FileSystemImpl::setCurrentDirectory(const Path& path)
        {
            return SetCurrentDirectory(path.toString().getBuffer()) == TRUE;
        }

        FileSystemInfo FileSystemImpl::getFileSystemInfo(const Path& base)
        {
            ULARGE_INTEGER free, total, totalFree;
            FileSystemInfo fileSystemInfo = {0, 0, 0};

            if(GetDiskFreeSpaceEx(base.toString().getBuffer(), &free, &total, &totalFree))
            {
                fileSystemInfo.free      = totalFree.QuadPart;
                fileSystemInfo.available = free.QuadPart;
                fileSystemInfo.capacity  = total.QuadPart;
            }

			return fileSystemInfo;
        }

        bool FileSystemImpl::createLink(const Path& target, const String& link)
        {
			return CreateSymbolicLink(link.getBuffer(), target.toString().getBuffer(), target.isDirectory() ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) != 0;
        }
    }
}
<|endoftext|>


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

#ifndef INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_
#define INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_

#include "distortos/RawMessageQueue.hpp"

#include "distortos/internal/memory/dummyDeleter.hpp"

namespace distortos
{

/**
 * \brief StaticRawMessageQueue2 class is a variant of RawMessageQueue that has automatic storage for queue's contents.
 *
 * This class is a replacement for StaticRawMessageQueue and StaticRawMessageQueueFromSize. To use this new API modify
 * your code in following way:
 * - `'StaticRawMessageQueue<T, QueueSize>'` -> `'StaticRawMessageQueue2<sizeof(T), QueueSize>'`;
 * - `'StaticRawMessageQueueFromSize<ElementSize, QueueSize>'` -> `'StaticRawMessageQueue2<ElementSize, QueueSize>'`;
 *
 * Transition schedule:
 * 1. v0.5.0 - `StaticRawMessageQueue<T, QueueSize>` and `StaticRawMessageQueueFromSize<ElementSize, QueueSize>` are
 * converted to deprecated aliases to `StaticRawMessageQueue2<ElementSize, QueueSize>`;
 * 2. v0.6.0 - "old" `StaticRawMessageQueue<T, QueueSize>` and `StaticRawMessageQueueFromSize<ElementSize, QueueSize>`
 * aliases are removed, `StaticRawMessageQueue2<ElementSize, QueueSize>` is renamed to
 * `StaticRawMessageQueue<ElementSize, QueueSize>`, deprecated `StaticRawMessageQueue2<ElementSize, QueueSize>` alias is
 * added;
 * 3. v0.7.0 - deprecated `StaticRawMessageQueue2<ElementSize, QueueSize>` alias is removed;
 *
 * \tparam ElementSize is the size of single queue element, bytes
 * \tparam QueueSize is the maximum number of elements in queue
 *
 * \ingroup queues
 */

template<size_t ElementSize, size_t QueueSize>
class StaticRawMessageQueue2 : public RawMessageQueue
{
public:

	/**
	 * \brief StaticRawMessageQueue2's constructor
	 */

	explicit StaticRawMessageQueue2() :
			RawMessageQueue{{entryStorage_.data(), internal::dummyDeleter<EntryStorage>},
					{valueStorage_.data(), internal::dummyDeleter<uint8_t>}, ElementSize, QueueSize}
	{

	}

private:

	/// storage for queue's entries
	std::array<EntryStorage, QueueSize> entryStorage_;

	/// storage for queue's contents
	std::array<uint8_t, ElementSize * QueueSize> valueStorage_;
};

/**
 * \brief StaticRawMessageQueue class is a variant of RawMessageQueue that has automatic storage for queue's contents.
 *
 * \tparam T is the type of data in queue
 * \tparam QueueSize is the maximum number of elements in queue
 *
 * \ingroup queues
 */

template<typename T, size_t QueueSize>
using StaticRawMessageQueue = StaticRawMessageQueue2<sizeof(T), QueueSize>;

/**
 * \brief StaticRawMessageQueueFromSize type alias is a variant of StaticRawMessageQueue which uses size of element
 * (instead of type) as template argument.
 *
 * \tparam ElementSize is the size of single queue element, bytes
 * \tparam QueueSize is the maximum number of elements in queue
 */

template<size_t ElementSize, size_t QueueSize>
using StaticRawMessageQueueFromSize = StaticRawMessageQueue2<ElementSize, QueueSize>;

}	// namespace distortos

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

#ifndef INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_
#define INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_

#include "distortos/RawMessageQueue.hpp"

#include "distortos/internal/memory/dummyDeleter.hpp"

namespace distortos
{

/**
 * \brief StaticRawMessageQueue2 class is a variant of RawMessageQueue that has automatic storage for queue's contents.
 *
 * This class is a replacement for StaticRawMessageQueue and StaticRawMessageQueueFromSize. To use this new API modify
 * your code in following way:
 * - `'StaticRawMessageQueue<T, QueueSize>'` -> `'StaticRawMessageQueue2<sizeof(T), QueueSize>'`;
 * - `'StaticRawMessageQueueFromSize<ElementSize, QueueSize>'` -> `'StaticRawMessageQueue2<ElementSize, QueueSize>'`;
 *
 * Transition schedule:
 * 1. v0.5.0 - `StaticRawMessageQueue<T, QueueSize>` and `StaticRawMessageQueueFromSize<ElementSize, QueueSize>` are
 * converted to deprecated aliases to `StaticRawMessageQueue2<ElementSize, QueueSize>`;
 * 2. v0.6.0 - "old" `StaticRawMessageQueue<T, QueueSize>` and `StaticRawMessageQueueFromSize<ElementSize, QueueSize>`
 * aliases are removed, `StaticRawMessageQueue2<ElementSize, QueueSize>` is renamed to
 * `StaticRawMessageQueue<ElementSize, QueueSize>`, deprecated `StaticRawMessageQueue2<ElementSize, QueueSize>` alias is
 * added;
 * 3. v0.7.0 - deprecated `StaticRawMessageQueue2<ElementSize, QueueSize>` alias is removed;
 *
 * \tparam ElementSize is the size of single queue element, bytes
 * \tparam QueueSize is the maximum number of elements in queue
 *
 * \ingroup queues
 */

template<size_t ElementSize, size_t QueueSize>
class StaticRawMessageQueue2 : public RawMessageQueue
{
public:

	/**
	 * \brief StaticRawMessageQueue2's constructor
	 */

	explicit StaticRawMessageQueue2() :
			RawMessageQueue{{entryStorage_.data(), internal::dummyDeleter<EntryStorage>},
					{valueStorage_.data(), internal::dummyDeleter<uint8_t>}, ElementSize, QueueSize}
	{

	}

private:

	/// storage for queue's entries
	std::array<EntryStorage, QueueSize> entryStorage_;

	/// storage for queue's contents
	std::array<uint8_t, ElementSize * QueueSize> valueStorage_;
};

/**
 * \brief StaticRawMessageQueue class is a variant of RawMessageQueue that has automatic storage for queue's contents.
 *
 * \deprecated scheduled to be removed after v0.5.0, use StaticRawMessageQueue2<sizeof(T), QueueSize>`
 *
 * \tparam T is the type of data in queue
 * \tparam QueueSize is the maximum number of elements in queue
 *
 * \ingroup queues
 */

template<typename T, size_t QueueSize>
using StaticRawMessageQueue __attribute__ ((deprecated("Use StaticRawMessageQueue2<sizeof(T), QueueSize>"))) =
		StaticRawMessageQueue2<sizeof(T), QueueSize>;

/**
 * \brief StaticRawMessageQueueFromSize type alias is a variant of StaticRawMessageQueue which uses size of element
 * (instead of type) as template argument.
 *
 * \tparam ElementSize is the size of single queue element, bytes
 * \tparam QueueSize is the maximum number of elements in queue
 */

template<size_t ElementSize, size_t QueueSize>
using StaticRawMessageQueueFromSize = StaticRawMessageQueue2<ElementSize, QueueSize>;

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993-2010 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"

// interface header
#include "LuaExtras.h"

// system headers
#include <string>
using std::string;

// local headers
#include "LuaHeader.h"

//============================================================================//
//============================================================================//

bool LuaExtras::PushEntries(lua_State* L)
{
  PUSH_LUA_CFUNC(L, tobool);
  PUSH_LUA_CFUNC(L, isnil);
  PUSH_LUA_CFUNC(L, isbool);
  PUSH_LUA_CFUNC(L, isnumber);
  PUSH_LUA_CFUNC(L, isstring);
  PUSH_LUA_CFUNC(L, istable);
  PUSH_LUA_CFUNC(L, isthread);
  PUSH_LUA_CFUNC(L, isfunction);
  PUSH_LUA_CFUNC(L, isuserdata);

  PUSH_LUA_CFUNC(L, flush);
  PUSH_LUA_CFUNC(L, stderr_write);

  PUSH_LUA_CFUNC(L, traceback);

  return true;
}

//============================================================================//

int LuaExtras::tobool(lua_State* L)
{
  switch (lua_type(L, 1)) {
    case LUA_TBOOLEAN: {
      lua_settop(L, 1);
      break;
    }
    case LUA_TNUMBER: {
      lua_pushboolean(L, (lua_tofloat(L, 1) != 0.0f));
      break;
    }
    case LUA_TSTRING: {
      const char* c = lua_tostring(L, 1);
      const bool value = (((c[0] == '1') && (c[1] == 0)) ||
			  (((c[0] == 't') || (c[0] == 'T')) &&
			   ((c[1] == 'r') || (c[1] == 'R')) &&
			   ((c[2] == 'u') || (c[2] == 'U')) &&
			   ((c[3] == 'e') || (c[3] == 'E')) &&
			    (c[4] == 0)));
      lua_pushboolean(L, value);
      break;
    }
    default: {
      lua_pushboolean(L, false);
      break;
    }
  }
  return 1;
}

//============================================================================//

int LuaExtras::isnil(lua_State* L)
{
  lua_pushboolean(L, lua_isnoneornil(L, 1));
  return 1;
}

int LuaExtras::isbool(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TBOOLEAN);
  return 1;
}

int LuaExtras::isnumber(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TNUMBER);
  return 1;
}

int LuaExtras::isstring(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TSTRING);
  return 1;
}

int LuaExtras::istable(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TTABLE);
  return 1;
}

int LuaExtras::isthread(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TTHREAD);
  return 1;
}

int LuaExtras::isfunction(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TFUNCTION);
  return 1;
}

int LuaExtras::isuserdata(lua_State* L)
{
  const int type = lua_type(L, 1);
  lua_pushboolean(L, (type == LUA_TUSERDATA) ||
		     (type == LUA_TLIGHTUSERDATA));
  return 1;
}

//============================================================================//
//============================================================================//
//
//  flush()
//

int LuaExtras::flush(lua_State* L)
{
  if (!lua_israwstring(L, 1)) {
    fflush(stdout);
  }
  else {
    const string key = lua_tostring(L, 1);
	 if (key == "stdout") { fflush(stdout); }
    else if (key == "stderr") { fflush(stderr); }
    else if (key == "stdin")  { fflush(stdin);  }
    else {
      luaL_error(L, "flush() unknown stream type: %s\n", key.c_str());
    }
  }
  return 0;
}

//============================================================================//
//============================================================================//
//
//  stderr_write()
//

int LuaExtras::stderr_write(lua_State* L)
{
  luaL_checkstring(L, 1);
  if (!lua_isboolean(L, 1) || !lua_tobool(L, 1)) {
    fprintf(stderr, lua_tostring(L, 1));
  } else {
    fprintf(stderr, lua_tostring(L, 1));
  }
  return 0;
}

//============================================================================//
//============================================================================//
//
//  traceback()
//
//  - copied directly from src/other/lua/src/ldblib.c
//

static lua_State *getthread (lua_State *L, int *arg) {
  if (lua_isthread(L, 1)) {
    *arg = 1;
    return lua_tothread(L, 1);
  }
  else {
    *arg = 0;
    return L;
  }
}

#define LEVELS1  12  // size of the first part of the stack
#define LEVELS2  10  // size of the second part of the stack

int LuaExtras::traceback(lua_State *L)  // db_errorfb() function
{
  int level;
  int firstpart = 1;  // still before eventual `...'
  int arg;
  lua_State *L1 = getthread(L, &arg);
  lua_Debug ar;
  if (lua_isnumber(L, arg+2)) {
    level = (int)lua_tointeger(L, arg+2);
    lua_pop(L, 1);
  }
  else
    level = (L == L1) ? 1 : 0;  // level 0 may be this own function
  if (lua_gettop(L) == arg)
    lua_pushliteral(L, "");
  else if (!lua_isstring(L, arg+1)) return 1;  // message is not a string
  else lua_pushliteral(L, "\n");
  lua_pushliteral(L, "stack traceback:");
  while (lua_getstack(L1, level++, &ar)) {
    if (level > LEVELS1 && firstpart) {
      // no more than `LEVELS2' more levels?
      if (!lua_getstack(L1, level+LEVELS2, &ar))
	level--;  // keep going
      else {
	lua_pushliteral(L, "\n\t...");  // too many levels
	while (lua_getstack(L1, level+LEVELS2, &ar))  // find last levels
	  level++;
      }
      firstpart = 0;
      continue;
    }
    lua_pushliteral(L, "\n\t");
    lua_getinfo(L1, "Snl", &ar);
    lua_pushfstring(L, "%s:", ar.short_src);
    if (ar.currentline > 0)
      lua_pushfstring(L, "%d:", ar.currentline);
    if (*ar.namewhat != '\0')  // is there a name?
	lua_pushfstring(L, " in function " LUA_QS, ar.name);
    else {
      if (*ar.what == 'm')  // main?
	lua_pushfstring(L, " in main chunk");
      else if (*ar.what == 'C' || *ar.what == 't')
	lua_pushliteral(L, " ?");  // C function or tail call
      else
	lua_pushfstring(L, " in function <%s:%d>",
			   ar.short_src, ar.linedefined);
    }
    lua_concat(L, lua_gettop(L) - arg);
  }
  lua_concat(L, lua_gettop(L) - arg);
  return 1;
}

//============================================================================//
//============================================================================//
//
//  dump()  &  listing()
//

#include "other/lua/src/lstate.h"
#include "other/lua/src/llimits.h"
#define luac_c // for luaU_print()
#include "other/lua/src/lundump.h"

#define api_checknelems(L, n)  api_check(L, (n) <= (L->top - L->base))

static int Writer(lua_State *L, const void* b, size_t size, void* B) {
  (void)L;
  luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
  return 0;
}

static int Dump(lua_State *L, lua_Writer writer, void *data, bool strip)
{
  int status;
  TValue *o;
  lua_lock(L);
  api_checknelems(L, 1);
  o = L->top - 1;
  if (isLfunction(o)) {
    status = luaU_dump(L, clvalue(o)->l.p, writer, data, strip ? 1 : 0);
  } else {
    status = 1;
  }
  lua_unlock(L);
  return status;
}

int LuaExtras::dump(lua_State* L)
{
  luaL_Buffer b;
  luaL_checktype(L, 1, LUA_TFUNCTION);
  const bool strip = lua_isboolean(L, 2) && lua_tobool(L, 2);
  lua_settop(L, 1);
  luaL_buffinit(L,&b);
  if (Dump(L, Writer, &b, strip) != 0) {
    luaL_error(L, "unable to dump given function");
  }
  luaL_pushresult(&b);
  return 1;
}

static int Listing(lua_State *L, lua_Writer /*writer*/, void* /*data*/, int level)
{
  int status = 0;
  TValue *o;
  lua_lock(L);
  api_checknelems(L, 1);
  o = L->top - 1;
  if (isLfunction(o)) {
    luaU_print(clvalue(o)->l.p, level);
  } else {
    status = 1;
  }
  lua_unlock(L);
  return status;
}

int LuaExtras::listing(lua_State* L)
{
  luaL_Buffer b;
  luaL_checktype(L, 1, LUA_TFUNCTION);
  const int level = luaL_optint(L, 2, 0);
  lua_settop(L, 1);
  luaL_buffinit(L,&b);
  if (Listing(L, Writer, &b, level) != 0) {
    luaL_error(L, "unable to dump given function");
  }
  luaL_pushresult(&b);
  return 1;
}

//============================================================================//
//============================================================================//

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>* fprintf => fputs fix<commit_after>/* bzflag
 * Copyright (c) 1993-2010 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"

// interface header
#include "LuaExtras.h"

// system headers
#include <string>
using std::string;

// local headers
#include "LuaHeader.h"

//============================================================================//
//============================================================================//

bool LuaExtras::PushEntries(lua_State* L)
{
  PUSH_LUA_CFUNC(L, tobool);
  PUSH_LUA_CFUNC(L, isnil);
  PUSH_LUA_CFUNC(L, isbool);
  PUSH_LUA_CFUNC(L, isnumber);
  PUSH_LUA_CFUNC(L, isstring);
  PUSH_LUA_CFUNC(L, istable);
  PUSH_LUA_CFUNC(L, isthread);
  PUSH_LUA_CFUNC(L, isfunction);
  PUSH_LUA_CFUNC(L, isuserdata);

  PUSH_LUA_CFUNC(L, flush);
  PUSH_LUA_CFUNC(L, stderr_write);

  PUSH_LUA_CFUNC(L, traceback);

  return true;
}

//============================================================================//

int LuaExtras::tobool(lua_State* L)
{
  switch (lua_type(L, 1)) {
    case LUA_TBOOLEAN: {
      lua_settop(L, 1);
      break;
    }
    case LUA_TNUMBER: {
      lua_pushboolean(L, (lua_tofloat(L, 1) != 0.0f));
      break;
    }
    case LUA_TSTRING: {
      const char* c = lua_tostring(L, 1);
      const bool value = (((c[0] == '1') && (c[1] == 0)) ||
			  (((c[0] == 't') || (c[0] == 'T')) &&
			   ((c[1] == 'r') || (c[1] == 'R')) &&
			   ((c[2] == 'u') || (c[2] == 'U')) &&
			   ((c[3] == 'e') || (c[3] == 'E')) &&
			    (c[4] == 0)));
      lua_pushboolean(L, value);
      break;
    }
    default: {
      lua_pushboolean(L, false);
      break;
    }
  }
  return 1;
}

//============================================================================//

int LuaExtras::isnil(lua_State* L)
{
  lua_pushboolean(L, lua_isnoneornil(L, 1));
  return 1;
}

int LuaExtras::isbool(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TBOOLEAN);
  return 1;
}

int LuaExtras::isnumber(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TNUMBER);
  return 1;
}

int LuaExtras::isstring(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TSTRING);
  return 1;
}

int LuaExtras::istable(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TTABLE);
  return 1;
}

int LuaExtras::isthread(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TTHREAD);
  return 1;
}

int LuaExtras::isfunction(lua_State* L)
{
  lua_pushboolean(L, lua_type(L, 1) == LUA_TFUNCTION);
  return 1;
}

int LuaExtras::isuserdata(lua_State* L)
{
  const int type = lua_type(L, 1);
  lua_pushboolean(L, (type == LUA_TUSERDATA) ||
		     (type == LUA_TLIGHTUSERDATA));
  return 1;
}

//============================================================================//
//============================================================================//
//
//  flush()
//

int LuaExtras::flush(lua_State* L)
{
  if (!lua_israwstring(L, 1)) {
    fflush(stdout);
  }
  else {
    const string key = lua_tostring(L, 1);
	 if (key == "stdout") { fflush(stdout); }
    else if (key == "stderr") { fflush(stderr); }
    else if (key == "stdin")  { fflush(stdin);  }
    else {
      luaL_error(L, "flush() unknown stream type: %s\n", key.c_str());
    }
  }
  return 0;
}

//============================================================================//
//============================================================================//
//
//  stderr_write()
//

int LuaExtras::stderr_write(lua_State* L)
{
  const char* s = luaL_checkstring(L, 1);
  fputs(s, stderr);
  return 0;
}

//============================================================================//
//============================================================================//
//
//  traceback()
//
//  - copied directly from src/other/lua/src/ldblib.c
//

static lua_State *getthread (lua_State *L, int *arg) {
  if (lua_isthread(L, 1)) {
    *arg = 1;
    return lua_tothread(L, 1);
  }
  else {
    *arg = 0;
    return L;
  }
}

#define LEVELS1  12  // size of the first part of the stack
#define LEVELS2  10  // size of the second part of the stack

int LuaExtras::traceback(lua_State *L)  // db_errorfb() function
{
  int level;
  int firstpart = 1;  // still before eventual `...'
  int arg;
  lua_State *L1 = getthread(L, &arg);
  lua_Debug ar;
  if (lua_isnumber(L, arg+2)) {
    level = (int)lua_tointeger(L, arg+2);
    lua_pop(L, 1);
  }
  else
    level = (L == L1) ? 1 : 0;  // level 0 may be this own function
  if (lua_gettop(L) == arg)
    lua_pushliteral(L, "");
  else if (!lua_isstring(L, arg+1)) return 1;  // message is not a string
  else lua_pushliteral(L, "\n");
  lua_pushliteral(L, "stack traceback:");
  while (lua_getstack(L1, level++, &ar)) {
    if (level > LEVELS1 && firstpart) {
      // no more than `LEVELS2' more levels?
      if (!lua_getstack(L1, level+LEVELS2, &ar))
	level--;  // keep going
      else {
	lua_pushliteral(L, "\n\t...");  // too many levels
	while (lua_getstack(L1, level+LEVELS2, &ar))  // find last levels
	  level++;
      }
      firstpart = 0;
      continue;
    }
    lua_pushliteral(L, "\n\t");
    lua_getinfo(L1, "Snl", &ar);
    lua_pushfstring(L, "%s:", ar.short_src);
    if (ar.currentline > 0)
      lua_pushfstring(L, "%d:", ar.currentline);
    if (*ar.namewhat != '\0')  // is there a name?
	lua_pushfstring(L, " in function " LUA_QS, ar.name);
    else {
      if (*ar.what == 'm')  // main?
	lua_pushfstring(L, " in main chunk");
      else if (*ar.what == 'C' || *ar.what == 't')
	lua_pushliteral(L, " ?");  // C function or tail call
      else
	lua_pushfstring(L, " in function <%s:%d>",
			   ar.short_src, ar.linedefined);
    }
    lua_concat(L, lua_gettop(L) - arg);
  }
  lua_concat(L, lua_gettop(L) - arg);
  return 1;
}

//============================================================================//
//============================================================================//
//
//  dump()  &  listing()
//

#include "other/lua/src/lstate.h"
#include "other/lua/src/llimits.h"
#define luac_c // for luaU_print()
#include "other/lua/src/lundump.h"

#define api_checknelems(L, n)  api_check(L, (n) <= (L->top - L->base))

static int Writer(lua_State *L, const void* b, size_t size, void* B) {
  (void)L;
  luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
  return 0;
}

static int Dump(lua_State *L, lua_Writer writer, void *data, bool strip)
{
  int status;
  TValue *o;
  lua_lock(L);
  api_checknelems(L, 1);
  o = L->top - 1;
  if (isLfunction(o)) {
    status = luaU_dump(L, clvalue(o)->l.p, writer, data, strip ? 1 : 0);
  } else {
    status = 1;
  }
  lua_unlock(L);
  return status;
}

int LuaExtras::dump(lua_State* L)
{
  luaL_Buffer b;
  luaL_checktype(L, 1, LUA_TFUNCTION);
  const bool strip = lua_isboolean(L, 2) && lua_tobool(L, 2);
  lua_settop(L, 1);
  luaL_buffinit(L,&b);
  if (Dump(L, Writer, &b, strip) != 0) {
    luaL_error(L, "unable to dump given function");
  }
  luaL_pushresult(&b);
  return 1;
}

static int Listing(lua_State *L, lua_Writer /*writer*/, void* /*data*/, int level)
{
  int status = 0;
  TValue *o;
  lua_lock(L);
  api_checknelems(L, 1);
  o = L->top - 1;
  if (isLfunction(o)) {
    luaU_print(clvalue(o)->l.p, level);
  } else {
    status = 1;
  }
  lua_unlock(L);
  return status;
}

int LuaExtras::listing(lua_State* L)
{
  luaL_Buffer b;
  luaL_checktype(L, 1, LUA_TFUNCTION);
  const int level = luaL_optint(L, 2, 0);
  lua_settop(L, 1);
  luaL_buffinit(L,&b);
  if (Listing(L, Writer, &b, level) != 0) {
    luaL_error(L, "unable to dump given function");
  }
  luaL_pushresult(&b);
  return 1;
}

//============================================================================//
//============================================================================//

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>