<commit_before>#if _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
#endif

#include <chrono>
#include <mutex>
#include <thread>
#include <unordered_map>
#include <stdio.h>
#include <inttypes.h>
#include "LogVisor/LogVisor.hpp"

/* ANSI sequences */
#define RED "\x1b[1;31m"
#define YELLOW "\x1b[1;33m"
#define GREEN "\x1b[1;32m"
#define MAGENTA "\x1b[1;35m"
#define CYAN "\x1b[1;36m"
#define BOLD "\x1b[1m"
#define NORMAL "\x1b[0m"

#if _WIN32
#define FOREGROUND_WHITE FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE
#endif

namespace LogVisor
{

static std::unordered_map<std::thread::id, const char*> ThreadMap;
void RegisterThreadName(const char* name)
{
    ThreadMap[std::this_thread::get_id()] = name;
#if __APPLE__
    pthread_setname_np(name);
#elif __linux__
    pthread_setname_np(pthread_self(), name);
#elif _MSC_VER
    struct
    {
        DWORD dwType; // Must be 0x1000.
        LPCSTR szName; // Pointer to name (in user addr space).
        DWORD dwThreadID; // Thread ID (-1=caller thread).
        DWORD dwFlags; // Reserved for future use, must be zero.
    } info = {0x1000, name, (DWORD)-1, 0};
    __try
    {
        RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
    }
#endif
}

std::vector<std::unique_ptr<ILogger>> MainLoggers;
std::atomic_size_t ErrorCount(0);
static std::chrono::steady_clock MonoClock;
static std::chrono::steady_clock::time_point GlobalStart = MonoClock.now();
static inline std::chrono::steady_clock::duration CurrentUptime()
{return MonoClock.now() - GlobalStart;}
std::atomic_uint_fast64_t FrameIndex(0);

#if _WIN32
static HANDLE Term = 0;
#else
static const char* Term = nullptr;
#endif
static bool XtermColor = false;
struct ConsoleLogger : public ILogger
{
    std::mutex m;
    ConsoleLogger()
    {
#if _WIN32
        if (!Term)
            Term = GetStdHandle(STD_ERROR_HANDLE);
#else
        if (!Term)
        {
            Term = getenv("TERM");
            if (Term && !strncmp(Term, "xterm", 5))
            {
                XtermColor = true;
                putenv((char*)"TERM=xterm-16color");
            }
        }
#endif
    }

    static void _reportHead(const char* modName, const char* sourceInfo, Level severity)
    {
        std::chrono::steady_clock::duration tm = CurrentUptime();
        double tmd = tm.count() *
            std::chrono::steady_clock::duration::period::num /
            (double)std::chrono::steady_clock::duration::period::den;
        std::thread::id thrId = std::this_thread::get_id();
        const char* thrName = nullptr;
        if (ThreadMap.find(thrId) != ThreadMap.end())
            thrName = ThreadMap[thrId];

#if _WIN32
        SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
        fprintf(stderr, "[");
        SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
        fprintf(stderr, "%5.4f ", tmd);
        uint64_t fi = FrameIndex.load();
        if (fi)
            fprintf(stderr, "(%" PRIu64 ") ", fi);
        switch (severity)
        {
        case Info:
            SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE);
            fprintf(stderr, "INFO");
            break;
        case Warning:
            SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);
            fprintf(stderr, "WARNING");
            break;
        case Error:
            SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED);
            fprintf(stderr, "ERROR");
            break;
        case FatalError:
            SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED);
            fprintf(stderr, "FATAL ERROR");
            break;
        default:
            break;
        };
        SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
        fprintf(stderr, " %s", modName);
        SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);
        if (sourceInfo)
            fprintf(stderr, " {%s}", sourceInfo);
        SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE);
        if (thrName)
            fprintf(stderr, " (%s)", thrName);
        SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
        fprintf(stderr, "] ");
        SetConsoleTextAttribute(Term, FOREGROUND_WHITE);
#else
        if (XtermColor)
        {
            fprintf(stderr, BOLD "[");
            fprintf(stderr, GREEN "%5.4f ", tmd);
            uint_fast64_t fIdx = FrameIndex.load();
            if (fIdx)
                fprintf(stderr, "(%lu) ", fIdx);
            switch (severity)
            {
            case Info:
                fprintf(stderr, BOLD CYAN "INFO");
                break;
            case Warning:
                fprintf(stderr, BOLD YELLOW "WARNING");
                break;
            case Error:
                fprintf(stderr, RED BOLD "ERROR");
                break;
            case FatalError:
                fprintf(stderr, BOLD RED "FATAL ERROR");
                break;
            default:
                break;
            };
            fprintf(stderr, NORMAL BOLD " %s", modName);
            if (sourceInfo)
                fprintf(stderr, BOLD YELLOW " {%s}", sourceInfo);
            if (thrName)
                fprintf(stderr, BOLD MAGENTA " (%s)", thrName);
            fprintf(stderr, NORMAL BOLD "] " NORMAL);
        }
        else
        {
            fprintf(stderr, "[");
            fprintf(stderr, "%5.4f ", tmd);
            uint_fast64_t fIdx = FrameIndex.load();
            if (fIdx)
                fprintf(stderr, "(%lu) ", fIdx);
            switch (severity)
            {
            case Info:
                fprintf(stderr, "INFO");
                break;
            case Warning:
                fprintf(stderr, "WARNING");
                break;
            case Error:
                fprintf(stderr, "ERROR");
                break;
            case FatalError:
                fprintf(stderr, "FATAL ERROR");
                break;
            default:
                break;
            };
            fprintf(stderr, " %s", modName);
            if (sourceInfo)
                fprintf(stderr, " {%s}", sourceInfo);
            if (thrName)
                fprintf(stderr, " (%s)", thrName);
            fprintf(stderr, "] ");
        }
#endif
    }

    void report(const char* modName, Level severity,
                const char* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        _reportHead(modName, nullptr, severity);
        vfprintf(stderr, format, ap);
        fprintf(stderr, "\n");
    }

    void report(const char* modName, Level severity,
                const wchar_t* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        _reportHead(modName, nullptr, severity);
        vfwprintf(stderr, format, ap);
        fprintf(stderr, "\n");
    }

    void reportSource(const char* modName, Level severity,
                      const char* file, unsigned linenum,
                      const char* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        char sourceInfo[128];
        snprintf(sourceInfo, 128, "%s:%u", file, linenum);
        _reportHead(modName, sourceInfo, severity);
        vfprintf(stderr, format, ap);
        fprintf(stderr, "\n");
    }

    void reportSource(const char* modName, Level severity,
                      const char* file, unsigned linenum,
                      const wchar_t* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        char sourceInfo[128];
        snprintf(sourceInfo, 128, "%s:%u", file, linenum);
        _reportHead(modName, sourceInfo, severity);
        vfwprintf(stderr, format, ap);
        fprintf(stderr, "\n");
    }
};

void RegisterConsoleLogger()
{
    /* Determine if console logger already added */
    for (auto& logger : MainLoggers)
    {
        if (typeid(logger.get()) == typeid(ConsoleLogger))
            return;
    }

    /* Otherwise construct new console logger */
    MainLoggers.emplace_back(new ConsoleLogger);
}

struct FileLogger : public ILogger
{
    FILE* fp;
    std::mutex m;
    virtual void openFile()=0;
    virtual void closeFile() {fclose(fp);}

    void _reportHead(const char* modName, const char* sourceInfo, Level severity)
    {
        std::chrono::steady_clock::duration tm = CurrentUptime();
        double tmd = tm.count() *
            std::chrono::steady_clock::duration::period::num /
            (double)std::chrono::steady_clock::duration::period::den;
        std::thread::id thrId = std::this_thread::get_id();
        const char* thrName = nullptr;
        if (ThreadMap.find(thrId) != ThreadMap.end())
            thrName = ThreadMap[thrId];

        fprintf(fp, "[");
        switch (severity)
        {
        case Info:
            fprintf(fp, "INFO");
            break;
        case Warning:
            fprintf(fp, "WARNING");
            break;
        case Error:
            fprintf(fp, "ERROR");
            break;
        case FatalError:
            fprintf(fp, "FATAL ERROR");
            break;
        default:
            break;
        };
        fprintf(fp, " %s", modName);
        if (sourceInfo)
            fprintf(stderr, " {%s}", sourceInfo);
        if (thrName)
            fprintf(fp, " (%s)", thrName);
        fprintf(fp, " %5.4f", tmd);
        uint_fast64_t fIdx = FrameIndex.load();
        if (fIdx)
            fprintf(fp, " (%" PRIu64 ")", fIdx);
        fprintf(fp, "] ");
    }

    void report(const char* modName, Level severity,
                const char* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        openFile();
        _reportHead(modName, nullptr, severity);
        vfprintf(fp, format, ap);
        fprintf(fp, "\n");
        closeFile();
    }

    void report(const char* modName, Level severity,
                const wchar_t* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        openFile();
        _reportHead(modName, nullptr, severity);
        vfwprintf(fp, format, ap);
        fprintf(fp, "\n");
        closeFile();
    }

    void reportSource(const char* modName, Level severity,
                      const char* file, unsigned linenum,
                      const char* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        openFile();
        char sourceInfo[128];
        snprintf(sourceInfo, 128, "%s:%u", file, linenum);
        _reportHead(modName, sourceInfo, severity);
        vfprintf(fp, format, ap);
        fprintf(fp, "\n");
        closeFile();
    }

    void reportSource(const char* modName, Level severity,
                      const char* file, unsigned linenum,
                      const wchar_t* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        openFile();
        char sourceInfo[128];
        snprintf(sourceInfo, 128, "%s:%u", file, linenum);
        _reportHead(modName, sourceInfo, severity);
        vfwprintf(fp, format, ap);
        fprintf(fp, "\n");
        closeFile();
    }
};

struct FileLogger8 : public FileLogger
{
    const char* m_filepath;
    FileLogger8(const char* filepath) : m_filepath(filepath) {}
    void openFile() {fp = fopen(m_filepath, "a");}
};

void RegisterFileLogger(const char* filepath)
{
    /* Determine if file logger already added */
    for (auto& logger : MainLoggers)
    {
        FileLogger8* filelogger = dynamic_cast<FileLogger8*>(logger.get());
        if (filelogger)
        {
            if (!strcmp(filepath, filelogger->m_filepath))
                return;
        }
    }

    /* Otherwise construct new file logger */
    MainLoggers.emplace_back(new FileLogger8(filepath));
}

#if LOG_UCS2

struct FileLogger16 : public FileLogger
{
    const wchar_t* m_filepath;
    FileLogger16(const wchar_t* filepath) : m_filepath(filepath) {}
    void openFile() {fp = _wfopen(m_filepath, L"a");}
};

void RegisterFileLogger(const wchar_t* filepath)
{
    /* Determine if file logger already added */
    for (auto& logger : MainLoggers)
    {
        FileLogger16* filelogger = dynamic_cast<FileLogger16*>(logger.get());
        if (filelogger)
        {
            if (!wcscmp(filepath, filelogger->m_filepath))
                return;
        }
    }

    /* Otherwise construct new file logger */
    MainLoggers.emplace_back(new FileLogger16(filepath));
}

