<commit_before>// SciTE - Scintilla based Text Editor
/** @file Cookie.cxx
 ** Examine start of files for coding cookies and type information.
 **/
// Copyright 2011 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>

#include <string>
#include <vector>

#include "Scintilla.h"

#include "GUI.h"

#include "StringHelpers.h"
#include "Cookie.h"

std::string ExtractLine(const char *buf, size_t length) {
	unsigned int endl = 0;
	if (length > 0) {
		while ((endl < length) && (buf[endl] != '\r') && (buf[endl] != '\n')) {
			endl++;
		}
		if (((endl + 1) < length) && (buf[endl] == '\r') && (buf[endl+1] == '\n')) {
			endl++;
		}
		if (endl < length) {
			endl++;
		}
	}
	return std::string(buf, 0, endl);
}

static const char codingCookie[] = "coding";

static bool isEncodingChar(char ch) {
	return (ch == '_') || (ch == '-') || (ch == '.') ||
	       (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
	       (ch >= '0' && ch <= '9');
}

static bool isSpaceChar(char ch) {
	return (ch == ' ') || (ch == '\t');
}

static UniMode CookieValue(const std::string &s) {
	size_t posCoding = s.find(codingCookie);
	if (posCoding != std::string::npos) {
		posCoding += strlen(codingCookie);
		if ((s[posCoding] == ':') || (s[posCoding] == '=')) {
			posCoding++;
			if ((s[posCoding] == '\"') || (s[posCoding] == '\'')) {
				posCoding++;
			}
			while ((posCoding < s.length()) &&
			        (isSpaceChar(s[posCoding]))) {
				posCoding++;
			}
			size_t endCoding = posCoding;
			while ((endCoding < s.length()) &&
			        (isEncodingChar(s[endCoding]))) {
				endCoding++;
			}
			std::string code(s, posCoding, endCoding-posCoding);
			LowerCaseAZ(code);
			if (code == "utf-8") {
				return uniCookie;
			}
		}
	}
	return uni8Bit;
}

UniMode CodingCookieValue(const char *buf, size_t length) {
	std::string l1 = ExtractLine(buf, length);
	UniMode unicodeMode = CookieValue(l1);
	if (unicodeMode == uni8Bit) {
		std::string l2 = ExtractLine(buf + l1.length(), length - l1.length());
		unicodeMode = CookieValue(l2);
	}
	return unicodeMode;
}

<commit_msg>Invoke the correct constructor. The only 3 argument std::string constructor is (const string& str, size_t pos, size_t len = npos). This requires a std::string first arg, not a char* so the char* is converted to std::string with the single argument constructor which depends on a NUL terminator. When the file being opened is larger than the buffer size (128K) there is no NUL and the call fails.<commit_after>// SciTE - Scintilla based Text Editor
/** @file Cookie.cxx
 ** Examine start of files for coding cookies and type information.
 **/
// Copyright 2011 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>

#include <string>
#include <vector>

#include "Scintilla.h"

#include "GUI.h"

#include "StringHelpers.h"
#include "Cookie.h"

std::string ExtractLine(const char *buf, size_t length) {
	unsigned int endl = 0;
	if (length > 0) {
		while ((endl < length) && (buf[endl] != '\r') && (buf[endl] != '\n')) {
			endl++;
		}
		if (((endl + 1) < length) && (buf[endl] == '\r') && (buf[endl+1] == '\n')) {
			endl++;
		}
		if (endl < length) {
			endl++;
		}
	}
	return std::string(buf, endl);
}

static const char codingCookie[] = "coding";

static bool isEncodingChar(char ch) {
	return (ch == '_') || (ch == '-') || (ch == '.') ||
	       (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
	       (ch >= '0' && ch <= '9');
}

static bool isSpaceChar(char ch) {
	return (ch == ' ') || (ch == '\t');
}

static UniMode CookieValue(const std::string &s) {
	size_t posCoding = s.find(codingCookie);
	if (posCoding != std::string::npos) {
		posCoding += strlen(codingCookie);
		if ((s[posCoding] == ':') || (s[posCoding] == '=')) {
			posCoding++;
			if ((s[posCoding] == '\"') || (s[posCoding] == '\'')) {
				posCoding++;
			}
			while ((posCoding < s.length()) &&
			        (isSpaceChar(s[posCoding]))) {
				posCoding++;
			}
			size_t endCoding = posCoding;
			while ((endCoding < s.length()) &&
			        (isEncodingChar(s[endCoding]))) {
				endCoding++;
			}
			std::string code(s, posCoding, endCoding-posCoding);
			LowerCaseAZ(code);
			if (code == "utf-8") {
				return uniCookie;
			}
		}
	}
	return uni8Bit;
}

UniMode CodingCookieValue(const char *buf, size_t length) {
	std::string l1 = ExtractLine(buf, length);
	UniMode unicodeMode = CookieValue(l1);
	if (unicodeMode == uni8Bit) {
		std::string l2 = ExtractLine(buf + l1.length(), length - l1.length());
		unicodeMode = CookieValue(l2);
	}
	return unicodeMode;
}

<|endoftext|>


<commit_before>#if (TARGET_OS_WATCH != 1)

#include "braincloud/internal/DefaultWebSocket.h"

#include <algorithm>
#include <iostream>
#include <cctype>

#define MAX_PAYLOAD (64 * 1024)

static std::mutex lwsContextMutex;

namespace BrainCloud
{
    static struct lws_protocols protocols[] = {
        {
            "brainCloud",
            &DefaultWebSocket::libWebsocketsCallback,
            0,
            MAX_PAYLOAD,
            0, NULL, 0
        },
        { NULL, NULL, 0, 0 } /* terminator */
    };

    static const struct lws_extension exts[] = {
        {
            "permessage-deflate",
            lws_extension_callback_pm_deflate,
            "permessage-deflate; client_no_context_takeover"
        },
        {
            "deflate-frame",
            lws_extension_callback_pm_deflate,
            "deflate_frame"
        },
        { NULL, NULL, NULL /* terminator */ }
    };

    IWebSocket* IWebSocket::create(const std::string& address, int port, const std::map<std::string, std::string>& headers)
    {
        return new DefaultWebSocket(address, port, headers);
    }

    //struct lws_context* DefaultWebSocket::_pLwsContext = NULL;

    DefaultWebSocket::~DefaultWebSocket()
    {
        close();
    }

    DefaultWebSocket::DefaultWebSocket(const std::string& uri, int port, const std::map<std::string, std::string>& headers)
        : _isValid(false)
        , _pLwsContext(NULL)
        , _pLws(NULL)
        , _isConnecting(true)
        , _authHeaders(headers)
    {
        std::string uriCopy = uri;

        // Split address into host/addr/origin/protocol
        std::string protocol = uriCopy.substr(0, std::min<size_t>(uriCopy.size(), uriCopy.find_first_of(':')));
        size_t protocolSize = protocol.size() + 3;
        size_t argsPos = std::min<size_t>(uriCopy.size(), uriCopy.find_first_of('?', protocolSize));
        if (uriCopy[argsPos - 1] != '/')
        {
            uriCopy.insert(uriCopy.begin() + argsPos, '/');
        }
        size_t slashPos = std::min<size_t>(uriCopy.size(), uriCopy.find_first_of('/', protocolSize));
        std::string path = uriCopy.substr(slashPos);
        if (path.empty())
        {
            path = "/";
        }
        std::string addr = uriCopy.substr(protocolSize, slashPos - protocolSize);
        std::string host = addr;
        std::string origin = host + ":" + std::to_string(port);

        // Validate
        std::string protocolCaps = protocol;
        std::transform(protocol.begin(), protocol.end(), protocolCaps.begin(), [](unsigned char c){ return std::toupper(c); });
        if (protocolCaps != "WS" && protocolCaps != "WSS")
        {
            std::cout << "Invalid websocket protocol: " << protocol << std::endl;
            return;
        }
        bool useSSL = protocolCaps == "WSS";

        // Create context
        //if (!_pLwsContext)
        {
            struct lws_context_creation_info info;
            memset(&info, 0, sizeof info);

            info.port = CONTEXT_PORT_NO_LISTEN;
            info.protocols = protocols;
            info.gid = -1;
            info.uid = -1;
            info.extensions = exts;
            info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;
            info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;

            std::unique_lock<std::mutex> lock(lwsContextMutex);
            _pLwsContext = lws_create_context(&info);
            if (!_pLwsContext)
            {
                std::cout << "Failed to create websocket context" << std::endl;
                return;
            }
        }

        // Start update thread
        _updateThread = std::thread([this]()
        {
            _mutex.lock();
            while (_isConnecting || _isValid)
            {
                _mutex.unlock();
                lws_callback_on_writable_all_protocol(_pLwsContext, &protocols[0]);
                lws_service(_pLwsContext, 100);
                _mutex.lock();
            }
            _mutex.unlock();
        });

        // Create connection
        {
            struct lws_client_connect_info connectInfo;
            memset(&connectInfo, 0, sizeof(connectInfo));

            connectInfo.context = _pLwsContext;
            connectInfo.address = addr.c_str();
            connectInfo.port = port;
            if (useSSL)
            {
                connectInfo.ssl_connection =
                    LCCSCF_USE_SSL
#if defined(BC_SSL_ALLOW_SELFSIGNED)
                    | LCCSCF_ALLOW_SELFSIGNED
#endif
                    // | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
                    // | LCCSCF_ALLOW_EXPIRED
                    ;
            }
            else
            {
                connectInfo.ssl_connection = 0;
            }
            connectInfo.path = path.c_str();
            connectInfo.host = host.c_str();
            connectInfo.origin = origin.c_str();
            connectInfo.protocol = protocols[0].name;
            connectInfo.ietf_version_or_minus_one = -1;
            connectInfo.userdata = this;

            _pLws = lws_client_connect_via_info(&connectInfo);
            if (!_pLws)
            {
                std::cout << "Failed to create websocket context" << std::endl;
                return;
            }
        }
    }

    int DefaultWebSocket::libWebsocketsCallback(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len)
    {
        DefaultWebSocket *pWebSocket = (DefaultWebSocket *)lws_wsi_user(wsi);

        switch (reason)
        {
            case LWS_CALLBACK_WSI_DESTROY:
            case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
            case LWS_CALLBACK_CLOSED:
            {
                if (!pWebSocket)
                {
                    return -1;
                }
                pWebSocket->onClose();
                break;
            }
            case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
            {
                if (!pWebSocket || !in)
                {
                    return -1;
                }
                pWebSocket->onError((const char*)in);
                break;
            }
            case LWS_CALLBACK_CLIENT_ESTABLISHED:
            {
                if (!pWebSocket)
                {
                    return -1;
                }
                pWebSocket->onConnect();
                break;
            }
            case LWS_CALLBACK_CLIENT_RECEIVE:
            {
                if (!pWebSocket || !in)
                {
                    return -1;
                }
                pWebSocket->onRecv((const char*)in, (int)len);
                break;
            }
            case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
            {
                if (!pWebSocket || !in)
                {
                    return -1;
                }

                unsigned char **p = (unsigned char **)in;
                unsigned char *end = (*p) + len;
                if (!pWebSocket->onProcessHeaders(p, end))
                {
                    return -1;
                }
                break;
            }
            case LWS_CALLBACK_CLIENT_WRITEABLE:
            {
                if (!pWebSocket)
                {
                    return -1;
                }
                pWebSocket->processSendQueue();
                break;
            }
            default:
                break;
        }

        return 0;
    }

    bool DefaultWebSocket::isValid()
    {
        std::unique_lock<std::mutex> lock(_mutex);

        if (_isConnecting)
        {
            _connectionCondition.wait(lock, [this]() { return !_isConnecting; });
        }

        return _isValid;
    }

    void DefaultWebSocket::send(const std::string& message)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _sendQueue.push(message);
    }

    void DefaultWebSocket::processSendQueue()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        while (!_sendQueue.empty())
        {
            const std::string& message = _sendQueue.front();

            _sendBuffer.resize(LWS_PRE + message.size());
            memcpy(_sendBuffer.data() + LWS_PRE, message.c_str(), message.size());
            lws_write(_pLws, _sendBuffer.data() + LWS_PRE, message.size(), LWS_WRITE_TEXT);

            _sendQueue.pop();
        }
    }

    std::string DefaultWebSocket::recv()
    {
        std::unique_lock<std::mutex> lock(_recvMutex);

        if (!_recvQueue.empty())
        {
            std::string message = _recvQueue.front();
            _recvQueue.pop();
            return message;
        }

        _recvCondition.wait(lock, [this]()
        {
            return !_isValid || !_recvQueue.empty();
        });

        if (_isValid && !_recvQueue.empty())
        {
            std::string message = _recvQueue.front();
            _recvQueue.pop();
            return message;
        }

        return "";
    }

    void DefaultWebSocket::close()
    {
        // Stop and clean send queue
        {
            std::unique_lock<std::mutex> lock(_mutex);
            while (!_sendQueue.empty()) _sendQueue.pop();
            _isValid = false;
            _isConnecting = false;
            _connectionCondition.notify_all();
        }

        // Stop and clean recving
        {
            std::unique_lock<std::mutex> lock(_recvMutex);
            while (!_recvQueue.empty()) _recvQueue.pop();
            _recvCondition.notify_all();
        }

        // Join update thread
        if (_updateThread.joinable())
        {
            _updateThread.join();
        }

        // Destroy libWebSockets
        if (_pLws)
        {
            lws_set_timeout(_pLws, NO_PENDING_TIMEOUT, LWS_TO_KILL_SYNC);
            _pLws = NULL;
        }

        // Destroy the context
        if (_pLwsContext)
        {
            std::unique_lock<std::mutex> lock(lwsContextMutex);
            lws_context_destroy(_pLwsContext);
            _pLwsContext = NULL;
        }
    }

    void DefaultWebSocket::onClose()
    {
        std::cout << "WebSocket closed" << std::endl;

        std::unique_lock<std::mutex> lock(_mutex);
        _isValid = false;
        _isConnecting = false;
        _connectionCondition.notify_all();
        _pLws = NULL; // This is now invalid
    }

    void DefaultWebSocket::onError(const char* msg)
    {
        std::cout << "WebSocket error: " << msg << std::endl;

        std::unique_lock<std::mutex> lock(_mutex);
        _isValid = false;
        _isConnecting = false;
        _connectionCondition.notify_all();
        _pLws = NULL; // This is now invalid
    }

    void DefaultWebSocket::onConnect()
    {
        std::cout << "WebSocket Connected!" << std::endl;

        std::unique_lock<std::mutex> lock(_mutex);
        _isValid = true;
        _isConnecting = false;
        _connectionCondition.notify_all();
    }

    void DefaultWebSocket::onRecv(const char* buffer, int len)
    {
        std::unique_lock<std::mutex> lock(_recvMutex);
        std::string message(buffer, len);
        _recvQueue.push(message);
        _recvCondition.notify_all();
    }

    bool DefaultWebSocket::onProcessHeaders(unsigned char** ppBuffer, unsigned char* pEnd)
    {
        if (_authHeaders.empty())
        {
            return true;
        }

        std::string key;

        for (std::map<std::string, std::string>::iterator it = _authHeaders.begin(); it != _authHeaders.end(); ++it)
        {
            key = it->first;
            key += ":";
            const std::string& value = it->second;

            if (lws_add_http_header_by_name(_pLws, (const unsigned char *)key.c_str(), (const unsigned char *)value.c_str(), (int)value.size(), ppBuffer, pEnd))
            {
                return false;
            }
        }

        return true;
    }
};