#endif

}
<commit_msg>support for conemu ANSI terminal on windows<commit_after>#if _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
#else
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#endif

#include <chrono>
#include <mutex>
#include <thread>
#include <unordered_map>
#include <stdio.h>
#include <inttypes.h>
#include "LogVisor/LogVisor.hpp"

/* ANSI sequences */
#define RED "\x1b[1;31m"
#define YELLOW "\x1b[1;33m"
#define GREEN "\x1b[1;32m"
#define MAGENTA "\x1b[1;35m"
#define CYAN "\x1b[1;36m"
#define BOLD "\x1b[1m"
#define NORMAL "\x1b[0m"

#if _WIN32
#define FOREGROUND_WHITE FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE
#endif

namespace LogVisor
{

static std::unordered_map<std::thread::id, const char*> ThreadMap;
void RegisterThreadName(const char* name)
{
    ThreadMap[std::this_thread::get_id()] = name;
#if __APPLE__
    pthread_setname_np(name);
#elif __linux__
    pthread_setname_np(pthread_self(), name);
#elif _MSC_VER
    struct
    {
        DWORD dwType; // Must be 0x1000.
        LPCSTR szName; // Pointer to name (in user addr space).
        DWORD dwThreadID; // Thread ID (-1=caller thread).
        DWORD dwFlags; // Reserved for future use, must be zero.
    } info = {0x1000, name, (DWORD)-1, 0};
    __try
    {
        RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
    }
#endif
}

std::vector<std::unique_ptr<ILogger>> MainLoggers;
std::atomic_size_t ErrorCount(0);
static std::chrono::steady_clock MonoClock;
static std::chrono::steady_clock::time_point GlobalStart = MonoClock.now();
static inline std::chrono::steady_clock::duration CurrentUptime()
{return MonoClock.now() - GlobalStart;}
std::atomic_uint_fast64_t FrameIndex(0);

static inline int ConsoleWidth()
{
    int retval = 80;
#if _WIN32
    CONSOLE_SCREEN_BUFFER_INFO info;
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
    retval = info.dwSize.X;
#else
    struct winsize w;
    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1)
        retval = w.ws_col;
#endif
    if (retval < 10)
        return 10;
    return retval;
}

#if _WIN32
static HANDLE Term = 0;
#else
static const char* Term = nullptr;
#endif
static bool XtermColor = false;
struct ConsoleLogger : public ILogger
{
    std::mutex m;
    ConsoleLogger()
    {
#if _WIN32
        const char* conemuANSI = getenv("ConEmuANSI");
        if (conemuANSI && !strcmp(conemuANSI, "ON"))
            XtermColor = true;
        if (!Term)
            Term = GetStdHandle(STD_ERROR_HANDLE);
#else
        if (!Term)
        {
            Term = getenv("TERM");
            if (Term && !strncmp(Term, "xterm", 5))
            {
                XtermColor = true;
                putenv((char*)"TERM=xterm-16color");
            }
        }
#endif
    }

    static void _reportHead(const char* modName, const char* sourceInfo, Level severity)
    {
        /* Clear current line out */
        int width = ConsoleWidth();
        fprintf(stderr, "\r");
        for (int w=0 ; w<width ; ++w)
            fprintf(stderr, " ");
        fprintf(stderr, "\r");

        std::chrono::steady_clock::duration tm = CurrentUptime();
        double tmd = tm.count() *
            std::chrono::steady_clock::duration::period::num /
            (double)std::chrono::steady_clock::duration::period::den;
        std::thread::id thrId = std::this_thread::get_id();
        const char* thrName = nullptr;
        if (ThreadMap.find(thrId) != ThreadMap.end())
            thrName = ThreadMap[thrId];

        if (XtermColor)
        {
            fprintf(stderr, BOLD "[");
            fprintf(stderr, GREEN "%5.4f ", tmd);
            uint_fast64_t fIdx = FrameIndex.load();
            if (fIdx)
                fprintf(stderr, "(%" PRIu64 ") ", fIdx);
            switch (severity)
            {
                case Info:
                    fprintf(stderr, BOLD CYAN "INFO");
                    break;
                case Warning:
                    fprintf(stderr, BOLD YELLOW "WARNING");
                    break;
                case Error:
                    fprintf(stderr, RED BOLD "ERROR");
                    break;
                case FatalError:
                    fprintf(stderr, BOLD RED "FATAL ERROR");
                    break;
                default:
                    break;
            };
            fprintf(stderr, NORMAL BOLD " %s", modName);
            if (sourceInfo)
                fprintf(stderr, BOLD YELLOW " {%s}", sourceInfo);
            if (thrName)
                fprintf(stderr, BOLD MAGENTA " (%s)", thrName);
            fprintf(stderr, NORMAL BOLD "] " NORMAL);
        }
        else
        {
#if _WIN32
            SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
            fprintf(stderr, "[");
            SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
            fprintf(stderr, "%5.4f ", tmd);
            uint64_t fi = FrameIndex.load();
            if (fi)
                fprintf(stderr, "(%" PRIu64 ") ", fi);
            switch (severity)
            {
            case Info:
                SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE);
                fprintf(stderr, "INFO");
                break;
            case Warning:
                SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);
                fprintf(stderr, "WARNING");
                break;
            case Error:
                SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED);
                fprintf(stderr, "ERROR");
                break;
            case FatalError:
                SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED);
                fprintf(stderr, "FATAL ERROR");
                break;
            default:
                break;
            };
            SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
            fprintf(stderr, " %s", modName);
            SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);
            if (sourceInfo)
                fprintf(stderr, " {%s}", sourceInfo);
            SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE);
            if (thrName)
                fprintf(stderr, " (%s)", thrName);
            SetConsoleTextAttribute(Term, FOREGROUND_INTENSITY | FOREGROUND_WHITE);
            fprintf(stderr, "] ");
            SetConsoleTextAttribute(Term, FOREGROUND_WHITE);
#else
            fprintf(stderr, "[");
            fprintf(stderr, "%5.4f ", tmd);
            uint_fast64_t fIdx = FrameIndex.load();
            if (fIdx)
                fprintf(stderr, "(%" PRIu64 ") ", fIdx);
            switch (severity)
            {
            case Info:
                fprintf(stderr, "INFO");
                break;
            case Warning:
                fprintf(stderr, "WARNING");
                break;
            case Error:
                fprintf(stderr, "ERROR");
                break;
            case FatalError:
                fprintf(stderr, "FATAL ERROR");
                break;
            default:
                break;
            };
            fprintf(stderr, " %s", modName);
            if (sourceInfo)
                fprintf(stderr, " {%s}", sourceInfo);
            if (thrName)
                fprintf(stderr, " (%s)", thrName);
            fprintf(stderr, "] ");
#endif
        }
    }

    void report(const char* modName, Level severity,
                const char* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        _reportHead(modName, nullptr, severity);
        vfprintf(stderr, format, ap);
        fprintf(stderr, "\n");
    }

    void report(const char* modName, Level severity,
                const wchar_t* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        _reportHead(modName, nullptr, severity);
        vfwprintf(stderr, format, ap);
        fprintf(stderr, "\n");
    }

    void reportSource(const char* modName, Level severity,
                      const char* file, unsigned linenum,
                      const char* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        char sourceInfo[128];
        snprintf(sourceInfo, 128, "%s:%u", file, linenum);
        _reportHead(modName, sourceInfo, severity);
        vfprintf(stderr, format, ap);
        fprintf(stderr, "\n");
    }

    void reportSource(const char* modName, Level severity,
                      const char* file, unsigned linenum,
                      const wchar_t* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        char sourceInfo[128];
        snprintf(sourceInfo, 128, "%s:%u", file, linenum);
        _reportHead(modName, sourceInfo, severity);
        vfwprintf(stderr, format, ap);
        fprintf(stderr, "\n");
    }
};

void RegisterConsoleLogger()
{
    /* Determine if console logger already added */
    for (auto& logger : MainLoggers)
    {
        if (typeid(logger.get()) == typeid(ConsoleLogger))
            return;
    }

    /* Otherwise construct new console logger */
    MainLoggers.emplace_back(new ConsoleLogger);
}

struct FileLogger : public ILogger
{
    FILE* fp;
    std::mutex m;
    virtual void openFile()=0;
    virtual void closeFile() {fclose(fp);}

    void _reportHead(const char* modName, const char* sourceInfo, Level severity)
    {
        std::chrono::steady_clock::duration tm = CurrentUptime();
        double tmd = tm.count() *
            std::chrono::steady_clock::duration::period::num /
            (double)std::chrono::steady_clock::duration::period::den;
        std::thread::id thrId = std::this_thread::get_id();
        const char* thrName = nullptr;
        if (ThreadMap.find(thrId) != ThreadMap.end())
            thrName = ThreadMap[thrId];

        fprintf(fp, "[");
        switch (severity)
        {
        case Info:
            fprintf(fp, "INFO");
            break;
        case Warning:
            fprintf(fp, "WARNING");
            break;
        case Error:
            fprintf(fp, "ERROR");
            break;
        case FatalError:
            fprintf(fp, "FATAL ERROR");
            break;
        default:
            break;
        };
        fprintf(fp, " %s", modName);
        if (sourceInfo)
            fprintf(stderr, " {%s}", sourceInfo);
        if (thrName)
            fprintf(fp, " (%s)", thrName);
        fprintf(fp, " %5.4f", tmd);
        uint_fast64_t fIdx = FrameIndex.load();
        if (fIdx)
            fprintf(fp, " (%" PRIu64 ")", fIdx);
        fprintf(fp, "] ");
    }

    void report(const char* modName, Level severity,
                const char* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        openFile();
        _reportHead(modName, nullptr, severity);
        vfprintf(fp, format, ap);
        fprintf(fp, "\n");
        closeFile();
    }

    void report(const char* modName, Level severity,
                const wchar_t* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        openFile();
        _reportHead(modName, nullptr, severity);
        vfwprintf(fp, format, ap);
        fprintf(fp, "\n");
        closeFile();
    }

    void reportSource(const char* modName, Level severity,
                      const char* file, unsigned linenum,
                      const char* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        openFile();
        char sourceInfo[128];
        snprintf(sourceInfo, 128, "%s:%u", file, linenum);
        _reportHead(modName, sourceInfo, severity);
        vfprintf(fp, format, ap);
        fprintf(fp, "\n");
        closeFile();
    }

    void reportSource(const char* modName, Level severity,
                      const char* file, unsigned linenum,
                      const wchar_t* format, va_list ap)
    {
        std::unique_lock<std::mutex> lk(m);
        openFile();
        char sourceInfo[128];
        snprintf(sourceInfo, 128, "%s:%u", file, linenum);
        _reportHead(modName, sourceInfo, severity);
        vfwprintf(fp, format, ap);
        fprintf(fp, "\n");
        closeFile();
    }
};

struct FileLogger8 : public FileLogger
{
    const char* m_filepath;
    FileLogger8(const char* filepath) : m_filepath(filepath) {}
    void openFile() {fp = fopen(m_filepath, "a");}
};

void RegisterFileLogger(const char* filepath)
{
    /* Determine if file logger already added */
    for (auto& logger : MainLoggers)
    {
        FileLogger8* filelogger = dynamic_cast<FileLogger8*>(logger.get());
        if (filelogger)
        {
            if (!strcmp(filepath, filelogger->m_filepath))
                return;
        }
    }

    /* Otherwise construct new file logger */
    MainLoggers.emplace_back(new FileLogger8(filepath));
}

#if LOG_UCS2

struct FileLogger16 : public FileLogger
{
    const wchar_t* m_filepath;
    FileLogger16(const wchar_t* filepath) : m_filepath(filepath) {}
    void openFile() {fp = _wfopen(m_filepath, L"a");}
};

void RegisterFileLogger(const wchar_t* filepath)
{
    /* Determine if file logger already added */
    for (auto& logger : MainLoggers)
    {
        FileLogger16* filelogger = dynamic_cast<FileLogger16*>(logger.get());
        if (filelogger)
        {
            if (!wcscmp(filepath, filelogger->m_filepath))
                return;
        }
    }

    /* Otherwise construct new file logger */
    MainLoggers.emplace_back(new FileLogger16(filepath));
}

#endif

}
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexTCL.cxx
 ** Lexer for TCL language.
 **/
// Copyright 1998-2001 by Andre Arpin <arpin@kingston.net>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>

#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"

#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

// Extended to accept accented characters
static inline bool IsAWordChar(int ch) {
	return ch >= 0x80 ||
        (isalnum(ch) || ch == '_' || ch ==':' || ch=='.'); // : name space separator
}

static inline bool IsAWordStart(int ch) {
	return ch >= 0x80 || (ch ==':' || isalpha(ch) || ch == '_');
}

static inline bool IsANumberChar(int ch) {
	// Not exactly following number definition (several dots are seen as OK, etc.)
	// but probably enough in most cases.
	return (ch < 0x80) &&
	       (IsADigit(ch, 0x10) || toupper(ch) == 'E' ||
	        ch == '.' || ch == '-' || ch == '+');
}

static void ColouriseTCLDoc(unsigned int startPos, int length, int , WordList *keywordlists[], Accessor &styler) {
#define  isComment(s) (s==SCE_TCL_COMMENT || s==SCE_TCL_COMMENTLINE || s==SCE_TCL_COMMENT_BOX || s==SCE_TCL_BLOCK_COMMENT)
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool commentLevel = false;
    bool subBrace = false; // substitution begin with a brace ${.....}
	enum tLineState {LS_DEFAULT, LS_OPEN_COMMENT, LS_OPEN_DOUBLE_QUOTE, LS_COMMENT_BOX, LS_MASK_STATE = 0xf,
        LS_COMMAND_EXPECTED = 16, LS_BRACE_ONLY = 32 } lineState = LS_DEFAULT;
	bool prevSlash = false;
	int currentLevel = 0;
    bool expected = 0;
    bool subParen = 0;

	int currentLine = styler.GetLine(startPos);
    if (currentLine > 0)
        currentLine--;
	length += startPos - styler.LineStart(currentLine);
	// make sure lines overlap
	startPos = styler.LineStart(currentLine);

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];
	WordList &keywords4 = *keywordlists[3];
	WordList &keywords5 = *keywordlists[4];
	WordList &keywords6 = *keywordlists[5];
	WordList &keywords7 = *keywordlists[6];
    WordList &keywords8 = *keywordlists[7];
    WordList &keywords9 = *keywordlists[8];

	if (currentLine > 0) {
        int ls = styler.GetLineState(currentLine - 1);
		lineState = tLineState(ls & LS_MASK_STATE);
		expected = LS_COMMAND_EXPECTED == tLineState(ls & LS_COMMAND_EXPECTED);
        subBrace = LS_BRACE_ONLY == tLineState(ls & LS_BRACE_ONLY);
		currentLevel = styler.LevelAt(currentLine - 1) >> 17;
		commentLevel = (styler.LevelAt(currentLine - 1) >> 16) & 1;
	} else
		styler.SetLevel(0, SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG);
	bool visibleChars = false;

	int previousLevel = currentLevel;
    StyleContext sc(startPos, length, SCE_TCL_DEFAULT, styler);
	for (; ; sc.Forward()) {
next:
        if (sc.ch=='\r' && sc.chNext == '\n') // only ignore \r on PC process on the mac
            continue;
        bool atEnd = !sc.More();  // make sure we coloured the last word
        if (lineState != LS_DEFAULT) {
            sc.SetState(SCE_TCL_DEFAULT);
            if (lineState == LS_OPEN_COMMENT)
                sc.SetState(SCE_TCL_COMMENTLINE);
            else if (lineState == LS_OPEN_DOUBLE_QUOTE)
                sc.SetState(SCE_TCL_IN_QUOTE);
            else if (lineState == LS_COMMENT_BOX && (sc.ch == '#' || (sc.ch == ' ' && sc.chNext=='#')))
                sc.SetState(SCE_TCL_COMMENT_BOX);
            lineState = LS_DEFAULT;
        }
        if (subBrace) { // ${ overrides every thing even \ except }
            if (sc.ch == '}') {
                subBrace = false;
                sc.SetState(SCE_TCL_OPERATOR);
                sc.ForwardSetState(SCE_TCL_DEFAULT);
                goto next;
            }
            else
                sc.SetState(SCE_TCL_SUB_BRACE);
            if (!sc.atLineEnd)
                continue;
        } else if (sc.state == SCE_TCL_DEFAULT || sc.state ==SCE_TCL_OPERATOR) {
            expected &= isspacechar(static_cast<unsigned char>(sc.ch)) || IsAWordStart(sc.ch) || sc.ch =='#';
        } else if (sc.state == SCE_TCL_SUBSTITUTION) {
            switch(sc.ch) {
            case '(':
                subParen=true;
                sc.SetState(SCE_TCL_OPERATOR);
                sc.ForwardSetState(SCE_TCL_SUBSTITUTION);
                continue;
            case ')':
                sc.SetState(SCE_TCL_OPERATOR);
                subParen=false;
                continue;
            case '$':
                continue;
            case ',':
                sc.SetState(SCE_TCL_OPERATOR);
                if (subParen)
                    sc.ForwardSetState(SCE_TCL_SUBSTITUTION);
                continue;
            default :
                // maybe spaces should be allowed ???
                if (!IsAWordChar(sc.ch)) { // probably the code is wrong
                    sc.SetState(SCE_TCL_DEFAULT);
                    subParen = 0;
                }
                break;
            }
        } else if (isComment(sc.state)) {
        } else if (!IsAWordChar(sc.ch)) {
            if ((sc.state == SCE_TCL_IDENTIFIER && expected) ||  sc.state == SCE_TCL_MODIFIER) {
                char w[100];
                char *s=w;
                sc.GetCurrent(w, sizeof(w));
                if (w[strlen(w)-1]=='\r')
                    w[strlen(w)-1]=0;
                while(*s == ':') // ignore leading : like in ::set a 10
                    ++s;
                bool quote = sc.state == SCE_TCL_IN_QUOTE;
                if (commentLevel  || expected) {
                    if (keywords.InList(s)) {
                        sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD);
                    } else if (keywords2.InList(s)) {
                        sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD2);
                    } else if (keywords3.InList(s)) {
                        sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD3);
                    } else if (keywords4.InList(s)) {
                        sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD4);
                    } else if (sc.GetRelative(-static_cast<int>(strlen(s))-1) == '{' &&
                        keywords5.InList(s) && sc.ch == '}') { // {keyword} exactly no spaces
                            sc.ChangeState(SCE_TCL_EXPAND);
                    }
                    if (keywords6.InList(s)) {
                        sc.ChangeState(SCE_TCL_WORD5);
                    } else if (keywords7.InList(s)) {
                        sc.ChangeState(SCE_TCL_WORD6);
                    } else if (keywords8.InList(s)) {
                        sc.ChangeState(SCE_TCL_WORD7);
                    } else if (keywords9.InList(s)) {
                        sc.ChangeState(SCE_TCL_WORD8);
                    }
                }
                expected = false;
                sc.SetState(quote ? SCE_TCL_IN_QUOTE : SCE_TCL_DEFAULT);
            } else if (sc.state == SCE_TCL_MODIFIER || sc.state == SCE_TCL_IDENTIFIER) {
                sc.SetState(SCE_TCL_DEFAULT);
            }
        }
		if (atEnd)
			break;
        if (sc.atLineEnd) {
            lineState = LS_DEFAULT;
			currentLine = styler.GetLine(sc.currentPos);
			if (foldComment && sc.state!=SCE_TCL_COMMENT && isComment(sc.state)) {
				if (currentLevel == 0) {
					++currentLevel;
					commentLevel = true;
				}
			} else {
				if (visibleChars && commentLevel) {
					--currentLevel;
					--previousLevel;
					commentLevel = false;
				}
			}
			int flag = 0;
			if (!visibleChars)
				flag = SC_FOLDLEVELWHITEFLAG;
			if (currentLevel > previousLevel)
				flag = SC_FOLDLEVELHEADERFLAG;
			styler.SetLevel(currentLine, flag + previousLevel + SC_FOLDLEVELBASE + (currentLevel << 17) + (commentLevel << 16));

			// Update the line state, so it can be seen by next line
			if (sc.state == SCE_TCL_IN_QUOTE)
				lineState = LS_OPEN_DOUBLE_QUOTE;
			else {
			     if (prevSlash) {
				    if (isComment(sc.state))
					    lineState = LS_OPEN_COMMENT;
                } else if (sc.state == SCE_TCL_COMMENT_BOX)
                    lineState = LS_COMMENT_BOX;
			}
            styler.SetLineState(currentLine,
                (subBrace ? LS_BRACE_ONLY : 0) |
                (expected ? LS_COMMAND_EXPECTED : 0)  | lineState);
            if (lineState == LS_COMMENT_BOX)
                sc.ForwardSetState(SCE_TCL_COMMENT_BOX);
            else if (lineState == LS_OPEN_DOUBLE_QUOTE)
                sc.ForwardSetState(SCE_TCL_IN_QUOTE);
            else
                sc.ForwardSetState(SCE_TCL_DEFAULT);
			prevSlash = false;
			previousLevel = currentLevel;
			goto next;
		}

		if (prevSlash) {
            prevSlash = false;
            if (sc.ch == '#' && IsANumberChar(sc.chNext))
                sc.ForwardSetState(SCE_TCL_NUMBER);
            continue;
		}
        prevSlash = sc.ch == '\\';
        if (isComment(sc.state))
            continue;
		if (sc.atLineStart) {
			visibleChars = false;
			if (sc.state!=SCE_TCL_IN_QUOTE && !isComment(sc.state))
            {
				sc.SetState(SCE_TCL_DEFAULT);
                expected = IsAWordStart(sc.ch)|| isspacechar(static_cast<unsigned char>(sc.ch));
            }
		}

		switch (sc.state) {
		case SCE_TCL_NUMBER:
			if (!IsANumberChar(sc.ch))
				sc.SetState(SCE_TCL_DEFAULT);
			break;
		case SCE_TCL_IN_QUOTE:
			if (sc.ch == '"') {
				sc.ForwardSetState(SCE_TCL_DEFAULT);
				visibleChars = true; // necessary if a " is the first and only character on a line
				goto next;
			} else if (sc.ch == '[' || sc.ch == ']' || sc.ch == '$') {
				sc.SetState(SCE_TCL_OPERATOR);
                expected = sc.ch == '[';
                sc.ForwardSetState(SCE_TCL_IN_QUOTE);
				goto next;
			}
            continue;
        case SCE_TCL_OPERATOR:
			sc.SetState(SCE_TCL_DEFAULT);
			break;
		}

		if (sc.ch == '#') {
			if (visibleChars) {
                if (sc.state != SCE_TCL_IN_QUOTE && expected)
					sc.SetState(SCE_TCL_COMMENT);
			} else {
                sc.SetState(SCE_TCL_COMMENTLINE);
                if (sc.chNext == '~')
                    sc.SetState(SCE_TCL_BLOCK_COMMENT);
                if (sc.atLineStart && (sc.chNext == '#' || sc.chNext == '-'))
                        sc.SetState(SCE_TCL_COMMENT_BOX);
            }
        }

		if (!isspacechar(static_cast<unsigned char>(sc.ch))) {
			visibleChars = true;
		}

		if (sc.ch == '\\') {
			prevSlash = true;
			continue;
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_TCL_DEFAULT) {
            if (IsAWordStart(sc.ch)) {
				sc.SetState(SCE_TCL_IDENTIFIER);
			} else if (IsADigit(sc.ch) && !IsAWordChar(sc.chPrev)) {
				sc.SetState(SCE_TCL_NUMBER);
			} else {
				switch (sc.ch) {
				case '\"':
					sc.SetState(SCE_TCL_IN_QUOTE);
					break;
				case '{':
					sc.SetState(SCE_TCL_OPERATOR);
					expected = true;
					++currentLevel;
					break;
				case '}':
					sc.SetState(SCE_TCL_OPERATOR);
					expected = true;
					--currentLevel;
					break;
				case '[':
                    expected = true;
				case ']':
				case '(':
				case ')':
					sc.SetState(SCE_TCL_OPERATOR);
					break;
				case ';':
                    expected = true;
					break;
                case '$':
                    subParen = 0;
                    if (sc.chNext != '{') {
                        sc.SetState(SCE_TCL_SUBSTITUTION);
                    }
                    else {
                        sc.SetState(SCE_TCL_OPERATOR);  // $
                        sc.Forward();  // {
                        sc.ForwardSetState(SCE_TCL_SUB_BRACE);
                        subBrace = true;
                    }
                    break;
                case '#':
                    if ((isspacechar(static_cast<unsigned char>(sc.chPrev))||
                            isoperator(static_cast<char>(sc.chPrev))) && IsADigit(sc.chNext,0x10))
                        sc.SetState(SCE_TCL_NUMBER);
                    break;
                case '-':
                    sc.SetState(IsADigit(sc.chNext)? SCE_TCL_NUMBER: SCE_TCL_MODIFIER);
                    break;
                default:
                    if (isoperator(static_cast<char>(sc.ch))) {
                        sc.SetState(SCE_TCL_OPERATOR);
                    }
				}
			}
		}
	}
	sc.Complete();
}