#endif
<commit_msg>Fixed log for WS to make it easier to debug<commit_after>#if (TARGET_OS_WATCH != 1)

#include "braincloud/internal/DefaultWebSocket.h"

#include <algorithm>
#include <iostream>
#include <cctype>

#define MAX_PAYLOAD (64 * 1024)

static std::mutex lwsContextMutex;

namespace BrainCloud
{
    static struct lws_protocols protocols[] = {
        {
            "brainCloud",
            &DefaultWebSocket::libWebsocketsCallback,
            0,
            MAX_PAYLOAD,
            0, NULL, 0
        },
        { NULL, NULL, 0, 0 } /* terminator */
    };

    static const struct lws_extension exts[] = {
        {
            "permessage-deflate",
            lws_extension_callback_pm_deflate,
            "permessage-deflate; client_no_context_takeover"
        },
        {
            "deflate-frame",
            lws_extension_callback_pm_deflate,
            "deflate_frame"
        },
        { NULL, NULL, NULL /* terminator */ }
    };

    IWebSocket* IWebSocket::create(const std::string& address, int port, const std::map<std::string, std::string>& headers)
    {
        return new DefaultWebSocket(address, port, headers);
    }

    //struct lws_context* DefaultWebSocket::_pLwsContext = NULL;

    DefaultWebSocket::~DefaultWebSocket()
    {
        close();
    }

    DefaultWebSocket::DefaultWebSocket(const std::string& uri, int port, const std::map<std::string, std::string>& headers)
        : _isValid(false)
        , _pLwsContext(NULL)
        , _pLws(NULL)
        , _isConnecting(true)
        , _authHeaders(headers)
    {
        std::string uriCopy = uri;

        // Split address into host/addr/origin/protocol
        std::string protocol = uriCopy.substr(0, std::min<size_t>(uriCopy.size(), uriCopy.find_first_of(':')));
        size_t protocolSize = protocol.size() + 3;
        size_t argsPos = std::min<size_t>(uriCopy.size(), uriCopy.find_first_of('?', protocolSize));
        if (uriCopy[argsPos - 1] != '/')
        {
            uriCopy.insert(uriCopy.begin() + argsPos, '/');
        }
        size_t slashPos = std::min<size_t>(uriCopy.size(), uriCopy.find_first_of('/', protocolSize));
        std::string path = uriCopy.substr(slashPos);
        if (path.empty())
        {
            path = "/";
        }
        std::string addr = uriCopy.substr(protocolSize, slashPos - protocolSize);
        std::string host = addr;
        std::string origin = host + ":" + std::to_string(port);

        // Validate
        std::string protocolCaps = protocol;
        std::transform(protocol.begin(), protocol.end(), protocolCaps.begin(), [](unsigned char c){ return std::toupper(c); });
        if (protocolCaps != "WS" && protocolCaps != "WSS")
        {
            std::cout << "Invalid websocket protocol: " << protocol << std::endl;
            return;
        }
        bool useSSL = protocolCaps == "WSS";

        // Create context
        //if (!_pLwsContext)
        {
            struct lws_context_creation_info info;
            memset(&info, 0, sizeof info);

            info.port = CONTEXT_PORT_NO_LISTEN;
            info.protocols = protocols;
            info.gid = -1;
            info.uid = -1;
            info.extensions = exts;
            info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;
            info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;

            std::unique_lock<std::mutex> lock(lwsContextMutex);
            _pLwsContext = lws_create_context(&info);
            if (!_pLwsContext)
            {
                std::cout << "Failed to create websocket context" << std::endl;
                return;
            }
        }

        // Start update thread
        _updateThread = std::thread([this]()
        {
            _mutex.lock();
            while (_isConnecting || _isValid)
            {
                _mutex.unlock();
                lws_callback_on_writable_all_protocol(_pLwsContext, &protocols[0]);
                lws_service(_pLwsContext, 100);
                _mutex.lock();
            }
            _mutex.unlock();
        });

        // Create connection
        {
            struct lws_client_connect_info connectInfo;
            memset(&connectInfo, 0, sizeof(connectInfo));

            connectInfo.context = _pLwsContext;
            connectInfo.address = addr.c_str();
            connectInfo.port = port;
            if (useSSL)
            {
                connectInfo.ssl_connection =
                    LCCSCF_USE_SSL
#if defined(BC_SSL_ALLOW_SELFSIGNED)
                    | LCCSCF_ALLOW_SELFSIGNED
#endif
                    // | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
                    // | LCCSCF_ALLOW_EXPIRED
                    ;
            }
            else
            {
                connectInfo.ssl_connection = 0;
            }
            connectInfo.path = path.c_str();
            connectInfo.host = host.c_str();
            connectInfo.origin = origin.c_str();
            connectInfo.protocol = protocols[0].name;
            connectInfo.ietf_version_or_minus_one = -1;
            connectInfo.userdata = this;

            _pLws = lws_client_connect_via_info(&connectInfo);
            if (!_pLws)
            {
                std::cout << "Failed to create websocket client" << std::endl;
                return;
            }
        }
    }

    int DefaultWebSocket::libWebsocketsCallback(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len)
    {
        DefaultWebSocket *pWebSocket = (DefaultWebSocket *)lws_wsi_user(wsi);

        switch (reason)
        {
            case LWS_CALLBACK_WSI_DESTROY:
            case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
            case LWS_CALLBACK_CLOSED:
            {
                if (!pWebSocket)
                {
                    return -1;
                }
                pWebSocket->onClose();
                break;
            }
            case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
            {
                if (!pWebSocket || !in)
                {
                    return -1;
                }
                pWebSocket->onError((const char*)in);
                break;
            }
            case LWS_CALLBACK_CLIENT_ESTABLISHED:
            {
                if (!pWebSocket)
                {
                    return -1;
                }
                pWebSocket->onConnect();
                break;
            }
            case LWS_CALLBACK_CLIENT_RECEIVE:
            {
                if (!pWebSocket || !in)
                {
                    return -1;
                }
                pWebSocket->onRecv((const char*)in, (int)len);
                break;
            }
            case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
            {
                if (!pWebSocket || !in)
                {
                    return -1;
                }

                unsigned char **p = (unsigned char **)in;
                unsigned char *end = (*p) + len;
                if (!pWebSocket->onProcessHeaders(p, end))
                {
                    return -1;
                }
                break;
            }
            case LWS_CALLBACK_CLIENT_WRITEABLE:
            {
                if (!pWebSocket)
                {
                    return -1;
                }
                pWebSocket->processSendQueue();
                break;
            }
            default:
                break;
        }

        return 0;
    }

    bool DefaultWebSocket::isValid()
    {
        std::unique_lock<std::mutex> lock(_mutex);

        if (_isConnecting)
        {
            _connectionCondition.wait(lock, [this]() { return !_isConnecting; });
        }

        return _isValid;
    }

    void DefaultWebSocket::send(const std::string& message)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _sendQueue.push(message);
    }

    void DefaultWebSocket::processSendQueue()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        while (!_sendQueue.empty())
        {
            const std::string& message = _sendQueue.front();

            _sendBuffer.resize(LWS_PRE + message.size());
            memcpy(_sendBuffer.data() + LWS_PRE, message.c_str(), message.size());
            lws_write(_pLws, _sendBuffer.data() + LWS_PRE, message.size(), LWS_WRITE_TEXT);

            _sendQueue.pop();
        }
    }

    std::string DefaultWebSocket::recv()
    {
        std::unique_lock<std::mutex> lock(_recvMutex);

        if (!_recvQueue.empty())
        {
            std::string message = _recvQueue.front();
            _recvQueue.pop();
            return message;
        }

        _recvCondition.wait(lock, [this]()
        {
            return !_isValid || !_recvQueue.empty();
        });

        if (_isValid && !_recvQueue.empty())
        {
            std::string message = _recvQueue.front();
            _recvQueue.pop();
            return message;
        }

        return "";
    }

    void DefaultWebSocket::close()
    {
        // Stop and clean send queue
        {
            std::unique_lock<std::mutex> lock(_mutex);
            while (!_sendQueue.empty()) _sendQueue.pop();
            _isValid = false;
            _isConnecting = false;
            _connectionCondition.notify_all();
        }

        // Stop and clean recving
        {
            std::unique_lock<std::mutex> lock(_recvMutex);
            while (!_recvQueue.empty()) _recvQueue.pop();
            _recvCondition.notify_all();
        }

        // Join update thread
        if (_updateThread.joinable())
        {
            _updateThread.join();
        }

        // Destroy libWebSockets
        if (_pLws)
        {
            lws_set_timeout(_pLws, NO_PENDING_TIMEOUT, LWS_TO_KILL_SYNC);
            _pLws = NULL;
        }

        // Destroy the context
        if (_pLwsContext)
        {
            std::unique_lock<std::mutex> lock(lwsContextMutex);
            lws_context_destroy(_pLwsContext);
            _pLwsContext = NULL;
        }
    }

    void DefaultWebSocket::onClose()
    {
        std::cout << "WebSocket closed" << std::endl;

        std::unique_lock<std::mutex> lock(_mutex);
        _isValid = false;
        _isConnecting = false;
        _connectionCondition.notify_all();
        _pLws = NULL; // This is now invalid
    }

    void DefaultWebSocket::onError(const char* msg)
    {
        std::cout << "WebSocket error: " << msg << std::endl;

        std::unique_lock<std::mutex> lock(_mutex);
        _isValid = false;
        _isConnecting = false;
        _connectionCondition.notify_all();
        _pLws = NULL; // This is now invalid
    }

    void DefaultWebSocket::onConnect()
    {
        std::cout << "WebSocket Connected!" << std::endl;

        std::unique_lock<std::mutex> lock(_mutex);
        _isValid = true;
        _isConnecting = false;
        _connectionCondition.notify_all();
    }

    void DefaultWebSocket::onRecv(const char* buffer, int len)
    {
        std::unique_lock<std::mutex> lock(_recvMutex);
        std::string message(buffer, len);
        _recvQueue.push(message);
        _recvCondition.notify_all();
    }

    bool DefaultWebSocket::onProcessHeaders(unsigned char** ppBuffer, unsigned char* pEnd)
    {
        if (_authHeaders.empty())
        {
            return true;
        }

        std::string key;

        for (std::map<std::string, std::string>::iterator it = _authHeaders.begin(); it != _authHeaders.end(); ++it)
        {
            key = it->first;
            key += ":";
            const std::string& value = it->second;

            if (lws_add_http_header_by_name(_pLws, (const unsigned char *)key.c_str(), (const unsigned char *)value.c_str(), (int)value.size(), ppBuffer, pEnd))
            {
                return false;
            }
        }

        return true;
    }
};