static const char * const tclWordListDesc[] = {
            "TCL Keywords",
            "TK Keywords",
            "iTCL Keywords",
            "tkCommands",
            "expand"
            "user1",
            "user2",
            "user3",
            "user4",
            0
        };

// this code supports folding in the colourizer
LexerModule lmTCL(SCLEX_TCL, ColouriseTCLDoc, "tcl", 0, tclWordListDesc);
<commit_msg>Add missing comma.<commit_after>// Scintilla source code edit control
/** @file LexTCL.cxx
 ** Lexer for TCL language.
 **/
// Copyright 1998-2001 by Andre Arpin <arpin@kingston.net>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>

#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"

#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

// Extended to accept accented characters
static inline bool IsAWordChar(int ch) {
	return ch >= 0x80 ||
        (isalnum(ch) || ch == '_' || ch ==':' || ch=='.'); // : name space separator
}

static inline bool IsAWordStart(int ch) {
	return ch >= 0x80 || (ch ==':' || isalpha(ch) || ch == '_');
}

static inline bool IsANumberChar(int ch) {
	// Not exactly following number definition (several dots are seen as OK, etc.)
	// but probably enough in most cases.
	return (ch < 0x80) &&
	       (IsADigit(ch, 0x10) || toupper(ch) == 'E' ||
	        ch == '.' || ch == '-' || ch == '+');
}

static void ColouriseTCLDoc(unsigned int startPos, int length, int , WordList *keywordlists[], Accessor &styler) {
#define  isComment(s) (s==SCE_TCL_COMMENT || s==SCE_TCL_COMMENTLINE || s==SCE_TCL_COMMENT_BOX || s==SCE_TCL_BLOCK_COMMENT)
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool commentLevel = false;
    bool subBrace = false; // substitution begin with a brace ${.....}
	enum tLineState {LS_DEFAULT, LS_OPEN_COMMENT, LS_OPEN_DOUBLE_QUOTE, LS_COMMENT_BOX, LS_MASK_STATE = 0xf,
        LS_COMMAND_EXPECTED = 16, LS_BRACE_ONLY = 32 } lineState = LS_DEFAULT;
	bool prevSlash = false;
	int currentLevel = 0;
    bool expected = 0;
    bool subParen = 0;

	int currentLine = styler.GetLine(startPos);
    if (currentLine > 0)
        currentLine--;
	length += startPos - styler.LineStart(currentLine);
	// make sure lines overlap
	startPos = styler.LineStart(currentLine);

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];
	WordList &keywords4 = *keywordlists[3];
	WordList &keywords5 = *keywordlists[4];
	WordList &keywords6 = *keywordlists[5];
	WordList &keywords7 = *keywordlists[6];
    WordList &keywords8 = *keywordlists[7];
    WordList &keywords9 = *keywordlists[8];

	if (currentLine > 0) {
        int ls = styler.GetLineState(currentLine - 1);
		lineState = tLineState(ls & LS_MASK_STATE);
		expected = LS_COMMAND_EXPECTED == tLineState(ls & LS_COMMAND_EXPECTED);
        subBrace = LS_BRACE_ONLY == tLineState(ls & LS_BRACE_ONLY);
		currentLevel = styler.LevelAt(currentLine - 1) >> 17;
		commentLevel = (styler.LevelAt(currentLine - 1) >> 16) & 1;
	} else
		styler.SetLevel(0, SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG);
	bool visibleChars = false;

	int previousLevel = currentLevel;
    StyleContext sc(startPos, length, SCE_TCL_DEFAULT, styler);
	for (; ; sc.Forward()) {
next:
        if (sc.ch=='\r' && sc.chNext == '\n') // only ignore \r on PC process on the mac
            continue;
        bool atEnd = !sc.More();  // make sure we coloured the last word
        if (lineState != LS_DEFAULT) {
            sc.SetState(SCE_TCL_DEFAULT);
            if (lineState == LS_OPEN_COMMENT)
                sc.SetState(SCE_TCL_COMMENTLINE);
            else if (lineState == LS_OPEN_DOUBLE_QUOTE)
                sc.SetState(SCE_TCL_IN_QUOTE);
            else if (lineState == LS_COMMENT_BOX && (sc.ch == '#' || (sc.ch == ' ' && sc.chNext=='#')))
                sc.SetState(SCE_TCL_COMMENT_BOX);
            lineState = LS_DEFAULT;
        }
        if (subBrace) { // ${ overrides every thing even \ except }
            if (sc.ch == '}') {
                subBrace = false;
                sc.SetState(SCE_TCL_OPERATOR);
                sc.ForwardSetState(SCE_TCL_DEFAULT);
                goto next;
            }
            else
                sc.SetState(SCE_TCL_SUB_BRACE);
            if (!sc.atLineEnd)
                continue;
        } else if (sc.state == SCE_TCL_DEFAULT || sc.state ==SCE_TCL_OPERATOR) {
            expected &= isspacechar(static_cast<unsigned char>(sc.ch)) || IsAWordStart(sc.ch) || sc.ch =='#';
        } else if (sc.state == SCE_TCL_SUBSTITUTION) {
            switch(sc.ch) {
            case '(':
                subParen=true;
                sc.SetState(SCE_TCL_OPERATOR);
                sc.ForwardSetState(SCE_TCL_SUBSTITUTION);
                continue;
            case ')':
                sc.SetState(SCE_TCL_OPERATOR);
                subParen=false;
                continue;
            case '$':
                continue;
            case ',':
                sc.SetState(SCE_TCL_OPERATOR);
                if (subParen)
                    sc.ForwardSetState(SCE_TCL_SUBSTITUTION);
                continue;
            default :
                // maybe spaces should be allowed ???
                if (!IsAWordChar(sc.ch)) { // probably the code is wrong
                    sc.SetState(SCE_TCL_DEFAULT);
                    subParen = 0;
                }
                break;
            }
        } else if (isComment(sc.state)) {
        } else if (!IsAWordChar(sc.ch)) {
            if ((sc.state == SCE_TCL_IDENTIFIER && expected) ||  sc.state == SCE_TCL_MODIFIER) {
                char w[100];
                char *s=w;
                sc.GetCurrent(w, sizeof(w));
                if (w[strlen(w)-1]=='\r')
                    w[strlen(w)-1]=0;
                while(*s == ':') // ignore leading : like in ::set a 10
                    ++s;
                bool quote = sc.state == SCE_TCL_IN_QUOTE;
                if (commentLevel  || expected) {
                    if (keywords.InList(s)) {
                        sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD);
                    } else if (keywords2.InList(s)) {
                        sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD2);
                    } else if (keywords3.InList(s)) {
                        sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD3);
                    } else if (keywords4.InList(s)) {
                        sc.ChangeState(quote ? SCE_TCL_WORD_IN_QUOTE : SCE_TCL_WORD4);
                    } else if (sc.GetRelative(-static_cast<int>(strlen(s))-1) == '{' &&
                        keywords5.InList(s) && sc.ch == '}') { // {keyword} exactly no spaces
                            sc.ChangeState(SCE_TCL_EXPAND);
                    }
                    if (keywords6.InList(s)) {
                        sc.ChangeState(SCE_TCL_WORD5);
                    } else if (keywords7.InList(s)) {
                        sc.ChangeState(SCE_TCL_WORD6);
                    } else if (keywords8.InList(s)) {
                        sc.ChangeState(SCE_TCL_WORD7);
                    } else if (keywords9.InList(s)) {
                        sc.ChangeState(SCE_TCL_WORD8);
                    }
                }
                expected = false;
                sc.SetState(quote ? SCE_TCL_IN_QUOTE : SCE_TCL_DEFAULT);
            } else if (sc.state == SCE_TCL_MODIFIER || sc.state == SCE_TCL_IDENTIFIER) {
                sc.SetState(SCE_TCL_DEFAULT);
            }
        }
		if (atEnd)
			break;
        if (sc.atLineEnd) {
            lineState = LS_DEFAULT;
			currentLine = styler.GetLine(sc.currentPos);
			if (foldComment && sc.state!=SCE_TCL_COMMENT && isComment(sc.state)) {
				if (currentLevel == 0) {
					++currentLevel;
					commentLevel = true;
				}
			} else {
				if (visibleChars && commentLevel) {
					--currentLevel;
					--previousLevel;
					commentLevel = false;
				}
			}
			int flag = 0;
			if (!visibleChars)
				flag = SC_FOLDLEVELWHITEFLAG;
			if (currentLevel > previousLevel)
				flag = SC_FOLDLEVELHEADERFLAG;
			styler.SetLevel(currentLine, flag + previousLevel + SC_FOLDLEVELBASE + (currentLevel << 17) + (commentLevel << 16));

			// Update the line state, so it can be seen by next line
			if (sc.state == SCE_TCL_IN_QUOTE)
				lineState = LS_OPEN_DOUBLE_QUOTE;
			else {
			     if (prevSlash) {
				    if (isComment(sc.state))
					    lineState = LS_OPEN_COMMENT;
                } else if (sc.state == SCE_TCL_COMMENT_BOX)
                    lineState = LS_COMMENT_BOX;
			}
            styler.SetLineState(currentLine,
                (subBrace ? LS_BRACE_ONLY : 0) |
                (expected ? LS_COMMAND_EXPECTED : 0)  | lineState);
            if (lineState == LS_COMMENT_BOX)
                sc.ForwardSetState(SCE_TCL_COMMENT_BOX);
            else if (lineState == LS_OPEN_DOUBLE_QUOTE)
                sc.ForwardSetState(SCE_TCL_IN_QUOTE);
            else
                sc.ForwardSetState(SCE_TCL_DEFAULT);
			prevSlash = false;
			previousLevel = currentLevel;
			goto next;
		}

		if (prevSlash) {
            prevSlash = false;
            if (sc.ch == '#' && IsANumberChar(sc.chNext))
                sc.ForwardSetState(SCE_TCL_NUMBER);
            continue;
		}
        prevSlash = sc.ch == '\\';
        if (isComment(sc.state))
            continue;
		if (sc.atLineStart) {
			visibleChars = false;
			if (sc.state!=SCE_TCL_IN_QUOTE && !isComment(sc.state))
            {
				sc.SetState(SCE_TCL_DEFAULT);
                expected = IsAWordStart(sc.ch)|| isspacechar(static_cast<unsigned char>(sc.ch));
            }
		}

		switch (sc.state) {
		case SCE_TCL_NUMBER:
			if (!IsANumberChar(sc.ch))
				sc.SetState(SCE_TCL_DEFAULT);
			break;
		case SCE_TCL_IN_QUOTE:
			if (sc.ch == '"') {
				sc.ForwardSetState(SCE_TCL_DEFAULT);
				visibleChars = true; // necessary if a " is the first and only character on a line
				goto next;
			} else if (sc.ch == '[' || sc.ch == ']' || sc.ch == '$') {
				sc.SetState(SCE_TCL_OPERATOR);
                expected = sc.ch == '[';
                sc.ForwardSetState(SCE_TCL_IN_QUOTE);
				goto next;
			}
            continue;
        case SCE_TCL_OPERATOR:
			sc.SetState(SCE_TCL_DEFAULT);
			break;
		}

		if (sc.ch == '#') {
			if (visibleChars) {
                if (sc.state != SCE_TCL_IN_QUOTE && expected)
					sc.SetState(SCE_TCL_COMMENT);
			} else {
                sc.SetState(SCE_TCL_COMMENTLINE);
                if (sc.chNext == '~')
                    sc.SetState(SCE_TCL_BLOCK_COMMENT);
                if (sc.atLineStart && (sc.chNext == '#' || sc.chNext == '-'))
                        sc.SetState(SCE_TCL_COMMENT_BOX);
            }
        }

		if (!isspacechar(static_cast<unsigned char>(sc.ch))) {
			visibleChars = true;
		}

		if (sc.ch == '\\') {
			prevSlash = true;
			continue;
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_TCL_DEFAULT) {
            if (IsAWordStart(sc.ch)) {
				sc.SetState(SCE_TCL_IDENTIFIER);
			} else if (IsADigit(sc.ch) && !IsAWordChar(sc.chPrev)) {
				sc.SetState(SCE_TCL_NUMBER);
			} else {
				switch (sc.ch) {
				case '\"':
					sc.SetState(SCE_TCL_IN_QUOTE);
					break;
				case '{':
					sc.SetState(SCE_TCL_OPERATOR);
					expected = true;
					++currentLevel;
					break;
				case '}':
					sc.SetState(SCE_TCL_OPERATOR);
					expected = true;
					--currentLevel;
					break;
				case '[':
                    expected = true;
				case ']':
				case '(':
				case ')':
					sc.SetState(SCE_TCL_OPERATOR);
					break;
				case ';':
                    expected = true;
					break;
                case '$':
                    subParen = 0;
                    if (sc.chNext != '{') {
                        sc.SetState(SCE_TCL_SUBSTITUTION);
                    }
                    else {
                        sc.SetState(SCE_TCL_OPERATOR);  // $
                        sc.Forward();  // {
                        sc.ForwardSetState(SCE_TCL_SUB_BRACE);
                        subBrace = true;
                    }
                    break;
                case '#':
                    if ((isspacechar(static_cast<unsigned char>(sc.chPrev))||
                            isoperator(static_cast<char>(sc.chPrev))) && IsADigit(sc.chNext,0x10))
                        sc.SetState(SCE_TCL_NUMBER);
                    break;
                case '-':
                    sc.SetState(IsADigit(sc.chNext)? SCE_TCL_NUMBER: SCE_TCL_MODIFIER);
                    break;
                default:
                    if (isoperator(static_cast<char>(sc.ch))) {
                        sc.SetState(SCE_TCL_OPERATOR);
                    }
				}
			}
		}
	}
	sc.Complete();
}

static const char * const tclWordListDesc[] = {
            "TCL Keywords",
            "TK Keywords",
            "iTCL Keywords",
            "tkCommands",
            "expand",
            "user1",
            "user2",
            "user3",
            "user4",
            0
        };

// this code supports folding in the colourizer
LexerModule lmTCL(SCLEX_TCL, ColouriseTCLDoc, "tcl", 0, tclWordListDesc);
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
//
// CGRA Math Library
//
//
//----------------------------------------------------------------------------

#pragma once

#include <cassert>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <random>
#include <sstream>
#include <string>
#include <type_traits>

namespace cgra {

}

<commit_msg>Added basic vector matrix and quaternion definitions<commit_after>//----------------------------------------------------------------------------
//
// CGRA Math Library
//
//
//----------------------------------------------------------------------------

#pragma once

#include <cassert>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <random>
#include <sstream>
#include <string>
#include <type_traits>

namespace cgra {

	template <typename, size_t> class basic_vec;
	template <typename, size_t, size_t> class basic_mat;
	template <typename> class basic_quat;

	template <typename T, size_t N>
	class basic_vec {
	private:
		T m_data[N];

	public:
		using value_t = T;
		static constexpr size_t size = N;

		// TODO more constructors
		basic_vec() { }

		const T & operator[](size_t i) const {
			assert(i < N);
			return m_data[i];
		}

		T & operator[](size_t i) {
			assert(i < N);
			return m_data[i];
		}

		inline friend std::ostream & operator<<(std::ostream &out, const basic_vec &v) {
			return out << '(' << ')';
		}
	};

	template <typename T>
	class basic_vec<T, 0> {
	public:
		using value_t = T;
		static constexpr size_t size = 0;

		basic_vec() { }
		template <typename U>
		basic_vec(const basic_vec<U, 0> &v) { }

		const T & operator[](size_t i) const {
			assert(false);
			return *(this);
		}

		T & operator[](size_t i) {
			assert(false);
			return *(this);
		}

		inline friend std::ostream & operator<<(std::ostream &out, const basic_vec &v) {
			return out << '(' << ')';
		}
	};

	template <typename T>
	class basic_vec<T, 1> {
	public:
		using value_t = T;
		static constexpr size_t size = 1;

		union{ T x; T r; T s; };

		basic_vec() : x(0) { }
		explicit basic_vec(T s) : x(s) { }
		explicit basic_vec(const T *p) : x(p[0]) { }
		template <typename U>
		basic_vec(const basic_vec<U, 1> &v) : x(v.x) { }

		const T & operator[](size_t i) const {
			assert(i < 1);
			return (&x)[i];
		}

		T & operator[](size_t i) {
			assert(i < 1);
			return (&x)[i];
		}

		inline friend std::ostream & operator<<(std::ostream &out, const basic_vec &v) {
			return out << '(' << v.x << ')';
		}
	};

	template <typename T>
	class basic_vec<T, 2> {
	public:
		using value_t = T;
		static constexpr size_t size = 2;

		union{ T x; T r; T s; };
		union{ T y; T g; T t; };

		basic_vec() : x(0), y(0) { }
		basic_vec(T _x, T _y) : x(_x), y(_y) { }
		explicit basic_vec(T s) : x(s), y(s) { }
		explicit basic_vec(const T *p) : x(p[0]), y(p[1]) { }
		template <typename U>
		basic_vec(const basic_vec<U, 2> &v) : x(v.x), y(v.y) { }

		const T & operator[](size_t i) const {
			assert(i < 2);
			return (&x)[i];
		}

		T & operator[](size_t i) {
			assert(i < 2);
			return (&x)[i];
		}

		inline friend std::ostream & operator<<(std::ostream &out, const basic_vec &v) {
			return out << '(' << v.x << ", " << v.y << ')';
		}
	};

	template <typename T>
	class basic_vec<T, 3> {
	public:
		using value_t = T;
		static constexpr size_t size = 3;

		union{ T x; T r; T s; };
		union{ T y; T g; T t; };
		union{ T z; T b; T p; };

		basic_vec() : x(0), y(0), z(0) { }
		basic_vec(T _x, T _y, T _z) : x(_x), y(_y), z(_z) { }
		explicit basic_vec(T s) : x(s), y(s), z(s) { }
		explicit basic_vec(const T *p) : x(p[0]), y(p[1]), z(p[2]) { }
		template <typename U>
		basic_vec(const basic_vec<U, 3> &v) : x(v.x), y(v.y), z(v.z) { }