#endif
<|endoftext|>


<commit_before>// Cuboid.cpp
// Copyright (c) 2009, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.

#include "stdafx.h"
#include "Cuboid.h"
#include "../interface/PropertyVertex.h"
#include "../interface/PropertyDouble.h"
#include "../interface/PropertyLength.h"
#include "Gripper.h"
#include "MarkedList.h"

CCuboid::CCuboid(const gp_Ax2& pos, double x, double y, double z, const wxChar* title, const HeeksColor& col):CSolid(BRepPrimAPI_MakeBox(pos, x, y, z), title, col), m_pos(pos), m_x(x), m_y(y), m_z(z)
{
}

CCuboid::CCuboid(const TopoDS_Solid &solid, const wxChar* title, const HeeksColor& col):CSolid(solid, title, col), m_pos(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1), gp_Dir(1, 0, 0)), m_x(0.0), m_y(0.0), m_z(0.0)
{
}

const wxBitmap &CCuboid::GetIcon()
{
	static wxBitmap* icon = NULL;
	if(icon == NULL)icon = new wxBitmap(wxImage(wxGetApp().GetResFolder() + _T("/icons/cube.png")));
	return *icon;
}

HeeksObj *CCuboid::MakeACopy(void)const
{
	return new CCuboid(*this);
}

CCuboid::CCuboid( const CCuboid & rhs ) : CSolid(rhs)
{
    *this = rhs;    // Call the assignment operator.
}

CCuboid & CCuboid::operator= ( const CCuboid & rhs )
{
    if (this != &rhs)
    {
        m_pos = rhs.m_pos;
        m_x = rhs.m_x;
        m_y = rhs.m_y;
        m_z = rhs.m_z;

        CSolid::operator=( rhs );
    }

    return(*this);
}

bool CCuboid::IsDifferent(HeeksObj* other)
{
	CCuboid* cube = (CCuboid*)other;
	if(cube->m_x != m_x || cube->m_y != m_y || cube->m_z != m_z)
		return true;

	if(!IsEqual(cube->m_pos,m_pos))
		return true;

	return CShape::IsDifferent(other);
}

static void on_set_centre(const double *vt, HeeksObj* object){
	gp_Trsf mat;
	mat.SetTranslation ( gp_Vec ( ((CCuboid*)object)->m_pos.Location(), make_point(vt) ) );
	((CCuboid*)object)->m_pos.Transform(mat);
}

static void on_set_x(double value, HeeksObj* object){
	((CCuboid*)object)->m_x = value;
}

static void on_set_y(double value, HeeksObj* object){
	((CCuboid*)object)->m_y = value;
}

static void on_set_z(double value, HeeksObj* object){
	((CCuboid*)object)->m_z = value;
}

void CCuboid::MakeTransformedShape(const gp_Trsf &mat)
{
	m_pos.Transform(mat);
	double scale = gp_Vec(1, 0, 0).Transformed(mat).Magnitude();
	m_x = fabs(m_x * scale);
	m_y = fabs(m_y * scale);
	m_z = fabs(m_z * scale);
	m_shape = BRepPrimAPI_MakeBox(m_pos, m_x, m_y, m_z).Shape();
}

wxString CCuboid::StretchedName(){ return _("Stretched Cuboid");}

void CCuboid::GetProperties(std::list<Property *> *list)
{
	double pos[3];
	extract(m_pos.Location(), pos);
	list->push_back(new PropertyVertex(_("datum corner"), pos, this, on_set_centre));
	list->push_back(new PropertyLength(_("width ( x )"), m_x, this, on_set_x));
	list->push_back(new PropertyLength(_("height( y )"), m_y, this, on_set_y));
	list->push_back(new PropertyLength(_("depth ( z )"), m_z, this, on_set_z));

	CSolid::GetProperties(list);
}

class CCuboidCanvas: public ObjectCanvas
{
public:
	CCuboidCanvas::CCuboidCanvas(wxWindow* parent) : ObjectCanvas(parent)
	{
		// just draw a picture of a cube with some text
		PictureFrame* picture = new PictureFrame(this, wxImage(wxGetApp().GetResFolder() + _T("/bitmaps/dlgcuboid.png")));
		wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
		sizer->Add(picture, 1, wxGROW);
		SetSizer(sizer);
	}
};

static CCuboidCanvas* object_canvas = NULL;

ObjectCanvas* CCuboid::GetDialog(wxWindow* parent)
{
	if(object_canvas == NULL)object_canvas = new CCuboidCanvas(parent);
	return object_canvas;
}

void CCuboid::GetGripperPositions(std::list<GripData> *list, bool just_for_endof)
{
	gp_Pnt o = m_pos.Location();
	gp_Pnt px(o.XYZ() + m_pos.XDirection().XYZ() * m_x);
	gp_Pnt py(o.XYZ() + m_pos.YDirection().XYZ() * m_y);
	gp_Dir z_dir = m_pos.XDirection() ^ m_pos.YDirection();
	gp_Pnt pz(o.XYZ() + z_dir.XYZ() * m_z);
	gp_Pnt m2(o.XYZ() + m_pos.XDirection().XYZ() * m_x + m_pos.YDirection().XYZ() * m_y/2);
	gp_Pnt m3(o.XYZ() + m_pos.XDirection().XYZ() * m_x/2 + m_pos.YDirection().XYZ() * m_y);
	gp_Pnt m8(o.XYZ() + m_pos.YDirection().XYZ() * m_y/2 + z_dir.XYZ() * m_z);
	gp_Pnt pxy(o.XYZ() + m_pos.XDirection().XYZ() * m_x + m_pos.YDirection().XYZ() * m_y);
	gp_Pnt pxz(o.XYZ() + m_pos.XDirection().XYZ() * m_x + z_dir.XYZ() * m_z);
	gp_Pnt pyz(o.XYZ() + m_pos.YDirection().XYZ() * m_y + z_dir.XYZ() * m_z);
	gp_Pnt pxyz(o.XYZ() + m_pos.XDirection().XYZ() * m_x  + m_pos.YDirection().XYZ() * m_y + z_dir.XYZ() * m_z);
	list->push_back(GripData(GripperTypeTranslate,o.X(),o.Y(),o.Z(),NULL));
	list->push_back(GripData(GripperTypeRotateObject,px.X(),px.Y(),px.Z(),NULL));
	list->push_back(GripData(GripperTypeRotateObject,py.X(),py.Y(),py.Z(),NULL));
	list->push_back(GripData(GripperTypeRotateObject,pz.X(),pz.Y(),pz.Z(),NULL));
	list->push_back(GripData(GripperTypeScale,pxyz.X(),pxyz.Y(),pxyz.Z(),NULL));
	list->push_back(GripData(GripperTypeRotate,pxy.X(),pxy.Y(),pxy.Z(),NULL));
	list->push_back(GripData(GripperTypeRotate,pxz.X(),pxz.Y(),pxz.Z(),NULL));
	list->push_back(GripData(GripperTypeRotate,pyz.X(),pyz.Y(),pyz.Z(),NULL));
	list->push_back(GripData(GripperTypeObjectScaleX,m2.X(),m2.Y(),m2.Z(),NULL));
	list->push_back(GripData(GripperTypeObjectScaleY,m3.X(),m3.Y(),m3.Z(),NULL));
	list->push_back(GripData(GripperTypeObjectScaleZ,m8.X(),m8.Y(),m8.Z(),NULL));
}

void CCuboid::OnApplyProperties()
{
	CCuboid* new_object = new CCuboid(m_pos, m_x, m_y, m_z, m_title.c_str(), m_color);
	new_object->CopyIDsFrom(this);
	Owner()->Add(new_object, NULL);
	Owner()->Remove(this);
	if(wxGetApp().m_marked_list->ObjectMarked(this))
	{
		wxGetApp().m_marked_list->Remove(this, false);
		wxGetApp().m_marked_list->Add(new_object, true);
	}
	wxGetApp().Repaint();
}

bool CCuboid::GetScaleAboutMatrix(double *m)
{
	gp_Trsf mat = make_matrix(m_pos.Location(), m_pos.XDirection(), m_pos.YDirection());
	extract(mat, m);
	return true;
}

bool CCuboid::Stretch(const double *p, const double* shift, void* data)
{
	gp_Pnt vp = make_point(p);
	gp_Vec vshift = make_vector(shift);

	gp_Pnt o = m_pos.Location();
	gp_Dir z_dir = m_pos.XDirection() ^ m_pos.YDirection();
	gp_Pnt m2(o.XYZ() + m_pos.XDirection().XYZ() * m_x + m_pos.YDirection().XYZ() * m_y/2);
	gp_Pnt m3(o.XYZ() + m_pos.XDirection().XYZ() * m_x/2 + m_pos.YDirection().XYZ() * m_y);
	gp_Pnt m8(o.XYZ() + m_pos.YDirection().XYZ() * m_y/2 + z_dir.XYZ() * m_z);

	bool make_a_new_cuboid = false;

	if(m2.IsEqual(vp, wxGetApp().m_geom_tol)){
		m2 = m2.XYZ() + vshift.XYZ();
		double new_x = gp_Vec(m2.XYZ()) * gp_Vec(m_pos.XDirection()) - gp_Vec(o.XYZ()) * gp_Vec(m_pos.XDirection());
		if(new_x > 0){
			make_a_new_cuboid = true;
			m_x = new_x;
		}
	}
	else if(m3.IsEqual(vp, wxGetApp().m_geom_tol)){
		m3 = m3.XYZ() + vshift.XYZ();
		double new_y = gp_Vec(m3.XYZ()) * gp_Vec(m_pos.YDirection()) - gp_Vec(o.XYZ()) * gp_Vec(m_pos.YDirection());
		if(new_y > 0){
			make_a_new_cuboid = true;
			m_y = new_y;
		}
	}
	else if(m8.IsEqual(vp, wxGetApp().m_geom_tol)){
		m8 = m8.XYZ() + vshift.XYZ();
		double new_z = gp_Vec(m8.XYZ()) * gp_Vec(z_dir) - gp_Vec(o.XYZ()) * gp_Vec(z_dir);
		if(new_z > 0){
			make_a_new_cuboid = true;
			m_z = new_z;
		}
	}

	if(make_a_new_cuboid)
	{
		CCuboid* new_object = new CCuboid(m_pos, m_x, m_y, m_z, m_title.c_str(), m_color);
		new_object->CopyIDsFrom(this);
		Owner()->Add(new_object, NULL);
		Owner()->Remove(this);
		wxGetApp().m_marked_list->Clear(false);
		wxGetApp().m_marked_list->Add(new_object, true);
	}

	return true;
}