		const T & operator[](size_t i) const {
			assert(i < 3);
			return (&x)[i];
		}

		T & operator[](size_t i) {
			assert(i < 3);
			return (&x)[i];
		}

		inline friend std::ostream & operator<<(std::ostream &out, const basic_vec &v) {
			return out << '(' << v.x << ", " << v.y << ", " << v.z << ')';
		}
	};

	template <typename T>
	class basic_vec<T, 4> {
	public:
		using value_t = T;
		static constexpr size_t size = 4;

		union{ T x; T r; T s; };
		union{ T y; T g; T t; };
		union{ T z; T b; T p; };
		union{ T w; T a; T q; };

		basic_vec() : x(0), y(0), z(0), w(0) { }
		basic_vec(T _x, T _y, T _z, T _w) : x(_x), y(_y), z(_z), w(_w) { }
		explicit basic_vec(T s) : x(s), y(s), z(s), w(s) { }
		explicit basic_vec(const T *p) : x(p[0]), y(p[1]), z(p[2]), w(p[3]) { }
		template <typename U>
		basic_vec(const basic_vec<U, 4> &v) : x(v.x), y(v.y), z(v.z), w(v.w) { }

		const T & operator[](size_t i) const {
			assert(i < 4);
			return (&x)[i];
		}

		T & operator[](size_t i) {
			assert(i < 4);
			return (&x)[i];
		}

		inline friend std::ostream & operator<<(std::ostream &out, const basic_vec &v) {
			return out << '(' << v.x << ", " << v.y << ", " << v.z << ", " << v.w << ')';
		}
	};

	template <typename T, size_t M, size_t N>
	class basic_mat {
	private:
		T m_data[M*N];

	public:
		using value_t = T;
		static constexpr size_t cols = M;
		static constexpr size_t rows = N;
		static constexpr size_t size = M*N;

		// TODO more constructors
		basic_mat() { }

		const T & operator[](size_t i) const {
			assert(i < M);
			return reinterpret_cast<const basic_vec<T, N> &>(m_data[N*i]);
		}

		T & operator[](size_t i) {
			assert(i < M);
			return reinterpret_cast<basic_vec<T, N> &>(m_data[N*i]);
		}

		// TODO stream insertion
	};

	template <typename T>
	class basic_quat {
		using value_t = T;
		static constexpr size_t size = 4;

		T w, x, y, z;

		basic_quat() : w(1), x(0), y(0), z(0) { }
		basic_quat(T _w, T _x, T _y, T _z) :  w(_w), x(_x), y(_y), z(_z) { }
		template <typename U>
		basic_quat(const basic_quat<U>& q) : w(q.w), x(q.x), y(q.y), z(q.z) { }
		template <typename U>
		basic_quat(T _w, const basic_vec<U, 3> &v) : w(_w), x(v.x), y(v.y), z(v.z) { }
		template <typename U1, typename U2>
		basic_quat(const basic_vec<U1, 1> &v1, const basic_vec<U2, 3> &v2) : w(v1.x), x(v2.x), y(v2.y), z(v2.z) { }
		template <typename U>
		basic_quat(const basic_vec<U, 4> &v) : w(v.w), x(v.x), y(v.y), z(v.z) { }

	};

}

<|endoftext|>


<commit_before>#include <osgText/String>

#include <osg/Math>
#include <osg/Notify>

using namespace osgText;

////////////////////////////////////////////////////////////////////////
//
// helper class to make it safer to querry std::string's for encoding.
//
struct look_ahead_iterator
{
    look_ahead_iterator(const std::string& string):
        _string(string),
        _index(0),
        _nullCharacter(0) {}

    bool valid() const { return _index<_string.length(); }

    look_ahead_iterator& operator ++ ()
    {
        if (_index<_string.length()) ++_index;
        return *this;
    }

    look_ahead_iterator operator ++ (int)
    {
        look_ahead_iterator tmp(*this);
        if (_index<_string.length()) ++_index;
        return tmp;
    }

    look_ahead_iterator& operator += (int offset)
    {
        if (_index<_string.length()) _index = osg::minimum((unsigned int)(_index+offset),(unsigned int)_string.length());
        return *this;
    }

    unsigned char operator * () const
    {
        if (_index<_string.length()) return _string[_index];
        else return _nullCharacter;
    }

    unsigned char operator [] (unsigned int offset) const
    {

        if (_index+offset<_string.length()) return _string[_index+offset];
        else return _nullCharacter;
    }

    const std::string&      _string;
    unsigned int            _index;
    unsigned char           _nullCharacter;
};

String::Encoding findEncoding(look_ahead_iterator& charString,String::Encoding overrideEncoding)
{
    switch (charString[0])
    {
        case 0xEF: // 8-bit encoding
        {
            // 8-bit signature = EF BB BF
            if ((charString[1]==0xBB) && (charString[2]==0xBF))
            {
                charString+=3;
                return String::ENCODING_UTF8;
            }
            break;
        }
        case 0xFE: // big-endian 16-bit
        {
            // 16-bit signature = FE FF
            if (charString[1]==0xFF)
            {
                charString+=2;
                return String::ENCODING_UTF16_BE;
            }
            break;
        }
        case 0xFF: // little-endian
        {
            // 16-bit signature = FF FE
            // 32-bit signature = FF FE 00 00
            if (charString[1]==0xFE)
            {
                // NOTE: There is an a potential problem as a 16-bit empty string
                // is identical to a 32-bit start signature
                if ((charString[2]==0) && (charString[3]==0) && (overrideEncoding != String::ENCODING_UTF16)) //32-bit
                {
                    charString+=4;
                    return String::ENCODING_UTF32_LE;
                }
                else //16-bit
                {
                    charString+=2;
                    return String::ENCODING_UTF16_LE;
                }
            }
            break;
        }
        case 0x00: // 32-bit big-endian
        {
            // 32-bit signature = 00 00 FE FF
            if ((charString[1]==0x00) && (charString[2]==0xFE) && (charString[3]==0xFF))
            {
                charString+=4;
                return String::ENCODING_UTF32_BE;
            }
            break;
        }
    }
    return String::ENCODING_ASCII;
}

unsigned int getNextCharacter(look_ahead_iterator& charString,String::Encoding encoding)
{
    // For more info on unicode encodings see:
    // http://www-106.ibm.com/developerworks/unicode/library/u-encode.html
    switch(encoding)
    {
        case String::ENCODING_ASCII:
        {
            return *charString++;
        }
        case String::ENCODING_UTF8:
        {
            int char0 = *charString++;
            if (char0 < 0x80) // 1-byte character
            {
                return char0;
            }
            int char1 = *charString++;
            if (char0<0xe0) // 2-byte character
            {
                return ((char0&0x1f)<<6) | (char1&0x3f);
            }
            int char2 = *charString++;
            if (char0<0xf0) // 3-byte character
            {
                return ((char0&0xf)<<12) | ((char1&0x3f)<<6) | (char2&0x3f);
            }
            int char3 = *charString++;
            if (char0<0xf8) // 4-byte character
            {
                return ((char0&0x7)<<18) | ((char1&0x3f)<<12) | ((char2&0x3f)<<6) | (char3&0x3f);
            }
            break;
        }
        case String::ENCODING_UTF16_BE:
        {
            int char0 = *charString++;
            int char1 = *charString++;
            if ((char0<=0xD7) || (char0>=0xE0)) // simple character
            {
                return (char0<<8) | char1;
            }
            else if ((char0>=0xD8)&&(char0<=0xDB)) //using planes (this should get called very rarely)
            {
                int char2 = *charString++;
                int char3 = *charString++;
                int highSurrogate = (char0<<8) | char1;
                int lowSurrogate = (char2<<8) | char3;
                if ((char2>=0xDC)&&(char2<=0xDF)) //only for the valid range of low surrogate
                {
                    // This covers the range of all 17 unicode planes
                    return ((highSurrogate-0xD800)*0x400) + (lowSurrogate-0xD800) + 0x10000;
                }
            }
            break;
        }
        case String::ENCODING_UTF16_LE:
        {
            int char1 = *charString++;
            int char0 = *charString++;
            if ((char0<=0xD7) || (char0>=0xE0)) // simple character
            {
                return (char0<<8) | char1;
            }
            else if ((char0>=0xD8)&&(char0<=0xDB)) //using planes (this should get called very rarely)
            {
                int char3 = *charString++;
                int char2 = *charString++;
                int highSurrogate = (char0<<8) | char1;
                int lowSurrogate = (char2<<8) | char3;
                if ((char2>=0xDC)&&(char2<=0xDF)) //only for the valid range of low surrogate
                {
                    // This covers the range of all 17 unicode planes
                    return ((highSurrogate-0xD800)*0x400) + (lowSurrogate-0xD800) + 0x10000;
                }
            }
            break;
        }
        case String::ENCODING_UTF32_BE:
        {
            int character = ((((int)charString[0])<<24) | (((int)charString[1])<<16) |
                            (((int)charString[2])<<8) | charString[3]);
            charString+=4;
            if (character<0x110000)
            {
                // Character is constrained to the range set by the unicode standard
                return character;
            }
            break;
        }
        case String::ENCODING_UTF32_LE:
        {
            int character = ((((int)charString[3])<<24) | (((int)charString[2])<<16) |
                            (((int)charString[1])<<8) | charString[0]);
            charString+=4;
            if (character<0x110000)
            {
                // Character is constrained to the range set by the unicode standard
                return character;
            }
            break;
        }
        default:
        {
            // Should not reach this point unless the encoding is unhandled
            // ENCODING_UTF16, ENCODING_UTF32 and ENCODING_SIGNATURE should never enter this method
            osg::notify(osg::FATAL)<<"Error: Invalid string encoding"<<std::endl;
            break;
        }
    }
    return 0;
}

////////////////////////////////////////////////////////////////////////////
//
// String implemention.
//

String::String(const String& str):
    osg::Referenced(),
    std::vector<unsigned int>(str)
{
}

String& String::operator = (const String& str)
{
    if (&str==this) return *this;

    clear();
    std::copy(str.begin(),str.end(),std::back_inserter(*this));

    return *this;
}

void String::set(const std::string& text)
{
    clear();
    std::copy(text.begin(),text.end(),std::back_inserter(*this));
}

void String::set(const wchar_t* text)
{
    clear();
    while(*text)
    {
        push_back(*text++);
    }
}

void String::set(const std::string& text,Encoding encoding)
{
    clear();

    look_ahead_iterator itr(text);

    if ((encoding == ENCODING_SIGNATURE) ||
        (encoding == ENCODING_UTF16) ||
        (encoding == ENCODING_UTF32))
    {
        encoding = findEncoding(itr,encoding);
    }

    while(itr.valid())
    {
        unsigned int c = getNextCharacter(itr,encoding);
        if (c) push_back(c);
    }
}