void CCuboid::SetXMLElement(TiXmlElement* element)
{
	const gp_Pnt& l = m_pos.Location();
	element->SetDoubleAttribute("lx", l.X());
	element->SetDoubleAttribute("ly", l.Y());
	element->SetDoubleAttribute("lz", l.Z());

	const gp_Dir& d = m_pos.Direction();
	element->SetDoubleAttribute("dx", d.X());
	element->SetDoubleAttribute("dy", d.Y());
	element->SetDoubleAttribute("dz", d.Z());

	const gp_Dir& x = m_pos.XDirection();
	element->SetDoubleAttribute("xx", x.X());
	element->SetDoubleAttribute("xy", x.Y());
	element->SetDoubleAttribute("xz", x.Z());

	element->SetDoubleAttribute("wx", m_x);
	element->SetDoubleAttribute("wy", m_y);
	element->SetDoubleAttribute("wz", m_z);

	CSolid::SetXMLElement(element);
}

void CCuboid::SetFromXMLElement(TiXmlElement* pElem)
{
	double l[3] = {0, 0, 0};
	double d[3] = {0, 0, 1};
	double x[3] = {1, 0, 0};

	for(TiXmlAttribute* a = pElem->FirstAttribute(); a; a = a->Next())
	{
		std::string name(a->Name());
		if(name == "lx")	 {l[0] = a->DoubleValue();}
		else if(name == "ly"){l[1] = a->DoubleValue();}
		else if(name == "lz"){l[2] = a->DoubleValue();}

		else if(name == "dx"){d[0] = a->DoubleValue();}
		else if(name == "dy"){d[1] = a->DoubleValue();}
		else if(name == "dz"){d[2] = a->DoubleValue();}

		else if(name == "xx"){x[0] = a->DoubleValue();}
		else if(name == "xy"){x[1] = a->DoubleValue();}
		else if(name == "xz"){x[2] = a->DoubleValue();}

		else if(name == "wx"){m_x = a->DoubleValue();}
		else if(name == "wy"){m_y = a->DoubleValue();}
		else if(name == "wz"){m_z = a->DoubleValue();}
	}

	m_pos = gp_Ax2(make_point(l), make_vector(d), make_vector(x));

	CSolid::SetFromXMLElement(pElem);
}
<commit_msg>fixed  extra qualification ‘CCuboidCanvas::’ in Ubuntu build<commit_after>// Cuboid.cpp
// Copyright (c) 2009, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.

#include "stdafx.h"
#include "Cuboid.h"
#include "../interface/PropertyVertex.h"
#include "../interface/PropertyDouble.h"
#include "../interface/PropertyLength.h"
#include "Gripper.h"
#include "MarkedList.h"

CCuboid::CCuboid(const gp_Ax2& pos, double x, double y, double z, const wxChar* title, const HeeksColor& col):CSolid(BRepPrimAPI_MakeBox(pos, x, y, z), title, col), m_pos(pos), m_x(x), m_y(y), m_z(z)
{
}

CCuboid::CCuboid(const TopoDS_Solid &solid, const wxChar* title, const HeeksColor& col):CSolid(solid, title, col), m_pos(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1), gp_Dir(1, 0, 0)), m_x(0.0), m_y(0.0), m_z(0.0)
{
}

const wxBitmap &CCuboid::GetIcon()
{
	static wxBitmap* icon = NULL;
	if(icon == NULL)icon = new wxBitmap(wxImage(wxGetApp().GetResFolder() + _T("/icons/cube.png")));
	return *icon;
}

HeeksObj *CCuboid::MakeACopy(void)const
{
	return new CCuboid(*this);
}

CCuboid::CCuboid( const CCuboid & rhs ) : CSolid(rhs)
{
    *this = rhs;    // Call the assignment operator.
}

CCuboid & CCuboid::operator= ( const CCuboid & rhs )
{
    if (this != &rhs)
    {
        m_pos = rhs.m_pos;
        m_x = rhs.m_x;
        m_y = rhs.m_y;
        m_z = rhs.m_z;

        CSolid::operator=( rhs );
    }

    return(*this);
}

bool CCuboid::IsDifferent(HeeksObj* other)
{
	CCuboid* cube = (CCuboid*)other;
	if(cube->m_x != m_x || cube->m_y != m_y || cube->m_z != m_z)
		return true;

	if(!IsEqual(cube->m_pos,m_pos))
		return true;

	return CShape::IsDifferent(other);
}

static void on_set_centre(const double *vt, HeeksObj* object){
	gp_Trsf mat;
	mat.SetTranslation ( gp_Vec ( ((CCuboid*)object)->m_pos.Location(), make_point(vt) ) );
	((CCuboid*)object)->m_pos.Transform(mat);
}

static void on_set_x(double value, HeeksObj* object){
	((CCuboid*)object)->m_x = value;
}

static void on_set_y(double value, HeeksObj* object){
	((CCuboid*)object)->m_y = value;
}

static void on_set_z(double value, HeeksObj* object){
	((CCuboid*)object)->m_z = value;
}

void CCuboid::MakeTransformedShape(const gp_Trsf &mat)
{
	m_pos.Transform(mat);
	double scale = gp_Vec(1, 0, 0).Transformed(mat).Magnitude();
	m_x = fabs(m_x * scale);
	m_y = fabs(m_y * scale);
	m_z = fabs(m_z * scale);
	m_shape = BRepPrimAPI_MakeBox(m_pos, m_x, m_y, m_z).Shape();
}

wxString CCuboid::StretchedName(){ return _("Stretched Cuboid");}

void CCuboid::GetProperties(std::list<Property *> *list)
{
	double pos[3];
	extract(m_pos.Location(), pos);
	list->push_back(new PropertyVertex(_("datum corner"), pos, this, on_set_centre));
	list->push_back(new PropertyLength(_("width ( x )"), m_x, this, on_set_x));
	list->push_back(new PropertyLength(_("height( y )"), m_y, this, on_set_y));
	list->push_back(new PropertyLength(_("depth ( z )"), m_z, this, on_set_z));

	CSolid::GetProperties(list);
}

class CCuboidCanvas: public ObjectCanvas
{
public:
	CCuboidCanvas(wxWindow* parent) : ObjectCanvas(parent)
	{
		// just draw a picture of a cube with some text
		PictureFrame* picture = new PictureFrame(this, wxImage(wxGetApp().GetResFolder() + _T("/bitmaps/dlgcuboid.png")));
		wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
		sizer->Add(picture, 1, wxGROW);
		SetSizer(sizer);
	}
};

static CCuboidCanvas* object_canvas = NULL;

ObjectCanvas* CCuboid::GetDialog(wxWindow* parent)
{
	if(object_canvas == NULL)object_canvas = new CCuboidCanvas(parent);
	return object_canvas;
}

void CCuboid::GetGripperPositions(std::list<GripData> *list, bool just_for_endof)
{
	gp_Pnt o = m_pos.Location();
	gp_Pnt px(o.XYZ() + m_pos.XDirection().XYZ() * m_x);
	gp_Pnt py(o.XYZ() + m_pos.YDirection().XYZ() * m_y);
	gp_Dir z_dir = m_pos.XDirection() ^ m_pos.YDirection();
	gp_Pnt pz(o.XYZ() + z_dir.XYZ() * m_z);
	gp_Pnt m2(o.XYZ() + m_pos.XDirection().XYZ() * m_x + m_pos.YDirection().XYZ() * m_y/2);
	gp_Pnt m3(o.XYZ() + m_pos.XDirection().XYZ() * m_x/2 + m_pos.YDirection().XYZ() * m_y);
	gp_Pnt m8(o.XYZ() + m_pos.YDirection().XYZ() * m_y/2 + z_dir.XYZ() * m_z);
	gp_Pnt pxy(o.XYZ() + m_pos.XDirection().XYZ() * m_x + m_pos.YDirection().XYZ() * m_y);
	gp_Pnt pxz(o.XYZ() + m_pos.XDirection().XYZ() * m_x + z_dir.XYZ() * m_z);
	gp_Pnt pyz(o.XYZ() + m_pos.YDirection().XYZ() * m_y + z_dir.XYZ() * m_z);
	gp_Pnt pxyz(o.XYZ() + m_pos.XDirection().XYZ() * m_x  + m_pos.YDirection().XYZ() * m_y + z_dir.XYZ() * m_z);
	list->push_back(GripData(GripperTypeTranslate,o.X(),o.Y(),o.Z(),NULL));
	list->push_back(GripData(GripperTypeRotateObject,px.X(),px.Y(),px.Z(),NULL));
	list->push_back(GripData(GripperTypeRotateObject,py.X(),py.Y(),py.Z(),NULL));
	list->push_back(GripData(GripperTypeRotateObject,pz.X(),pz.Y(),pz.Z(),NULL));
	list->push_back(GripData(GripperTypeScale,pxyz.X(),pxyz.Y(),pxyz.Z(),NULL));
	list->push_back(GripData(GripperTypeRotate,pxy.X(),pxy.Y(),pxy.Z(),NULL));
	list->push_back(GripData(GripperTypeRotate,pxz.X(),pxz.Y(),pxz.Z(),NULL));
	list->push_back(GripData(GripperTypeRotate,pyz.X(),pyz.Y(),pyz.Z(),NULL));
	list->push_back(GripData(GripperTypeObjectScaleX,m2.X(),m2.Y(),m2.Z(),NULL));
	list->push_back(GripData(GripperTypeObjectScaleY,m3.X(),m3.Y(),m3.Z(),NULL));
	list->push_back(GripData(GripperTypeObjectScaleZ,m8.X(),m8.Y(),m8.Z(),NULL));
}

void CCuboid::OnApplyProperties()
{
	CCuboid* new_object = new CCuboid(m_pos, m_x, m_y, m_z, m_title.c_str(), m_color);
	new_object->CopyIDsFrom(this);
	Owner()->Add(new_object, NULL);
	Owner()->Remove(this);
	if(wxGetApp().m_marked_list->ObjectMarked(this))
	{
		wxGetApp().m_marked_list->Remove(this, false);
		wxGetApp().m_marked_list->Add(new_object, true);
	}
	wxGetApp().Repaint();
}

bool CCuboid::GetScaleAboutMatrix(double *m)
{
	gp_Trsf mat = make_matrix(m_pos.Location(), m_pos.XDirection(), m_pos.YDirection());
	extract(mat, m);
	return true;
}

bool CCuboid::Stretch(const double *p, const double* shift, void* data)
{
	gp_Pnt vp = make_point(p);
	gp_Vec vshift = make_vector(shift);

	gp_Pnt o = m_pos.Location();
	gp_Dir z_dir = m_pos.XDirection() ^ m_pos.YDirection();
	gp_Pnt m2(o.XYZ() + m_pos.XDirection().XYZ() * m_x + m_pos.YDirection().XYZ() * m_y/2);
	gp_Pnt m3(o.XYZ() + m_pos.XDirection().XYZ() * m_x/2 + m_pos.YDirection().XYZ() * m_y);
	gp_Pnt m8(o.XYZ() + m_pos.YDirection().XYZ() * m_y/2 + z_dir.XYZ() * m_z);

	bool make_a_new_cuboid = false;

	if(m2.IsEqual(vp, wxGetApp().m_geom_tol)){
		m2 = m2.XYZ() + vshift.XYZ();
		double new_x = gp_Vec(m2.XYZ()) * gp_Vec(m_pos.XDirection()) - gp_Vec(o.XYZ()) * gp_Vec(m_pos.XDirection());
		if(new_x > 0){
			make_a_new_cuboid = true;
			m_x = new_x;
		}
	}
	else if(m3.IsEqual(vp, wxGetApp().m_geom_tol)){
		m3 = m3.XYZ() + vshift.XYZ();
		double new_y = gp_Vec(m3.XYZ()) * gp_Vec(m_pos.YDirection()) - gp_Vec(o.XYZ()) * gp_Vec(m_pos.YDirection());
		if(new_y > 0){
			make_a_new_cuboid = true;
			m_y = new_y;
		}
	}
	else if(m8.IsEqual(vp, wxGetApp().m_geom_tol)){
		m8 = m8.XYZ() + vshift.XYZ();
		double new_z = gp_Vec(m8.XYZ()) * gp_Vec(z_dir) - gp_Vec(o.XYZ()) * gp_Vec(z_dir);
		if(new_z > 0){
			make_a_new_cuboid = true;
			m_z = new_z;
		}
	}

	if(make_a_new_cuboid)
	{
		CCuboid* new_object = new CCuboid(m_pos, m_x, m_y, m_z, m_title.c_str(), m_color);
		new_object->CopyIDsFrom(this);
		Owner()->Add(new_object, NULL);
		Owner()->Remove(this);
		wxGetApp().m_marked_list->Clear(false);
		wxGetApp().m_marked_list->Add(new_object, true);
	}

	return true;
}

void CCuboid::SetXMLElement(TiXmlElement* element)
{
	const gp_Pnt& l = m_pos.Location();
	element->SetDoubleAttribute("lx", l.X());
	element->SetDoubleAttribute("ly", l.Y());
	element->SetDoubleAttribute("lz", l.Z());

	const gp_Dir& d = m_pos.Direction();
	element->SetDoubleAttribute("dx", d.X());
	element->SetDoubleAttribute("dy", d.Y());
	element->SetDoubleAttribute("dz", d.Z());

	const gp_Dir& x = m_pos.XDirection();
	element->SetDoubleAttribute("xx", x.X());
	element->SetDoubleAttribute("xy", x.Y());
	element->SetDoubleAttribute("xz", x.Z());

	element->SetDoubleAttribute("wx", m_x);
	element->SetDoubleAttribute("wy", m_y);
	element->SetDoubleAttribute("wz", m_z);

	CSolid::SetXMLElement(element);
}

void CCuboid::SetFromXMLElement(TiXmlElement* pElem)
{
	double l[3] = {0, 0, 0};
	double d[3] = {0, 0, 1};
	double x[3] = {1, 0, 0};

	for(TiXmlAttribute* a = pElem->FirstAttribute(); a; a = a->Next())
	{
		std::string name(a->Name());
		if(name == "lx")	 {l[0] = a->DoubleValue();}
		else if(name == "ly"){l[1] = a->DoubleValue();}
		else if(name == "lz"){l[2] = a->DoubleValue();}

		else if(name == "dx"){d[0] = a->DoubleValue();}
		else if(name == "dy"){d[1] = a->DoubleValue();}
		else if(name == "dz"){d[2] = a->DoubleValue();}

		else if(name == "xx"){x[0] = a->DoubleValue();}
		else if(name == "xy"){x[1] = a->DoubleValue();}
		else if(name == "xz"){x[2] = a->DoubleValue();}

		else if(name == "wx"){m_x = a->DoubleValue();}
		else if(name == "wy"){m_y = a->DoubleValue();}
		else if(name == "wz"){m_z = a->DoubleValue();}
	}

	m_pos = gp_Ax2(make_point(l), make_vector(d), make_vector(x));

	CSolid::SetFromXMLElement(pElem);
}
<|endoftext|>


<commit_before>#include <string.h> // strrchr, strncpy
#include <stdio.h> // stdout
#include <dummy/tap_reporter.h>

#include <engine/Common.h>

#include "TestTools.h"

void ChangeDirectoryToExecutableOrigin( const char* executablePath );

void TestLogHandler( LogLevel level, const char* line )
{
    switch(level)
    {
        case LOG_INFO:
            dummyLog("%s", line);
            break;

        case LOG_ERROR:
        case LOG_FATAL_ERROR:
            dummyLog("%s", line);
            break;

        default:
            assert(!"Unknown log level");
    }
}

void InitTests( int argc, char const * const * argv )
{
    ChangeDirectoryToExecutableOrigin(argv[0]);
    SetLogHandler(TestLogHandler);
    dummyInit(dummyGetTAPReporter(stdout));
    dummyAddInlineTests();
}

int RunTests()
{
    const int failedTests = dummyRunTests();
    SetLogHandler(DefaultLogHandler);
    //return failedTests; // TODO: prove marks failed tests as doubious, with this line
    return 0;
}

#if defined(WIN32)

#include <direct.h>
void ChangeDirectory( const char* directory )
{
    _chdir(directory);
}

#else

#include <unistd.h>
void ChangeDirectory( const char* directory )
{
    chdir(directory);
}

#endif

void ChangeDirectoryToExecutableOrigin( const char* executablePath )
{
#if defined(WIN32)
    const char seperator = '\\';
#else
    const char seperator = '/';
#endif
    const char* lastSeperator = strrchr(executablePath, seperator);
    if(lastSeperator)
    {
        char buffer[256];
        const int length = lastSeperator - executablePath;
        strncpy(buffer, executablePath, length);
        ChangeDirectory(buffer);
    }
    else
    {
        // Already in the directory of the executable.
    }
}
<commit_msg>Fixed test tools<commit_after>#include <string.h> // strrchr, strncpy
#include <stdio.h> // stdout
#include <dummy/tap_reporter.h>

#include <engine/Common.h>

#include "TestTools.h"

void ChangeDirectoryToExecutableOrigin( const char* executablePath );

void TestLogHandler( LogLevel level, const char* line )
{
    switch(level)
    {
        case LOG_INFO:
            dummyLog("%s", line);
            break;

        case LOG_ERROR:
        case LOG_FATAL_ERROR:
            dummyLog("%s", line);
            break;

        default:
            assert(!"Unknown log level");
    }
}

void InitTests( int argc, char const * const * argv )
{
    ChangeDirectoryToExecutableOrigin(argv[0]);
    SetLogHandler(TestLogHandler);
    dummyInit(dummyGetTAPReporter(stdout));
    dummyAddInlineTests();
}

int RunTests()
{
    const int failedTests = dummyRunTests();
    SetLogHandler(DefaultLogHandler);
    //return failedTests; // TODO: prove marks failed tests as doubious, with this line
    return 0;
}

#if defined(WIN32)

#include <direct.h>
void ChangeDirectory( const char* directory )
{
    _chdir(directory);
}

#else

#include <unistd.h>
void ChangeDirectory( const char* directory )
{
    chdir(directory);
}

#endif

void ChangeDirectoryToExecutableOrigin( const char* executablePath )
{
#if defined(WIN32)
    const char seperator = '\\';
#else
    const char seperator = '/';
#endif
    const char* lastSeperator = strrchr(executablePath, seperator);
    if(lastSeperator)
    {
        char buffer[256];
        const int length = lastSeperator - executablePath;
        strncpy(buffer, executablePath, length);
        buffer[length] = '\0';
        ChangeDirectory(buffer);
    }
    else
    {
        // Already in the directory of the executable.
    }
}
<|endoftext|>


<commit_before>#define DEBUG_TYPE "enerc"
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/BasicBlock.h"
#include "llvm/Module.h"
#include "llvm/Constants.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Instructions.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/PassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/IRBuilder.h"

#include <sstream>
#include <set>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>

#define ECQ_PRECISE 0
#define ECQ_APPROX 1

#define FUNC_TRACE "enerc_trace"

// I'm not sure why, but I can't seem to enable debug output in the usual way
// (with command line flags). Here's a hack.
#undef DEBUG
#define DEBUG(s) s

using namespace llvm;
namespace {

// Command-line flags.
cl::opt<bool> optInstrument ("accept-inst",
    cl::desc("ACCEPT: enable profiling instrumentation"));
cl::opt<bool> optRelax ("accept-relax",
    cl::desc("ACCEPT: enable relaxations"));

/**** HELPERS ****/

// Look at the qualifier metadata on the instruction and determine whether it
// has approximate semantics.
bool isApprox(Instruction *instr) {
  MDNode *md = instr->getMetadata("quals");
  if (!md)
    return false;

  Value *val = md->getOperand(0);
  ConstantInt *ci = cast<ConstantInt>(val);
  if (ci) {
    APInt intval = ci->getValue();
    return intval == ECQ_APPROX;
  } else {
    llvm::errs() << "INVALID METADATA";
    return false;
  }
}

// Is it legal to elide this instruction?
bool elidable_helper(Instruction *instr,
                     std::set<Instruction*> &seen) {
  // Check for cycles.
  if (seen.count(instr)) {
    llvm::errs() << "CYCLE DETECTED\n";
    return false;
  }
  seen.insert(instr);

  if (isApprox(instr)) {
    return true;
  } else if (isa<StoreInst>(instr) ||
             isa<ReturnInst>(instr) ||
             isa<BranchInst>(instr)) {
    // Precise stores, returns, branches: never elidable.
    return false;
  } else {
    // Recursive case: all consumers are elidable.
    for (Value::use_iterator ui = instr->use_begin();
          ui != instr->use_end(); ++ui) {
      Instruction *user = dyn_cast<Instruction>(*ui);
      if (user && !elidable_helper(user, seen)) {
        return false;
      }
    }
    return true; // No non-elidable consumers.
  }
}
// Start with an empty "seen" (cycle-detection) set.
bool elidable(Instruction *instr) {
  std::set<Instruction*> seen;
  return elidable_helper(instr, seen);
}

// Format a source position.
std::string srcPosDesc(const Module &mod, const DebugLoc &dl) {
  std::stringstream ss;
  ss << mod.getModuleIdentifier() << ":";
  ss << dl.getLine();
  if (dl.getCol())
    ss << "," << dl.getCol();
  return ss.str();
}

/**** THE MAIN LLVM PASS ****/

struct ACCEPTPass : public FunctionPass {
  static char ID;

  Constant *blockCountFunction;
  unsigned long gApproxInsts;
  unsigned long gElidableInsts;
  unsigned long gTotalInsts;
  Module *module;
  std::map<std::pair<int, int>, int> relaxConfig;  // kind, num -> param

  ACCEPTPass() : FunctionPass(ID) {
    gApproxInsts = 0;
    gElidableInsts = 0;
    gTotalInsts = 0;
    module = 0;
  }

  virtual void getAnalysisUsage(AnalysisUsage &Info) const {
    Info.addRequired<LoopInfo>();
  }

  virtual bool runOnFunction(Function &F) {
    countAndInstrument(F);
    return perforateLoopsMain(F);
  }

  virtual bool doInitialization(Module &M) {
    module = &M;

    if (optInstrument)
      setUpInstrumentation();

    if (optRelax)
      loadRelaxConfig();

    return false;
  }

  virtual bool doFinalization(Module &M) {
    dumpStaticStats();
    if (!optRelax)
      dumpRelaxConfig();
    return false;
  }

  /**** TRACING AND STATISTICS ****/

  void countAndInstrument(Function &F) {
    for (Function::iterator bbi = F.begin(); bbi != F.end(); ++bbi) {
      unsigned int approxInsts = 0;
      unsigned int elidableInsts = 0;
      unsigned int totalInsts = 0;

      for (BasicBlock::iterator ii = bbi->begin(); ii != bbi->end();
            ++ii) {
        if ((Instruction*)ii == bbi->getTerminator()) {
          // Terminator instruction is not checked.
          continue;
        }

        // Record information about this instruction.
        bool iApprox = isApprox(ii);
        bool iElidable = elidable(ii);
        ++gTotalInsts;
        ++totalInsts;
        if (iApprox) {
          ++gApproxInsts;
          ++approxInsts;
        }
        if (iElidable) {
          ++gElidableInsts;
          ++elidableInsts;
        }
      }

      // Call the runtime profiling library for this block.
      if (optInstrument)
        insertTraceCall(F, bbi, approxInsts, elidableInsts, totalInsts);
    }
  }

  void setUpInstrumentation() {
    blockCountFunction = module->getOrInsertFunction(
      FUNC_TRACE,
      Type::getVoidTy(module->getContext()), // return type
      Type::getInt32Ty(module->getContext()), // approx
      Type::getInt32Ty(module->getContext()), // elidable
      Type::getInt32Ty(module->getContext()), // total
      NULL
    );
  }

  void insertTraceCall(Function &F, BasicBlock* bb,
                       unsigned int approx,
                       unsigned int elidable,
                       unsigned int total) {
    std::vector<Value *> args;
    args.push_back(
        ConstantInt::get(Type::getInt32Ty(F.getContext()), approx)
    );
    args.push_back(
        ConstantInt::get(Type::getInt32Ty(F.getContext()), elidable)
    );
    args.push_back(
        ConstantInt::get(Type::getInt32Ty(F.getContext()), total)
    );

    // For now, we're inserting calls at the end of basic blocks.
    CallInst::Create(
      blockCountFunction,
      args,
      "",
      bb->getTerminator()
    );
  }