std::string String::createUTF8EncodedString() const
{
    std::string utf8string;
    for(const_iterator itr=begin();
        itr!=end();
        ++itr)
    {
        unsigned int currentChar = *itr;
        if (currentChar < 0x80)
        {
            utf8string+=(char)currentChar;
        }
        else if (currentChar < 0x800)
        {
            utf8string+=(char)(0xc0 | (currentChar>>6));
            utf8string+=(char)(0x80 | currentChar & 0x3f);
        }
        else
        {
            utf8string+=(char)(0xe0 | (currentChar>>12));
            utf8string+=(char)(0x80 | (currentChar>>6) & 0x3f);
            utf8string+=(char)(0x80 | currentChar & 0x3f);
        }
    }
    return utf8string;
}
<commit_msg>Fix from Gabor for proper casting of char's to unsigned ints be setting up the osgText::String.<commit_after>#include <osgText/String>

#include <osg/Math>
#include <osg/Notify>

using namespace osgText;

////////////////////////////////////////////////////////////////////////
//
// helper class to make it safer to querry std::string's for encoding.
//
struct look_ahead_iterator
{
    look_ahead_iterator(const std::string& string):
        _string(string),
        _index(0),
        _nullCharacter(0) {}

    bool valid() const { return _index<_string.length(); }

    look_ahead_iterator& operator ++ ()
    {
        if (_index<_string.length()) ++_index;
        return *this;
    }

    look_ahead_iterator operator ++ (int)
    {
        look_ahead_iterator tmp(*this);
        if (_index<_string.length()) ++_index;
        return tmp;
    }

    look_ahead_iterator& operator += (int offset)
    {
        if (_index<_string.length()) _index = osg::minimum((unsigned int)(_index+offset),(unsigned int)_string.length());
        return *this;
    }

    unsigned char operator * () const
    {
        if (_index<_string.length()) return _string[_index];
        else return _nullCharacter;
    }

    unsigned char operator [] (unsigned int offset) const
    {

        if (_index+offset<_string.length()) return _string[_index+offset];
        else return _nullCharacter;
    }

    const std::string&      _string;
    unsigned int            _index;
    unsigned char           _nullCharacter;
};

String::Encoding findEncoding(look_ahead_iterator& charString,String::Encoding overrideEncoding)
{
    switch (charString[0])
    {
        case 0xEF: // 8-bit encoding
        {
            // 8-bit signature = EF BB BF
            if ((charString[1]==0xBB) && (charString[2]==0xBF))
            {
                charString+=3;
                return String::ENCODING_UTF8;
            }
            break;
        }
        case 0xFE: // big-endian 16-bit
        {
            // 16-bit signature = FE FF
            if (charString[1]==0xFF)
            {
                charString+=2;
                return String::ENCODING_UTF16_BE;
            }
            break;
        }
        case 0xFF: // little-endian
        {
            // 16-bit signature = FF FE
            // 32-bit signature = FF FE 00 00
            if (charString[1]==0xFE)
            {
                // NOTE: There is an a potential problem as a 16-bit empty string
                // is identical to a 32-bit start signature
                if ((charString[2]==0) && (charString[3]==0) && (overrideEncoding != String::ENCODING_UTF16)) //32-bit
                {
                    charString+=4;
                    return String::ENCODING_UTF32_LE;
                }
                else //16-bit
                {
                    charString+=2;
                    return String::ENCODING_UTF16_LE;
                }
            }
            break;
        }
        case 0x00: // 32-bit big-endian
        {
            // 32-bit signature = 00 00 FE FF
            if ((charString[1]==0x00) && (charString[2]==0xFE) && (charString[3]==0xFF))
            {
                charString+=4;
                return String::ENCODING_UTF32_BE;
            }
            break;
        }
    }
    return String::ENCODING_ASCII;
}

unsigned int getNextCharacter(look_ahead_iterator& charString,String::Encoding encoding)
{
    // For more info on unicode encodings see:
    // http://www-106.ibm.com/developerworks/unicode/library/u-encode.html
    switch(encoding)
    {
        case String::ENCODING_ASCII:
        {
            return *charString++;
        }
        case String::ENCODING_UTF8:
        {
            int char0 = *charString++;
            if (char0 < 0x80) // 1-byte character
            {
                return char0;
            }
            int char1 = *charString++;
            if (char0<0xe0) // 2-byte character
            {
                return ((char0&0x1f)<<6) | (char1&0x3f);
            }
            int char2 = *charString++;
            if (char0<0xf0) // 3-byte character
            {
                return ((char0&0xf)<<12) | ((char1&0x3f)<<6) | (char2&0x3f);
            }
            int char3 = *charString++;
            if (char0<0xf8) // 4-byte character
            {
                return ((char0&0x7)<<18) | ((char1&0x3f)<<12) | ((char2&0x3f)<<6) | (char3&0x3f);
            }
            break;
        }
        case String::ENCODING_UTF16_BE:
        {
            int char0 = *charString++;
            int char1 = *charString++;
            if ((char0<=0xD7) || (char0>=0xE0)) // simple character
            {
                return (char0<<8) | char1;
            }
            else if ((char0>=0xD8)&&(char0<=0xDB)) //using planes (this should get called very rarely)
            {
                int char2 = *charString++;
                int char3 = *charString++;
                int highSurrogate = (char0<<8) | char1;
                int lowSurrogate = (char2<<8) | char3;
                if ((char2>=0xDC)&&(char2<=0xDF)) //only for the valid range of low surrogate
                {
                    // This covers the range of all 17 unicode planes
                    return ((highSurrogate-0xD800)*0x400) + (lowSurrogate-0xD800) + 0x10000;
                }
            }
            break;
        }
        case String::ENCODING_UTF16_LE:
        {
            int char1 = *charString++;
            int char0 = *charString++;
            if ((char0<=0xD7) || (char0>=0xE0)) // simple character
            {
                return (char0<<8) | char1;
            }
            else if ((char0>=0xD8)&&(char0<=0xDB)) //using planes (this should get called very rarely)
            {
                int char3 = *charString++;
                int char2 = *charString++;
                int highSurrogate = (char0<<8) | char1;
                int lowSurrogate = (char2<<8) | char3;
                if ((char2>=0xDC)&&(char2<=0xDF)) //only for the valid range of low surrogate
                {
                    // This covers the range of all 17 unicode planes
                    return ((highSurrogate-0xD800)*0x400) + (lowSurrogate-0xD800) + 0x10000;
                }
            }
            break;
        }
        case String::ENCODING_UTF32_BE:
        {
            int character = ((((int)charString[0])<<24) | (((int)charString[1])<<16) |
                            (((int)charString[2])<<8) | charString[3]);
            charString+=4;
            if (character<0x110000)
            {
                // Character is constrained to the range set by the unicode standard
                return character;
            }
            break;
        }
        case String::ENCODING_UTF32_LE:
        {
            int character = ((((int)charString[3])<<24) | (((int)charString[2])<<16) |
                            (((int)charString[1])<<8) | charString[0]);
            charString+=4;
            if (character<0x110000)
            {
                // Character is constrained to the range set by the unicode standard
                return character;
            }
            break;
        }
        default:
        {
            // Should not reach this point unless the encoding is unhandled
            // ENCODING_UTF16, ENCODING_UTF32 and ENCODING_SIGNATURE should never enter this method
            osg::notify(osg::FATAL)<<"Error: Invalid string encoding"<<std::endl;
            break;
        }
    }
    return 0;
}

////////////////////////////////////////////////////////////////////////////
//
// String implemention.
//

String::String(const String& str):
    osg::Referenced(),
    std::vector<unsigned int>(str)
{
}

String& String::operator = (const String& str)
{
    if (&str==this) return *this;

    clear();
    std::copy(str.begin(),str.end(),std::back_inserter(*this));

    return *this;
}

void String::set(const std::string& text)
{
    clear();
    for ( std::string::const_iterator it = text.begin(); it != text.end(); ++it )
    {
        unsigned int charcode = (unsigned char )*it;
        push_back( charcode );
    }
}

void String::set(const wchar_t* text)
{
    clear();
    while(*text)
    {
        push_back(*text++);
    }
}

void String::set(const std::string& text,Encoding encoding)
{
    clear();

    look_ahead_iterator itr(text);

    if ((encoding == ENCODING_SIGNATURE) ||
        (encoding == ENCODING_UTF16) ||
        (encoding == ENCODING_UTF32))
    {
        encoding = findEncoding(itr,encoding);
    }

    while(itr.valid())
    {
        unsigned int c = getNextCharacter(itr,encoding);
        if (c) push_back(c);
    }
}

std::string String::createUTF8EncodedString() const
{
    std::string utf8string;
    for(const_iterator itr=begin();
        itr!=end();
        ++itr)
    {
        unsigned int currentChar = *itr;
        if (currentChar < 0x80)
        {
            utf8string+=(char)currentChar;
        }
        else if (currentChar < 0x800)
        {
            utf8string+=(char)(0xc0 | (currentChar>>6));
            utf8string+=(char)(0x80 | currentChar & 0x3f);
        }
        else
        {
            utf8string+=(char)(0xe0 | (currentChar>>12));
            utf8string+=(char)(0x80 | (currentChar>>6) & 0x3f);
            utf8string+=(char)(0x80 | currentChar & 0x3f);
        }
    }
    return utf8string;
}
<|endoftext|>


<commit_before>// Utility libraries
#include "util.h"
#include "libmorton_test.h"
#include <iostream>
#include <iomanip>
#include <inttypes.h>

#define MAX 16 // MAX x MAX x MAX coordinates will be tested / generated
const size_t total = MAX*MAX*MAX; // We need this a lot.
double LUT_ms = 0; // save LUT timing

using namespace std;

void checkDecodeCorrectness(){

}

void checkEncodeCorrectness(){
	printf("++ Checking correctness of encoding methods ... ");
	int failures = 0;
	for (size_t i = 0; i < 16; i++){
		for (size_t j = 0; j < 16; j++){
			for (size_t k = 0; k < 16; k++){
				uint64_t correct_code = control_morton[k + (j * 16) + (i * 16 * 16)];
				uint64_t lut_result = mortonEncode_LUT(i, j, k);
				uint64_t magicbits_result = mortonEncode_magicbits(i, j, k);
				uint64_t for_result = mortonEncode_for(i, j, k);
				if (lut_result != correct_code){printf(" Problem with correctness of LUT based method: %zu does not match %zu \n", lut_result, correct_code); failures++;}
				if (magicbits_result != correct_code){printf(" Problem with correctness of Magicbits based method: %zu does not match %zu \n", magicbits_result, correct_code); failures++;}
				if (for_result != correct_code){printf(" Problem with correctness of Magicbits based method: %zu does not match %zu \n", for_result, correct_code); failures++;}
			}
		}
	}
	if (failures != 0){printf("Correctness test failed \n");} else {printf("Passed. \n");}
}