  void dumpStaticStats() {
    FILE *results_file = fopen("enerc_static.txt", "w+");
    fprintf(results_file,
            "%lu %lu %lu\n", gApproxInsts, gElidableInsts, gTotalInsts);
    fclose(results_file);
  }

  /**** RELAXATION CONFIGURATION ***/

  typedef enum {
    rkPerforate
  } relaxKind;

  void dumpRelaxConfig() {
    std::ofstream configFile("accept_config.txt");;
    for (std::map<std::pair<int, int>, int>::iterator i = relaxConfig.begin();
         i != relaxConfig.end(); ++i) {
      configFile << i->first.first << " "
                 << i->first.second << " "
                 << i->second << "\n";
    }
    configFile.close();
  }

  void loadRelaxConfig() {
    std::ifstream configFile("accept_config.txt");;
    if (!configFile.good()) {
      errs() << "no config file; no optimizations will occur\n";
      return;
    }

    while (configFile.good()) {
      int kind;
      int ident;
      int param;
      configFile >> kind >> ident >> param;
      relaxConfig[std::pair<int, int>(kind, ident)] = param;
    }

    configFile.close();
  }

  /**** EXPERIMENT ****/
  void perforateLoopsTop(Loop *loop, int &loopId, int &perforatedLoops) {
    std::vector<Loop*> subLoops = loop->getSubLoops();
    for (int i = 0; i < subLoops.size(); ++i)
      perforateLoopsTop(subLoops[i], loopId, perforatedLoops);
    if (perforateLoops(loop, loopId))
      ++perforatedLoops;
    ++loopId;
  }

  bool perforateLoopsMain(Function &F) {
    int perforatedLoops = 0;
    int loopId = 0;
    LoopInfo &loopInfo = getAnalysis<LoopInfo>();

    for (LoopInfo::iterator li = loopInfo.begin();
         li != loopInfo.end(); ++li, ++loopId) {
      Loop *loop = *li;
      perforateLoopsTop(loop, loopId, perforatedLoops);
    }
    return perforatedLoops > 0;
  }

  bool perforateLoops(Loop *loop, int &loopId) {
    int perforatedLoops = 0;

    // We only consider loops for which there is a header (condition), a
    // latch (increment, in "for"), and a preheader (initialization).
    if (!loop->getHeader() || !loop->getLoopLatch()
        || !loop->getLoopPreheader())
      return false;
    // Count elidable instructions in the loop.
    int cTotal = 0;
    int cElidable = 0;
    for (Loop::block_iterator bi = loop->block_begin();
         bi != loop->block_end(); ++bi) {
      BasicBlock *block = *bi;

      // Don't count the loop control.
      if (block == loop->getHeader() || block == loop->getLoopLatch())
        continue;

      for (BasicBlock::iterator ii = block->begin();
           ii != block->end(); ++ii) {
        if ((Instruction*)ii == block->getTerminator())
          continue;
        if (elidable(ii))
          ++cElidable;
        ++cTotal;
      }
    }

    // How elidable is the loop body as a whole?
    errs() << "loop at "
           << srcPosDesc(*module, loop->getHeader()->begin()->getDebugLoc())
           << " - " << cElidable << "/" << cTotal << "\n";

    /*
    #define DUMPNN(e) if (e) (e)->dump(); else errs() << "null\n";
    errs() << "header: ";
    DUMPNN(loop->getHeader())
    errs() << "preheader: ";
    DUMPNN(loop->getLoopPreheader())
    errs() << "predecessor: ";
    DUMPNN(loop->getLoopPredecessor())
    errs() << "latch: ";
    DUMPNN(loop->getLoopLatch())
    errs() << "exit: ";
    DUMPNN(loop->getExitBlock())
    errs() << "exiting: ";
    DUMPNN(loop->getExitingBlock())
    errs() << "all contained blocks: ";
    for (Loop::block_iterator bi = loop->block_begin();
         bi != loop->block_end(); ++bi) {
      BasicBlock *block = *bi;
      block->dump();
    }
    */

    if (cElidable == cTotal) {
      errs() << "can perforate.\n";
      if (optRelax) {
        int param = relaxConfig[std::pair<int, int>(rkPerforate, loopId)];
        if (param) {
          errs() << "perforating with factor 2^" << param << "\n";
          perforateLoop(loop, param);
          ++perforatedLoops;
        }
      } else {
        relaxConfig[std::pair<int, int>(rkPerforate, loopId)] = 0;
      }
    }

    return perforatedLoops > 0;
  }

  void perforateLoop(Loop *loop, int logfactor=1) {
    // Check whether this loop is perforatable.
    // First, check for required blocks.
    if (!loop->getHeader() || !loop->getLoopLatch()
        || !loop->getLoopPreheader() || !loop->getExitBlock()) {
      llvm::errs() << "malformed loop\n";
      return;
    }
    // Next, make sure the header (condition block) ends with a body/exit
    // conditional branch.
    BranchInst *condBranch = dyn_cast<BranchInst>(
        loop->getHeader()->getTerminator()
    );
    if (!condBranch || condBranch->getNumSuccessors() != 2) {
      llvm::errs() << "malformed loop condition\n";
      return;
    }
    BasicBlock *bodyBlock;
    if (condBranch->getSuccessor(0) == loop->getExitBlock()) {
      bodyBlock = condBranch->getSuccessor(1);
    } else if (condBranch->getSuccessor(1) == loop->getExitBlock()) {
      bodyBlock = condBranch->getSuccessor(0);
    } else {
      llvm::errs() << "loop condition does not exit\n";
      return;
    }

    IRBuilder<> builder(module->getContext());
    Value *result;

    // Add our own counter to the preheader.
    builder.SetInsertPoint(loop->getLoopPreheader()->getTerminator());
    AllocaInst *counterAlloca = builder.CreateAlloca(
        builder.getInt32Ty(),
        0,
        "accept_counter"
    );
    builder.CreateStore(
        builder.getInt32(0),
        counterAlloca
    );

    // Increment the counter in the latch.
    builder.SetInsertPoint(loop->getLoopLatch()->getTerminator());
    result = builder.CreateLoad(
        counterAlloca,
        "accept_tmp"
    );
    result = builder.CreateAdd(
        result,
        builder.getInt32(1),
        "accept_inc"
    );
    builder.CreateStore(
        result,
        counterAlloca
    );

    // Get the first body block.

    // Check the counter before the loop's body.
    BasicBlock *checkBlock = BasicBlock::Create(
        module->getContext(),
        "accept_cond",
        bodyBlock->getParent(),
        bodyBlock
    );
    builder.SetInsertPoint(checkBlock);
    result = builder.CreateLoad(
        counterAlloca,
        "accept_tmp"
    );
    // Check whether the low n bits of the counter are zero.
    result = builder.CreateTrunc(
        result,
        Type::getIntNTy(module->getContext(), logfactor),
        "accept_trunc"
    );
    result = builder.CreateIsNull(
        result,
        "accept_cmp"
    );
    result = builder.CreateCondBr(
        result,
        bodyBlock,
        loop->getLoopLatch()
    );

    // Change the latch (condition block) to point to our new condition
    // instead of the body.
    condBranch->setSuccessor(0, checkBlock);
  }

};
char ACCEPTPass::ID = 0;

/**** PASS REGISTRATION FOOTNOTE ***/

// Register ACCEPT as a "standard pass". This allows the pass to run without
// running opt explicitly (e.g., as part of running `clang`).
static void registerACCEPTPass(const PassManagerBuilder &,
                               PassManagerBase &PM) {
  PM.add(new LoopInfo());
  PM.add(new ACCEPTPass());
}
static RegisterStandardPasses
    RegisterACCEPT(PassManagerBuilder::EP_EarlyAsPossible,
                   registerACCEPTPass);

}
<commit_msg>correct filename in source location strings<commit_after>#define DEBUG_TYPE "enerc"
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/BasicBlock.h"
#include "llvm/Module.h"
#include "llvm/Constants.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Instructions.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/PassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/IRBuilder.h"
#include "llvm/DebugInfo.h"

#include <sstream>
#include <set>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>

#define ECQ_PRECISE 0
#define ECQ_APPROX 1

#define FUNC_TRACE "enerc_trace"

// I'm not sure why, but I can't seem to enable debug output in the usual way
// (with command line flags). Here's a hack.
#undef DEBUG
#define DEBUG(s) s

using namespace llvm;
namespace {

// Command-line flags.
cl::opt<bool> optInstrument ("accept-inst",
    cl::desc("ACCEPT: enable profiling instrumentation"));
cl::opt<bool> optRelax ("accept-relax",
    cl::desc("ACCEPT: enable relaxations"));

/**** HELPERS ****/

// Look at the qualifier metadata on the instruction and determine whether it
// has approximate semantics.
bool isApprox(Instruction *instr) {
  MDNode *md = instr->getMetadata("quals");
  if (!md)
    return false;

  Value *val = md->getOperand(0);
  ConstantInt *ci = cast<ConstantInt>(val);
  if (ci) {
    APInt intval = ci->getValue();
    return intval == ECQ_APPROX;
  } else {
    llvm::errs() << "INVALID METADATA";
    return false;
  }
}

// Is it legal to elide this instruction?
bool elidable_helper(Instruction *instr,
                     std::set<Instruction*> &seen) {
  // Check for cycles.
  if (seen.count(instr)) {
    llvm::errs() << "CYCLE DETECTED\n";
    return false;
  }
  seen.insert(instr);

  if (isApprox(instr)) {
    return true;
  } else if (isa<StoreInst>(instr) ||
             isa<ReturnInst>(instr) ||
             isa<BranchInst>(instr)) {
    // Precise stores, returns, branches: never elidable.
    return false;
  } else {
    // Recursive case: all consumers are elidable.
    for (Value::use_iterator ui = instr->use_begin();
          ui != instr->use_end(); ++ui) {
      Instruction *user = dyn_cast<Instruction>(*ui);
      if (user && !elidable_helper(user, seen)) {
        return false;
      }
    }
    return true; // No non-elidable consumers.
  }
}
// Start with an empty "seen" (cycle-detection) set.
bool elidable(Instruction *instr) {
  std::set<Instruction*> seen;
  return elidable_helper(instr, seen);
}

// Format a source position.
std::string srcPosDesc(const Module &mod, const DebugLoc &dl) {
  LLVMContext &ctx = mod.getContext();
  std::stringstream ss;

  // Try to get filename from debug location.
  DIScope scope(dl.getScope(ctx));
  if (scope.Verify()) {
    ss << scope.getFilename().data();
  } else {
    // Fall back to the compilation unit name.
    ss << "(" << mod.getModuleIdentifier() << ")";
  }
  ss << ":";

  ss << dl.getLine();
  if (dl.getCol())
    ss << "," << dl.getCol();
  return ss.str();
}

/**** THE MAIN LLVM PASS ****/

struct ACCEPTPass : public FunctionPass {
  static char ID;

  Constant *blockCountFunction;
  unsigned long gApproxInsts;
  unsigned long gElidableInsts;
  unsigned long gTotalInsts;
  Module *module;
  std::map<std::pair<int, int>, int> relaxConfig;  // kind, num -> param

  ACCEPTPass() : FunctionPass(ID) {
    gApproxInsts = 0;
    gElidableInsts = 0;
    gTotalInsts = 0;
    module = 0;
  }

  virtual void getAnalysisUsage(AnalysisUsage &Info) const {
    Info.addRequired<LoopInfo>();
  }

  virtual bool runOnFunction(Function &F) {
    countAndInstrument(F);
    return perforateLoopsMain(F);
  }

  virtual bool doInitialization(Module &M) {
    module = &M;

    if (optInstrument)
      setUpInstrumentation();

    if (optRelax)
      loadRelaxConfig();

    return false;
  }

  virtual bool doFinalization(Module &M) {
    dumpStaticStats();
    if (!optRelax)
      dumpRelaxConfig();
    return false;
  }

  /**** TRACING AND STATISTICS ****/