#pragma optimize( "", off ) // don't optimize this, we're measuring performance here
void encodePerformanceTestLinear(){
	cout << "++ Encoding " << MAX << "^3 morton codes in LINEAR order (" << total << " in total)" << endl;

	Timer morton_LUT, morton_magicbits, morton_for;
	morton_LUT.reset(); morton_LUT.start();
	for (size_t i = 0; i < MAX; i++){
		for (size_t j = 0; j < MAX; j++){
			for (size_t k = 0; k < MAX; k++){
				mortonEncode_LUT(i, j, k);
			}
		}
	}
	morton_LUT.stop();
	cout << " LUT-based method: " << morton_LUT.getTotalTimeMs() << " ms" << endl;
	LUT_ms = morton_LUT.getTotalTimeMs();

	morton_magicbits.reset(); morton_magicbits.start();
	for (size_t i = 0; i < MAX; i++){
		for (size_t j = 0; j < MAX; j++){
			for (size_t k = 0; k < MAX; k++){
				mortonEncode_magicbits(i, j, k);
			}
		}
	}
	morton_magicbits.stop();
	cout << " Magic bits-based method: " << morton_magicbits.getTotalTimeMs() << " ms" << endl;

	morton_for.reset(); morton_for.start();
	for (size_t i = 0; i < MAX; i++){
		for (size_t j = 0; j < MAX; j++){
			for (size_t k = 0; k < MAX; k++){
				mortonEncode_for(i, j, k);
			}
		}
	}
	morton_for.stop();
	cout << " For-loop method: " << morton_for.getTotalTimeMs() << " ms" << endl;
}

#pragma optimize( "", off ) // don't optimize this, we're measuring performance here
void encodePerformanceTestRandom(){
	cout << "++ Encoding " << MAX << "^3 morton codes in RANDOM order (" << total << " in total)" << endl;

	// generate random coordinates in double array (because we're fancy like that)
	cout << " Generating random coordinates ... ";
	int **arr = (int **)malloc(total * sizeof(int *));
	for (int i = 0; i < total; i++){ arr[i] = (int *)malloc(3 * sizeof(int));}
	for (size_t i = 0; i < total; i++){ arr[i][0] = rand() % MAX; arr[i][1] = rand() % MAX; arr[i][2] = rand() % MAX;}
	cout << " done." << endl;

	// init timers
	Timer morton_LUT, morton_magicbits, morton_for;

	// Start testing performance
	morton_LUT.reset(); morton_LUT.start();
	for (size_t i = 0; i < total; i++){mortonEncode_LUT(arr[i][0], arr[i][1], arr[i][2]);}
	morton_LUT.stop();
	cout << " LUT-based method: " << morton_LUT.getTotalTimeMs() << " ms" << endl;

	morton_magicbits.reset(); morton_magicbits.start();
	for (size_t i = 0; i < total; i++){mortonEncode_magicbits(arr[i][0], arr[i][1], arr[i][2]);}
	morton_magicbits.stop();
	cout << " Magic bits-based method: " << morton_magicbits.getTotalTimeMs() << " ms" << endl;

	morton_for.reset(); morton_for.start();
	for (size_t i = 0; i < total; i++){ mortonEncode_for(arr[i][0], arr[i][1], arr[i][2]);}
	morton_for.stop();
	cout << " For-loop method: " << morton_for.getTotalTimeMs() << " ms" << endl;

	// Get rid of memory
	for (int i = 0; i < total; i++){free(arr[i]);}
	free(arr);
}

#pragma optimize( "", off ) // don't optimize this, we're measuring performance here
void decodePerformanceTestLinear(){
	cout << "++ Decoding " << MAX << "^3 morton codes in LINEAR order (" << total << " in total)" << endl;
	Timer morton_decode_magicbits, morton_decode_for;
	morton_decode_magicbits.reset(); morton_decode_magicbits.start();
	for (size_t i = 0; i < total; i++){
		mortonDecode_magicbits_X(i);
		mortonDecode_magicbits_Y(i);
		mortonDecode_magicbits_Z(i);
	}
	morton_decode_magicbits.stop();
	cout << " Magicbits method: " << morton_decode_magicbits.getTotalTimeMs() << " ms" << endl;

	morton_decode_for.reset(); morton_decode_for.start();
	for (size_t i = 0; i < total; i++){
		unsigned int x, y, z = 0;
		mortonDecode_for(i, x, y, z);
	}
	morton_decode_for.stop();
	cout << " For-loop method: " << morton_decode_for.getTotalTimeMs() << " ms" << endl;
}

int main(int argc, char *argv[]) {
	checkEncodeCorrectness();
	encodePerformanceTestLinear();
	encodePerformanceTestRandom();
	decodePerformanceTestLinear();
}
<commit_msg>Removed some global vars, added comment header<commit_after>// Libmorton Tests
// This is a program designed to test and benchmark the functionality offered by the libmorton library
//
// Jeroen Baert 2015

// Utility headers
#include "util.h"
#include "libmorton_test.h"
// Standard headers
#include <iostream>
#include <iomanip>
#include <inttypes.h>

// Configuration
// MAX x MAX x MAX coordinates will be tested / generated
#define MAX 16
const size_t total = MAX*MAX*MAX; // We need this a lot.

using namespace std;

void checkDecodeCorrectness(){
	printf("++ Checking correctness of decoding methods ... ");
}

void checkEncodeCorrectness(){
	printf("++ Checking correctness of encoding methods ... ");
	int failures = 0;
	for (size_t i = 0; i < 16; i++){
		for (size_t j = 0; j < 16; j++){
			for (size_t k = 0; k < 16; k++){
				// correct code
				uint64_t correct_code = control_morton[k + (j * 16) + (i * 16 * 16)];
				// result all our encoding methods give
				uint64_t lut_result = mortonEncode_LUT(i, j, k);
				uint64_t magicbits_result = mortonEncode_magicbits(i, j, k);
				uint64_t for_result = mortonEncode_for(i, j, k);
				// error messages if any code does not match correct result.
				if (lut_result != correct_code){printf(" Problem with correctness of LUT based method: %zu does not match %zu \n", lut_result, correct_code); failures++;}
				if (magicbits_result != correct_code){printf(" Problem with correctness of Magicbits based method: %zu does not match %zu \n", magicbits_result, correct_code); failures++;}
				if (for_result != correct_code){printf(" Problem with correctness of Magicbits based method: %zu does not match %zu \n", for_result, correct_code); failures++;}
			}
		}
	}
	if (failures != 0){printf("Correctness test failed \n");} else {printf("Passed. \n");}
}

// Test performance of encoding methods for a linear stream of coordinates
#pragma optimize( "", off ) // don't optimize this, we're measuring performance here
void encodePerformanceTestLinear(){
	cout << "++ Encoding " << MAX << "^3 morton codes in LINEAR order (" << total << " in total)" << endl;

	Timer morton_LUT, morton_magicbits, morton_for;
	morton_LUT.reset(); morton_LUT.start();
	for (size_t i = 0; i < MAX; i++){
		for (size_t j = 0; j < MAX; j++){
			for (size_t k = 0; k < MAX; k++){
				mortonEncode_LUT(i, j, k);
			}
		}
	}
	morton_LUT.stop();
	cout << " LUT-based method: " << morton_LUT.getTotalTimeMs() << " ms" << endl;

	morton_magicbits.reset(); morton_magicbits.start();
	for (size_t i = 0; i < MAX; i++){
		for (size_t j = 0; j < MAX; j++){
			for (size_t k = 0; k < MAX; k++){
				mortonEncode_magicbits(i, j, k);
			}
		}
	}
	morton_magicbits.stop();
	cout << " Magic bits-based method: " << morton_magicbits.getTotalTimeMs() << " ms" << endl;

	morton_for.reset(); morton_for.start();
	for (size_t i = 0; i < MAX; i++){
		for (size_t j = 0; j < MAX; j++){
			for (size_t k = 0; k < MAX; k++){
				mortonEncode_for(i, j, k);
			}
		}
	}
	morton_for.stop();
	cout << " For-loop method: " << morton_for.getTotalTimeMs() << " ms" << endl;
}

// Test performance of encoding methods for a random stream of coordinates
#pragma optimize( "", off ) // don't optimize this, we're measuring performance here
void encodePerformanceTestRandom(){
	cout << "++ Encoding " << MAX << "^3 morton codes in RANDOM order (" << total << " in total)" << endl;

	// generate random coordinates in double array (because we're fancy like that)
	cout << " Generating random coordinates ... ";
	int **arr = (int **)malloc(total * sizeof(int *));
	for (int i = 0; i < total; i++){ arr[i] = (int *)malloc(3 * sizeof(int));}
	for (size_t i = 0; i < total; i++){ arr[i][0] = rand() % MAX; arr[i][1] = rand() % MAX; arr[i][2] = rand() % MAX;}
	cout << " done." << endl;

	// init timers
	Timer morton_LUT, morton_magicbits, morton_for;

	// Start testing performance
	morton_LUT.reset(); morton_LUT.start();
	for (size_t i = 0; i < total; i++){mortonEncode_LUT(arr[i][0], arr[i][1], arr[i][2]);}
	morton_LUT.stop();
	cout << " LUT-based method: " << morton_LUT.getTotalTimeMs() << " ms" << endl;

	morton_magicbits.reset(); morton_magicbits.start();
	for (size_t i = 0; i < total; i++){mortonEncode_magicbits(arr[i][0], arr[i][1], arr[i][2]);}
	morton_magicbits.stop();
	cout << " Magic bits-based method: " << morton_magicbits.getTotalTimeMs() << " ms" << endl;

	morton_for.reset(); morton_for.start();
	for (size_t i = 0; i < total; i++){ mortonEncode_for(arr[i][0], arr[i][1], arr[i][2]);}
	morton_for.stop();
	cout << " For-loop method: " << morton_for.getTotalTimeMs() << " ms" << endl;

	// Get rid of memory
	for (int i = 0; i < total; i++){free(arr[i]);}
	free(arr);
}

#pragma optimize( "", off ) // don't optimize this, we're measuring performance here
void decodePerformanceTestLinear(){
	cout << "++ Decoding " << MAX << "^3 morton codes in LINEAR order (" << total << " in total)" << endl;
	Timer morton_decode_magicbits, morton_decode_for;
	morton_decode_magicbits.reset(); morton_decode_magicbits.start();
	for (size_t i = 0; i < total; i++){
		mortonDecode_magicbits_X(i);
		mortonDecode_magicbits_Y(i);
		mortonDecode_magicbits_Z(i);
	}
	morton_decode_magicbits.stop();
	cout << " Magicbits method: " << morton_decode_magicbits.getTotalTimeMs() << " ms" << endl;

	morton_decode_for.reset(); morton_decode_for.start();
	for (size_t i = 0; i < total; i++){
		unsigned int x, y, z = 0;
		mortonDecode_for(i, x, y, z);
	}
	morton_decode_for.stop();
	cout << " For-loop method: " << morton_decode_for.getTotalTimeMs() << " ms" << endl;
}

int main(int argc, char *argv[]) {
	checkEncodeCorrectness();
	encodePerformanceTestLinear();
	encodePerformanceTestRandom();
	decodePerformanceTestLinear();
}
<|endoftext|>