  void countAndInstrument(Function &F) {
    for (Function::iterator bbi = F.begin(); bbi != F.end(); ++bbi) {
      unsigned int approxInsts = 0;
      unsigned int elidableInsts = 0;
      unsigned int totalInsts = 0;

      for (BasicBlock::iterator ii = bbi->begin(); ii != bbi->end();
            ++ii) {
        if ((Instruction*)ii == bbi->getTerminator()) {
          // Terminator instruction is not checked.
          continue;
        }

        // Record information about this instruction.
        bool iApprox = isApprox(ii);
        bool iElidable = elidable(ii);
        ++gTotalInsts;
        ++totalInsts;
        if (iApprox) {
          ++gApproxInsts;
          ++approxInsts;
        }
        if (iElidable) {
          ++gElidableInsts;
          ++elidableInsts;
        }
      }

      // Call the runtime profiling library for this block.
      if (optInstrument)
        insertTraceCall(F, bbi, approxInsts, elidableInsts, totalInsts);
    }
  }

  void setUpInstrumentation() {
    blockCountFunction = module->getOrInsertFunction(
      FUNC_TRACE,
      Type::getVoidTy(module->getContext()), // return type
      Type::getInt32Ty(module->getContext()), // approx
      Type::getInt32Ty(module->getContext()), // elidable
      Type::getInt32Ty(module->getContext()), // total
      NULL
    );
  }

  void insertTraceCall(Function &F, BasicBlock* bb,
                       unsigned int approx,
                       unsigned int elidable,
                       unsigned int total) {
    std::vector<Value *> args;
    args.push_back(
        ConstantInt::get(Type::getInt32Ty(F.getContext()), approx)
    );
    args.push_back(
        ConstantInt::get(Type::getInt32Ty(F.getContext()), elidable)
    );
    args.push_back(
        ConstantInt::get(Type::getInt32Ty(F.getContext()), total)
    );

    // For now, we're inserting calls at the end of basic blocks.
    CallInst::Create(
      blockCountFunction,
      args,
      "",
      bb->getTerminator()
    );
  }

  void dumpStaticStats() {
    FILE *results_file = fopen("enerc_static.txt", "w+");
    fprintf(results_file,
            "%lu %lu %lu\n", gApproxInsts, gElidableInsts, gTotalInsts);
    fclose(results_file);
  }

  /**** RELAXATION CONFIGURATION ***/

  typedef enum {
    rkPerforate
  } relaxKind;

  void dumpRelaxConfig() {
    std::ofstream configFile("accept_config.txt");;
    for (std::map<std::pair<int, int>, int>::iterator i = relaxConfig.begin();
         i != relaxConfig.end(); ++i) {
      configFile << i->first.first << " "
                 << i->first.second << " "
                 << i->second << "\n";
    }
    configFile.close();
  }

  void loadRelaxConfig() {
    std::ifstream configFile("accept_config.txt");;
    if (!configFile.good()) {
      errs() << "no config file; no optimizations will occur\n";
      return;
    }

    while (configFile.good()) {
      int kind;
      int ident;
      int param;
      configFile >> kind >> ident >> param;
      relaxConfig[std::pair<int, int>(kind, ident)] = param;
    }

    configFile.close();
  }

  /**** EXPERIMENT ****/
  void perforateLoopsTop(Loop *loop, int &loopId, int &perforatedLoops) {
    std::vector<Loop*> subLoops = loop->getSubLoops();
    for (int i = 0; i < subLoops.size(); ++i)
      perforateLoopsTop(subLoops[i], loopId, perforatedLoops);
    if (perforateLoops(loop, loopId))
      ++perforatedLoops;
    ++loopId;
  }

  bool perforateLoopsMain(Function &F) {
    int perforatedLoops = 0;
    int loopId = 0;
    LoopInfo &loopInfo = getAnalysis<LoopInfo>();

    for (LoopInfo::iterator li = loopInfo.begin();
         li != loopInfo.end(); ++li, ++loopId) {
      Loop *loop = *li;
      perforateLoopsTop(loop, loopId, perforatedLoops);
    }
    return perforatedLoops > 0;
  }

  bool perforateLoops(Loop *loop, int &loopId) {
    int perforatedLoops = 0;

    // We only consider loops for which there is a header (condition), a
    // latch (increment, in "for"), and a preheader (initialization).
    if (!loop->getHeader() || !loop->getLoopLatch()
        || !loop->getLoopPreheader())
      return false;
    // Count elidable instructions in the loop.
    int cTotal = 0;
    int cElidable = 0;
    for (Loop::block_iterator bi = loop->block_begin();
         bi != loop->block_end(); ++bi) {
      BasicBlock *block = *bi;

      // Don't count the loop control.
      if (block == loop->getHeader() || block == loop->getLoopLatch())
        continue;

      for (BasicBlock::iterator ii = block->begin();
           ii != block->end(); ++ii) {
        if ((Instruction*)ii == block->getTerminator())
          continue;
        if (elidable(ii))
          ++cElidable;
        ++cTotal;
      }
    }

    // How elidable is the loop body as a whole?
    errs() << "loop at "
           << srcPosDesc(*module, loop->getHeader()->begin()->getDebugLoc())
           << " - " << cElidable << "/" << cTotal << "\n";

    /*
    #define DUMPNN(e) if (e) (e)->dump(); else errs() << "null\n";
    errs() << "header: ";
    DUMPNN(loop->getHeader())
    errs() << "preheader: ";
    DUMPNN(loop->getLoopPreheader())
    errs() << "predecessor: ";
    DUMPNN(loop->getLoopPredecessor())
    errs() << "latch: ";
    DUMPNN(loop->getLoopLatch())
    errs() << "exit: ";
    DUMPNN(loop->getExitBlock())
    errs() << "exiting: ";
    DUMPNN(loop->getExitingBlock())
    errs() << "all contained blocks: ";
    for (Loop::block_iterator bi = loop->block_begin();
         bi != loop->block_end(); ++bi) {
      BasicBlock *block = *bi;
      block->dump();
    }
    */

    if (cElidable == cTotal) {
      errs() << "can perforate.\n";
      if (optRelax) {
        int param = relaxConfig[std::pair<int, int>(rkPerforate, loopId)];
        if (param) {
          errs() << "perforating with factor 2^" << param << "\n";
          perforateLoop(loop, param);
          ++perforatedLoops;
        }
      } else {
        relaxConfig[std::pair<int, int>(rkPerforate, loopId)] = 0;
      }
    }

    return perforatedLoops > 0;
  }

  void perforateLoop(Loop *loop, int logfactor=1) {
    // Check whether this loop is perforatable.
    // First, check for required blocks.
    if (!loop->getHeader() || !loop->getLoopLatch()
        || !loop->getLoopPreheader() || !loop->getExitBlock()) {
      llvm::errs() << "malformed loop\n";
      return;
    }
    // Next, make sure the header (condition block) ends with a body/exit
    // conditional branch.
    BranchInst *condBranch = dyn_cast<BranchInst>(
        loop->getHeader()->getTerminator()
    );
    if (!condBranch || condBranch->getNumSuccessors() != 2) {
      llvm::errs() << "malformed loop condition\n";
      return;
    }
    BasicBlock *bodyBlock;
    if (condBranch->getSuccessor(0) == loop->getExitBlock()) {
      bodyBlock = condBranch->getSuccessor(1);
    } else if (condBranch->getSuccessor(1) == loop->getExitBlock()) {
      bodyBlock = condBranch->getSuccessor(0);
    } else {
      llvm::errs() << "loop condition does not exit\n";
      return;
    }

    IRBuilder<> builder(module->getContext());
    Value *result;

    // Add our own counter to the preheader.
    builder.SetInsertPoint(loop->getLoopPreheader()->getTerminator());
    AllocaInst *counterAlloca = builder.CreateAlloca(
        builder.getInt32Ty(),
        0,
        "accept_counter"
    );
    builder.CreateStore(
        builder.getInt32(0),
        counterAlloca
    );

    // Increment the counter in the latch.
    builder.SetInsertPoint(loop->getLoopLatch()->getTerminator());
    result = builder.CreateLoad(
        counterAlloca,
        "accept_tmp"
    );
    result = builder.CreateAdd(
        result,
        builder.getInt32(1),
        "accept_inc"
    );
    builder.CreateStore(
        result,
        counterAlloca
    );

    // Get the first body block.

    // Check the counter before the loop's body.
    BasicBlock *checkBlock = BasicBlock::Create(
        module->getContext(),
        "accept_cond",
        bodyBlock->getParent(),
        bodyBlock
    );
    builder.SetInsertPoint(checkBlock);
    result = builder.CreateLoad(
        counterAlloca,
        "accept_tmp"
    );
    // Check whether the low n bits of the counter are zero.
    result = builder.CreateTrunc(
        result,
        Type::getIntNTy(module->getContext(), logfactor),
        "accept_trunc"
    );
    result = builder.CreateIsNull(
        result,
        "accept_cmp"
    );
    result = builder.CreateCondBr(
        result,
        bodyBlock,
        loop->getLoopLatch()
    );

    // Change the latch (condition block) to point to our new condition
    // instead of the body.
    condBranch->setSuccessor(0, checkBlock);
  }

};
char ACCEPTPass::ID = 0;

/**** PASS REGISTRATION FOOTNOTE ***/

// Register ACCEPT as a "standard pass". This allows the pass to run without
// running opt explicitly (e.g., as part of running `clang`).
static void registerACCEPTPass(const PassManagerBuilder &,
                               PassManagerBase &PM) {
  PM.add(new LoopInfo());
  PM.add(new ACCEPTPass());
}
static RegisterStandardPasses
    RegisterACCEPT(PassManagerBuilder::EP_EarlyAsPossible,
                   registerACCEPTPass);

}
<|endoftext|>


<commit_before>/*
DisplayController.h - Library for Controlling a 14x28 bits FlipDot display sign using two FP2800A.
Created by Antonio Carioca, March 3, 2014.
*/

//#include "Arduino.h"

//#include <avr/pgmspace.h>
//#include "application.h"
#include "mark-iv-flip-dot-display-sign-14x28-controller.h"

/* CONSTANTS */
//const int DISPLAY_SIZE = 4;
const int DISPLAY_PIXEL_WIDTH = 28;
const int DISPLAY_PIXEL_HEIGHT = 14;
const int DISPLAY_SUBPANEL_QTY = 2;

//=== F O N T ===
// Font courtesy of aspro648
// coden taken from
// http://www.instructables.com/files/orig/FQC/A1CY/H5EW79JK/FQCA1CYH5EW79JK.txt
// The @ will display as space character.
// NOTE: MOVING ALL THE ARRAY BELOW TO PROGMEM

//DotDisplay::DotDisplay(int dataPin, int clockPin, int latchPin, int enableSubPanel1Pin, int enableSubPanel2Pin, int fontWidth, int fontHeight, prog_uchar fonteParam[][5]){
DotDisplay::DotDisplay(int dataPin, int clockPin, int latchPin,  int enableSubPanel1Pin, int enableSubPanel2Pin, int fontWidth, int fontHeight, byte fonteParam[][5]){

	pinMode(dataPin, OUTPUT);
	pinMode(clockPin, OUTPUT);
	pinMode(latchPin, OUTPUT);
	pinMode(enableSubPanel1Pin, OUTPUT);
	pinMode(enableSubPanel2Pin, OUTPUT);
	//disable FP2800A's
	digitalWrite(enableSubPanel1Pin, LOW);
	digitalWrite(enableSubPanel2Pin, LOW);

	_dataPin = dataPin;
	_clockPin = clockPin;
	_latchPin = latchPin;
	_enableSubPanel1Pin = enableSubPanel1Pin;
	_enableSubPanel2Pin = enableSubPanel2Pin;
	_fontWidth = fontWidth;
	_fontHeight = fontHeight;
	_fonteParam = fonteParam;

	//_maxNumRows = floor((DISPLAY_PIXEL_HEIGHT+1)/(_fontHeight));
	_maxNumRows = (int)((DISPLAY_PIXEL_HEIGHT+1)/(_fontHeight));
	//_maxRowLength = floor((DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY+1) / (_fontWidth+1));
	_maxRowLength = (int)((DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY+1) / (_fontWidth+1));
	_maxMessageLength = _maxRowLength * _maxNumRows;

}
/*
void DotDisplay::setSerial(HardwareSerial* hwPrint){
	printer = hwPrint; //operate on the address of print
	if(printer) {
		printer->begin(9600);
	}
}
*/

void DotDisplay::setDot(byte col, byte row, bool on){

	//accidentally reversed two data pins, so reversing back on the code here
	//on = !on;

	//2 pins - Data
	//5 pins - Column
	//4 pins - Rows

	//4 pins - Enable FP2800A (4 subpanels)
	byte subPanel = 1;
	//disable FP2800A's
	digitalWrite(_enableSubPanel1Pin, LOW);
	digitalWrite(_enableSubPanel2Pin, LOW);

	//enables next sunpanel
	if(col>=DISPLAY_PIXEL_WIDTH){
		//subPanel =  floor(col / DISPLAY_PIXEL_WIDTH)+1;
		subPanel =  (int)(col / DISPLAY_PIXEL_WIDTH)+1;
		col=col-DISPLAY_PIXEL_WIDTH;
	}

	/*
	if(printer) {
	printer->print("col: ");
	printer->print(col);
	printer->print(", ");
	printer->print("subPanel: ");
	printer->println(subPanel);
	}
	*/

	// IGNOREx4 + ROWx4 + IGNOREx1 + COLUMNx5 + DATAx2
	byte dataPins = on?1:2;
	byte colFirstThreeDigits = (col % 7)+1;
	//byte colLastTwoDigits = floor(col/7);
	byte colLastTwoDigits = (int)(col/7);
	byte colByte = colFirstThreeDigits | (colLastTwoDigits << 3);
	byte rowFirstThreeDigits = (row % 7)+1;
	byte rowLastDigit = row<7;
	byte rowByte = rowFirstThreeDigits | (rowLastDigit << 3);
	byte firstbyte = (dataPins) | (colByte << 2);
	byte secondbyte = rowByte;

	digitalWrite(_latchPin, LOW);
	shiftOut(_dataPin, _clockPin, LSBFIRST, firstbyte);
	shiftOut(_dataPin, _clockPin, LSBFIRST, secondbyte);
	digitalWrite(_latchPin, HIGH);
	//delay(1);

	//pulse the FP2800A's enable pins
	if(subPanel == 1){
		digitalWrite(_enableSubPanel1Pin, HIGH);
		delay(1);
		digitalWrite(_enableSubPanel1Pin, LOW);
	} else if (subPanel == 2) {
		digitalWrite(_enableSubPanel2Pin, HIGH);
		delay(1);
		digitalWrite(_enableSubPanel2Pin, LOW);
	}
}

//void DotDisplay::updateDisplay(char *textMessage){
void DotDisplay::updateDisplay(char textMessage[], char log[]){
	int currentColumn = 0;
	int currentRow = 0;

	char temp[500];
	sprintf(log, "_maxRowLength:%i, _maxNumRows:%i, MESSAGE:%s ", _maxRowLength, _maxNumRows,textMessage);

	//goes through all characters
	for (int ch = 0; ch < (_maxMessageLength);ch++){
		//get a character from the message
		int alphabetIndex = textMessage[ch] - ' '; //Subtract '@' so we get a number

		//Serial.println(alphabetIndex);
		//strcat(log,"Index: ");
		//strcat(log,alphabetIndex);
		sprintf(temp, "Character:%c ", textMessage[ch]);

		if ((alphabetIndex < 0) or (ch >=strlen(textMessage))) alphabetIndex=0;

		//push it to the next row if necessary
		if((currentColumn + _fontWidth) > (DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY)){
			currentColumn=0;
			currentRow=currentRow+_fontHeight;
		}

		//set all the bits in the next _fontWidth columns on the display
		for(byte col = currentColumn; col<(currentColumn+_fontWidth); col++){

			byte calculatedColumn = (col)%(_fontWidth+1);
			//for(byte row = 0; row < _fontHeight; row++)
			int characterRow = 0;
			for(byte row = currentRow; row < (currentRow + _fontHeight); row++){
				//bool isOn = bitRead(pgm_read_byte(&(_fonteParam[alphabetIndex][calculatedColumn])),6-characterRow);
				bool isOn = bitRead((byte)_fonteParam[alphabetIndex][calculatedColumn],6-row);//this index is needed as we are going from back to front

				setDot(col, row, isOn);
				/*
				if(printer) {
					printer->print(isOn);
				}
				*/
				char dot[2];
				if (isOn) {
					strcpy(dot,"1");
				}else {
					strcpy(dot,"0");
				}
				strcat(temp,dot);

				characterRow++;
			}
			/*
			if(printer) {
				printer->println("");
			}
			*/
			strcat(temp," ");
		}
		/*
		if(printer) {
			printer->println("/");
		}
		*/
		strcat(temp,"/");

		currentColumn = currentColumn+(_fontWidth+1);
	}
	strcat(log,temp);
}
<commit_msg>Further format changes<commit_after>/*
DisplayController.h - Library for Controlling a 14x28 bits FlipDot display sign using two FP2800A.
Created by Antonio Carioca, March 3, 2014.
*/

//#include "Arduino.h"

//#include <avr/pgmspace.h>
//#include "application.h"
#include "mark-iv-flip-dot-display-sign-14x28-controller.h"

/* CONSTANTS */
//const int DISPLAY_SIZE = 4;
const int DISPLAY_PIXEL_WIDTH = 28;
const int DISPLAY_PIXEL_HEIGHT = 14;
const int DISPLAY_SUBPANEL_QTY = 2;

//=== F O N T ===
// Font courtesy of aspro648
// coden taken from
// http://www.instructables.com/files/orig/FQC/A1CY/H5EW79JK/FQCA1CYH5EW79JK.txt
// The @ will display as space character.
// NOTE: MOVING ALL THE ARRAY BELOW TO PROGMEM

//DotDisplay::DotDisplay(int dataPin, int clockPin, int latchPin, int enableSubPanel1Pin, int enableSubPanel2Pin, int fontWidth, int fontHeight, prog_uchar fonteParam[][5]){
DotDisplay::DotDisplay(int dataPin, int clockPin, int latchPin,  int enableSubPanel1Pin, int enableSubPanel2Pin, int fontWidth, int fontHeight, byte fonteParam[][5]){

	pinMode(dataPin, OUTPUT);
	pinMode(clockPin, OUTPUT);
	pinMode(latchPin, OUTPUT);
	pinMode(enableSubPanel1Pin, OUTPUT);
	pinMode(enableSubPanel2Pin, OUTPUT);
	//disable FP2800A's
	digitalWrite(enableSubPanel1Pin, LOW);
	digitalWrite(enableSubPanel2Pin, LOW);

	_dataPin = dataPin;
	_clockPin = clockPin;
	_latchPin = latchPin;
	_enableSubPanel1Pin = enableSubPanel1Pin;
	_enableSubPanel2Pin = enableSubPanel2Pin;
	_fontWidth = fontWidth;
	_fontHeight = fontHeight;
	_fonteParam = fonteParam;

	//_maxNumRows = floor((DISPLAY_PIXEL_HEIGHT+1)/(_fontHeight));
	_maxNumRows = (int)((DISPLAY_PIXEL_HEIGHT+1)/(_fontHeight));
	//_maxRowLength = floor((DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY+1) / (_fontWidth+1));
	_maxRowLength = (int)((DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY+1) / (_fontWidth+1));
	_maxMessageLength = _maxRowLength * _maxNumRows;

}
/*
void DotDisplay::setSerial(HardwareSerial* hwPrint){
	printer = hwPrint; //operate on the address of print
	if(printer) {
		printer->begin(9600);
	}
}
*/

void DotDisplay::setDot(byte col, byte row, bool on){

	//accidentally reversed two data pins, so reversing back on the code here
	//on = !on;

	//2 pins - Data
	//5 pins - Column
	//4 pins - Rows

	//4 pins - Enable FP2800A (4 subpanels)
	byte subPanel = 1;
	//disable FP2800A's
	digitalWrite(_enableSubPanel1Pin, LOW);
	digitalWrite(_enableSubPanel2Pin, LOW);

	//enables next sunpanel
	if(col>=DISPLAY_PIXEL_WIDTH){
		//subPanel =  floor(col / DISPLAY_PIXEL_WIDTH)+1;
		subPanel =  (int)(col / DISPLAY_PIXEL_WIDTH)+1;
		col=col-DISPLAY_PIXEL_WIDTH;
	}

	/*
	if(printer) {
	printer->print("col: ");
	printer->print(col);
	printer->print(", ");
	printer->print("subPanel: ");
	printer->println(subPanel);
	}
	*/

	// IGNOREx4 + ROWx4 + IGNOREx1 + COLUMNx5 + DATAx2
	byte dataPins = on?1:2;
	byte colFirstThreeDigits = (col % 7)+1;
	//byte colLastTwoDigits = floor(col/7);
	byte colLastTwoDigits = (int)(col/7);
	byte colByte = colFirstThreeDigits | (colLastTwoDigits << 3);
	byte rowFirstThreeDigits = (row % 7)+1;
	byte rowLastDigit = row<7;
	byte rowByte = rowFirstThreeDigits | (rowLastDigit << 3);
	byte firstbyte = (dataPins) | (colByte << 2);
	byte secondbyte = rowByte;

	digitalWrite(_latchPin, LOW);
	shiftOut(_dataPin, _clockPin, LSBFIRST, firstbyte);
	shiftOut(_dataPin, _clockPin, LSBFIRST, secondbyte);
	digitalWrite(_latchPin, HIGH);
	//delay(1);

	//pulse the FP2800A's enable pins
	if(subPanel == 1){
		digitalWrite(_enableSubPanel1Pin, HIGH);
		delay(1);
		digitalWrite(_enableSubPanel1Pin, LOW);
	} else if (subPanel == 2) {
		digitalWrite(_enableSubPanel2Pin, HIGH);
		delay(1);
		digitalWrite(_enableSubPanel2Pin, LOW);
	}
}

//void DotDisplay::updateDisplay(char *textMessage){
void DotDisplay::updateDisplay(char textMessage[], char log[]){
	int currentColumn = 0;
	int currentRow = 0;

	char temp[500];
	sprintf(log, "_maxRowLength:%i, _maxNumRows:%i, MESSAGE:%s\n", _maxRowLength, _maxNumRows,textMessage);

	//goes through all characters
	for (int ch = 0; ch < (_maxMessageLength);ch++){
		//get a character from the message
		int alphabetIndex = textMessage[ch] - ' '; //Subtract '@' so we get a number

		//Serial.println(alphabetIndex);
		//strcat(log,"Index: ");
		//strcat(log,alphabetIndex);
		sprintf(temp, "Character[%i]:%c ",ch, textMessage[ch]);

		if ((alphabetIndex < 0) or (ch >=strlen(textMessage))) alphabetIndex=0;

		//push it to the next row if necessary
		if((currentColumn + _fontWidth) > (DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY)){
			currentColumn=0;
			currentRow=currentRow+_fontHeight;
		}

		//set all the bits in the next _fontWidth columns on the display
		for(byte col = currentColumn; col<(currentColumn+_fontWidth); col++){

			byte calculatedColumn = (col)%(_fontWidth+1);
			//for(byte row = 0; row < _fontHeight; row++)
			int characterRow = 0;
			for(byte row = currentRow; row < (currentRow + _fontHeight); row++){
				//bool isOn = bitRead(pgm_read_byte(&(_fonteParam[alphabetIndex][calculatedColumn])),6-characterRow);
				bool isOn = bitRead((byte)_fonteParam[alphabetIndex][calculatedColumn],6-row);//this index is needed as we are going from back to front

				setDot(col, row, isOn);
				/*
				if(printer) {
					printer->print(isOn);
				}
				*/
				char dot[2];
				if (isOn) {
					strcpy(dot,"1");
				}else {
					strcpy(dot,"0");
				}
				strcat(temp,dot);

				characterRow++;
			}
			/*
			if(printer) {
				printer->println("");
			}
			*/
			strcat(temp," ");
		}
		/*
		if(printer) {
			printer->println("/");
		}
		*/
		strcat(temp,"/");

		currentColumn = currentColumn+(_fontWidth+1);
	}
	strcat(log,temp);
}
<|endoftext|>