<commit_before>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2018 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_SYSTEM_PROCESS_HPP
#define CATS_CORECAT_SYSTEM_PROCESS_HPP

#include "OS.hpp"
#include "../Data/Array.hpp"
#include "../Text/String.hpp"
#include "../Util/Exception.hpp"

#if defined(CORECAT_OS_WINDOWS)
#   include "../Win32/Handle.hpp"
#elif defined(CORECAT_OS_LINUX) || defined(CORECAT_OS_MACOS)
#   include <unistd.h>
#   include <sys/ioctl.h>
#   include <sys/wait.h>
#   if defined(CORECAT_OS_MACOS)
#       include <crt_externs.h>
#       define environ (*_NSGetEnviron())
#   endif
#else
#   error Unknown OS
#endif

namespace Cats {
namespace Corecat {
inline namespace System {

struct ProcessOption {

    const char* file = nullptr;
    const char* const* argument = nullptr;
    const char* const* environment = nullptr;
    const char* directory = nullptr;

    ProcessOption(const char* file_, const char* const* argument_ = nullptr, const char* const* environment_ = nullptr, const char* directory_ = nullptr) :
        file(file_), argument(argument_), environment(environment_), directory(directory_) {}

};

class Process {

private:

    template <typename T>
    static Array<T> toNullTerminated(ArrayView<const T> arr) {

        Array<T> ret(arr.getSize() + 1);
        std::copy(arr.begin(), arr.end(), ret.begin());
        ret[arr.getSize()] = T();
        return ret;

    }

#if defined(CORECAT_OS_WINDOWS)
private:

    static WString getProcessDirectory() {

        WString path;
        path.setLength(MAX_PATH);
        while(true) {

            DWORD length = ::GetModuleFileNameW(nullptr, path.getData(), DWORD(path.getLength() + 1));
            if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

                path.setLength(path.getLength() * 2);
                continue;

            }
            if(!length)
                throw SystemException("::GetModuleFileNameW failed");
            while(length && path[length - 1] != '/' && path[length - 1] != '\\') --length;
            if(length) --length;
            path.setLength(length);
            return path;

        }

    }
    static WString getCurrentDirectory() {

        WString path;
        DWORD length = ::GetCurrentDirectoryW(0, nullptr);
        if(!length) return {};
        path.setLength(length - 1);
        ::GetCurrentDirectoryW(length, path.getData());
        return path;

    }
    static WString getSystemDirectory() {

        WString path;
        UINT length = ::GetSystemDirectoryW(nullptr, 0);
        if(!length) return {};
        path.setLength(length - 1);
        ::GetSystemDirectoryW(path.getData(), length);
        return path;

    }
    static WString getWindowsDirectory() {

        WString path;
        UINT length = ::GetWindowsDirectoryW(nullptr, 0);
        if(!length) return {};
        path.setLength(length - 1);
        ::GetWindowsDirectoryW(path.getData(), length);
        return path;

    }
    static WString getEnvironmentPath() {

        WString path;
        DWORD length = ::GetEnvironmentVariableW(L"PATH", nullptr, 0);
        if(!length) return {};
        path.setLength(length - 1);
        ::GetEnvironmentVariableW(L"PATH", path.getData(), length);
        return path;

    }

    static bool isExist(const WString& path) {

        DWORD attribute = ::GetFileAttributesW(path.getData());
        return attribute != INVALID_FILE_ATTRIBUTES && !(attribute & FILE_ATTRIBUTE_DIRECTORY);

    }

    static WString enumPath(const WString& file, const Array<WString>& pathList) {

        for(auto&& x : pathList) {

            auto path = x + L'\\' + file;
            if(isExist(path)) return path;

        }
        return {};

    }

    static WString enumExtension(const WString& file, const Array<WString>& pathList) {

        WString path;
        path = enumPath(file, pathList);
        if(!path.isEmpty()) return path;
        path = enumPath(file + L".com", pathList);
        if(!path.isEmpty()) return path;
        path = enumPath(file + L".exe", pathList);
        if(!path.isEmpty()) return path;
        throw SystemException("File not found");

    }
#endif

private:
#if defined(CORECAT_OS_WINDOWS)
    Handle handle;
#else
    pid_t pid;
#endif

public:

    Process(const ProcessOption& option) {
#if defined(CORECAT_OS_WINDOWS)
        Array<WString> pathList;
        pathList.push(getProcessDirectory());
        pathList.push(getCurrentDirectory());
        pathList.push(getSystemDirectory());
        pathList.push(getWindowsDirectory());
        // TODO: PATH
        auto path = enumExtension(WString(option.file), pathList);

        WString argument;
        if(option.argument) {

            for(auto p = option.argument; *p; ++p) {

                if(!argument.isEmpty()) argument += L' ';
                WString src(*p);
                WString dst;
                bool quote = false;
                for(std::size_t i = src.getLength() - 1; i != std::size_t(-1); --i) {

                    auto c = src[i];
                    dst += c;
                    if(quote && c == L'\\') dst += L'\\';
                    else if(c == L'\"') quote = true, dst += L'\\';
                    else quote = false;

                }
                argument += L'"' + dst.reverse() + L'"';

            }

        }

        WString environment;
        if(option.environment) {

            for(auto p = option.environment; *p; ++p) {

                environment += WString(*p);
                environment += wchar_t();

            }

        }

        STARTUPINFOW si = {};
        si.cb = sizeof(si);
        si.wShowWindow = SW_SHOWDEFAULT;
        PROCESS_INFORMATION pi = {};
        if(!::CreateProcessW(
            path.getData(),
            option.argument ? argument.getData() : nullptr,
            nullptr,
            nullptr,
            true,
            CREATE_UNICODE_ENVIRONMENT,
            option.environment ? environment.getData() : nullptr,
            option.directory ? WString(option.directory).getData() : nullptr,
            &si,
            &pi))
            throw SystemException("::CreateProcessW failed");
        ::CloseHandle(pi.hThread);
        handle = pi.hProcess;
#else
        int messagePipe[2];
        if(::pipe(messagePipe))
            throw SystemException("::pipe failed");

        int ret;
        do
            ret = ::ioctl(messagePipe[1], FIOCLEX);
        while(ret < 0 && errno == EINTR);
        if(ret) {

            ::close(messagePipe[0]);
            ::close(messagePipe[1]);
            throw SystemException("::ioctl failed");

        }

        pid = ::fork();
        if(pid < 0) {

            ::close(messagePipe[0]);
            ::close(messagePipe[1]);
            throw SystemException("::fork failed");

        }

        if(pid > 0) {

            // Parent process
            ::close(messagePipe[1]);

            ssize_t n;
            char data;
            do
                n = ::read(messagePipe[0], &data, 1);
            while(n < 0 && errno == EINTR);

            ::close(messagePipe[0]);
            if(n) {

                do
                    ret = ::waitpid(pid, nullptr, 0);
                while(ret < 0 && errno == EINTR);
                throw SystemException("Failed to create process");

            }

        } else {

            // Child process
            ::close(messagePipe[0]);
            do {

                if(option.environment) environ = const_cast<char**>(option.environment);
                if(option.directory && ::chdir(option.directory))
                    break;
                ::execvp(option.file, const_cast<char* const*>(option.argument));

            } while(false);

            // Failed
            ssize_t n;
            char data = 0;
            do
                n = ::write(messagePipe[1], &data, 1);
            while(n < 0 && errno == EINTR);
            ::_exit(127);

        }
#endif
    }
    Process(const char* file, const char* const* argument = nullptr, const char* const* environment = nullptr, const char* directory = nullptr) :
        Process(ProcessOption(file, argument, environment, directory)) {}
    Process(const char* file, const char* directory) :
        Process(file, nullptr, nullptr, directory) {}
    Process(const char* file, ArrayView<const char* const> argument, const char* directory = nullptr) :
        Process(file, toNullTerminated(argument).getData(), nullptr, directory) {}
    Process(const char* file, ArrayView<const char* const> argument, ArrayView<const char* const> environment, const char* directory = nullptr) :
        Process(file, toNullTerminated(argument).getData(), toNullTerminated(environment).getData(), directory) {}
    Process(const Process& src) = delete;
    ~Process() = default;

    Process& operator =(const Process& src) = delete;

    std::int64_t wait() {
#if defined(CORECAT_OS_WINDOWS)
        if(::WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0)
            throw SystemException("::WaitForSingleObject failed");
        DWORD ret;
        if(!::GetExitCodeProcess(handle, &ret))
            throw SystemException("::GetExitCodeProcess failed");
        handle.close();
        return ret;
#else
        int ret, code;
        do
            ret = ::waitpid(pid, &code, 0);
        while(ret < 0 && errno == EINTR);
        if(ret < 0)
            throw SystemException("::waitpid failed");
        pid = 0;
        return code;
#endif
    }

};

}
}
}

#endif
<commit_msg>Update Process<commit_after>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2018 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_SYSTEM_PROCESS_HPP
#define CATS_CORECAT_SYSTEM_PROCESS_HPP

#include "OS.hpp"
#include "../Data/Array.hpp"
#include "../Text/String.hpp"
#include "../Util/Exception.hpp"

#if defined(CORECAT_OS_WINDOWS)
#   include "../Win32/Handle.hpp"
#elif defined(CORECAT_OS_LINUX) || defined(CORECAT_OS_MACOS)
#   include <unistd.h>
#   include <sys/ioctl.h>
#   include <sys/wait.h>
#   if defined(CORECAT_OS_MACOS)
#       include <crt_externs.h>
#       define environ (*_NSGetEnviron())
#   endif
#else
#   error Unknown OS
#endif

namespace Cats {
namespace Corecat {
inline namespace System {

struct ProcessOption {

    const char* file = nullptr;
    const char* const* argument = nullptr;
    const char* const* environment = nullptr;
    const char* directory = nullptr;

    ProcessOption(const char* file_, const char* const* argument_ = nullptr, const char* const* environment_ = nullptr, const char* directory_ = nullptr) :
        file(file_), argument(argument_), environment(environment_), directory(directory_) {}

};

class Process {

private:

    template <typename T>
    static Array<T> toNullTerminated(ArrayView<const T> arr) {

        Array<T> ret(arr.getSize() + 1);
        std::copy(arr.begin(), arr.end(), ret.begin());
        ret[arr.getSize()] = T();
        return ret;

    }

#if defined(CORECAT_OS_WINDOWS)
private:

    static WString getProcessDirectory() {

        WString path;
        path.setLength(MAX_PATH);
        while(true) {

            DWORD length = ::GetModuleFileNameW(nullptr, path.getData(), DWORD(path.getLength() + 1));
            if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

                path.setLength(path.getLength() * 2);
                continue;

            }
            if(!length)
                throw SystemException("::GetModuleFileNameW failed");
            while(length && path[length - 1] != '/' && path[length - 1] != '\\') --length;
            if(length) --length;
            path.setLength(length);
            return path;

        }

    }
    static WString getCurrentDirectory() {

        WString path;
        DWORD length = ::GetCurrentDirectoryW(0, nullptr);
        if(!length) return {};
        path.setLength(length - 1);
        ::GetCurrentDirectoryW(length, path.getData());
        return path;

    }
    static WString getSystemDirectory() {

        WString path;
        UINT length = ::GetSystemDirectoryW(nullptr, 0);
        if(!length) return {};
        path.setLength(length - 1);
        ::GetSystemDirectoryW(path.getData(), length);
        return path;

    }
    static WString getWindowsDirectory() {

        WString path;
        UINT length = ::GetWindowsDirectoryW(nullptr, 0);
        if(!length) return {};
        path.setLength(length - 1);
        ::GetWindowsDirectoryW(path.getData(), length);
        return path;

    }
    static WString getEnvironmentPath() {

        WString path;
        DWORD length = ::GetEnvironmentVariableW(L"PATH", nullptr, 0);
        if(!length) return {};
        path.setLength(length - 1);
        ::GetEnvironmentVariableW(L"PATH", path.getData(), length);
        return path;

    }
    static const char* findPath(const char* const* environment) {

        for(auto p = environment; *p; ++p) {

            auto str = *p;
            if((str[0] == 'P' || str[0] == 'p') && (str[1] == 'A' || str[1] == 'a')
                && (str[2] == 'T' || str[2] == 't') && (str[3] == 'H' || str[3] == 'h') && str[4] == '=')
                return str + 5;

        }
        return nullptr;

    }

    static bool isExist(const WString& path) {

        DWORD attribute = ::GetFileAttributesW(path.getData());
        return attribute != INVALID_FILE_ATTRIBUTES && !(attribute & FILE_ATTRIBUTE_DIRECTORY);

    }

    static WString enumPath(const WString& file, const Array<WString>& pathList) {

        for(auto&& x : pathList) {

            auto path = x + L'\\' + file;
            if(isExist(path)) return path;

        }
        return {};

    }

    static WString enumExtension(const WString& file, const Array<WString>& pathList) {

        WString path;
        path = enumPath(file, pathList);
        if(!path.isEmpty()) return path;
        path = enumPath(file + L".com", pathList);
        if(!path.isEmpty()) return path;
        path = enumPath(file + L".exe", pathList);
        if(!path.isEmpty()) return path;
        throw SystemException("File not found");

    }
#endif

private:
#if defined(CORECAT_OS_WINDOWS)
    Handle handle;
#else
    pid_t pid;
#endif

public:

    Process(const ProcessOption& option) {
#if defined(CORECAT_OS_WINDOWS)
        Array<WString> pathList;
        pathList.push(getProcessDirectory());
        pathList.push(getCurrentDirectory());
        pathList.push(getSystemDirectory());
        pathList.push(getWindowsDirectory());
        // TODO: PATH
        auto path = enumExtension(WString(option.file), pathList);

        WString argument;
        if(option.argument) {

            for(auto p = option.argument; *p; ++p) {

                if(!argument.isEmpty()) argument += L' ';
                WString src(*p);
                WString dst;
                bool quote = false;
                for(std::size_t i = src.getLength() - 1; i != std::size_t(-1); --i) {

                    auto c = src[i];
                    dst += c;
                    if(quote && c == L'\\') dst += L'\\';
                    else if(c == L'\"') quote = true, dst += L'\\';
                    else quote = false;

                }
                argument += L'"' + dst.reverse() + L'"';

            }

        }

        WString environment;
        if(option.environment) {

            for(auto p = option.environment; *p; ++p) {

                environment += WString(*p);
                environment += wchar_t();

            }

        }

        STARTUPINFOW si = {};
        si.cb = sizeof(si);
        si.wShowWindow = SW_SHOWDEFAULT;
        PROCESS_INFORMATION pi = {};
        if(!::CreateProcessW(
            path.getData(),
            option.argument ? argument.getData() : nullptr,
            nullptr,
            nullptr,
            true,
            CREATE_UNICODE_ENVIRONMENT,
            option.environment ? environment.getData() : nullptr,
            option.directory ? WString(option.directory).getData() : nullptr,
            &si,
            &pi))
            throw SystemException("::CreateProcessW failed");
        ::CloseHandle(pi.hThread);
        handle = pi.hProcess;
#else
        int messagePipe[2];
        if(::pipe(messagePipe))
            throw SystemException("::pipe failed");

        int ret;
        do
            ret = ::ioctl(messagePipe[1], FIOCLEX);
        while(ret < 0 && errno == EINTR);
        if(ret) {

            ::close(messagePipe[0]);
            ::close(messagePipe[1]);
            throw SystemException("::ioctl failed");

        }

        pid = ::fork();
        if(pid < 0) {

            ::close(messagePipe[0]);
            ::close(messagePipe[1]);
            throw SystemException("::fork failed");

        }

        if(pid > 0) {

            // Parent process
            ::close(messagePipe[1]);

            ssize_t n;
            char data;
            do
                n = ::read(messagePipe[0], &data, 1);
            while(n < 0 && errno == EINTR);

            ::close(messagePipe[0]);
            if(n) {

                do
                    ret = ::waitpid(pid, nullptr, 0);
                while(ret < 0 && errno == EINTR);
                throw SystemException("Failed to create process");

            }

        } else {

            // Child process
            ::close(messagePipe[0]);
            do {

                if(option.environment) environ = const_cast<char**>(option.environment);
                if(option.directory && ::chdir(option.directory))
                    break;
                ::execvp(option.file, const_cast<char* const*>(option.argument));

            } while(false);

            // Failed
            ssize_t n;
            char data = 0;
            do
                n = ::write(messagePipe[1], &data, 1);
            while(n < 0 && errno == EINTR);
            ::_exit(127);

        }
#endif
    }
    Process(const char* file, const char* const* argument = nullptr, const char* const* environment = nullptr, const char* directory = nullptr) :
        Process(ProcessOption(file, argument, environment, directory)) {}
    Process(const char* file, const char* directory) :
        Process(file, nullptr, nullptr, directory) {}
    Process(const char* file, ArrayView<const char* const> argument, const char* directory = nullptr) :
        Process(file, toNullTerminated(argument).getData(), nullptr, directory) {}
    Process(const char* file, ArrayView<const char* const> argument, ArrayView<const char* const> environment, const char* directory = nullptr) :
        Process(file, toNullTerminated(argument).getData(), toNullTerminated(environment).getData(), directory) {}
    Process(const Process& src) = delete;
    ~Process() = default;

    Process& operator =(const Process& src) = delete;

    std::int64_t wait() {
#if defined(CORECAT_OS_WINDOWS)
        if(::WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0)
            throw SystemException("::WaitForSingleObject failed");
        DWORD ret;
        if(!::GetExitCodeProcess(handle, &ret))
            throw SystemException("::GetExitCodeProcess failed");
        handle.close();
        return ret;
#else
        int ret, code;
        do
            ret = ::waitpid(pid, &code, 0);
        while(ret < 0 && errno == EINTR);
        if(ret < 0)
            throw SystemException("::waitpid failed");
        pid = 0;
        return code;
#endif
    }

};

}
}
}

#endif
<|endoftext|>


<commit_before>#ifndef INCLUDE_AL_MAINLOOP_HPP
#define INCLUDE_AL_MAINLOOP_HPP

/*
	Copyright (C) 2006-2008. The Regents of the University of California (REGENTS).
	All Rights Reserved.

	Permission to use, copy, modify, distribute, and distribute modified versions
	of this software and its documentation without fee and without a signed
	licensing agreement, is hereby granted, provided that the above copyright
	notice, the list of contributors, this paragraph and the following two paragraphs
	appear in all copies, modifications, and distributions.

	IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
	SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
	OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
	BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
	HEREUNDER IS PROVIDED "AS IS". REGENTS HAS  NO OBLIGATION TO PROVIDE
	MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/

#include "allocore/system/al_Config.h"
#include "allocore/system/al_Time.h"
#include "allocore/system/al_MainLoop.h"
#include "allocore/types/al_MsgQueue.hpp"

namespace al {

/// Typically a single instance in the main thread
class MainLoop {
public:

	/// mainloop is a singleton; this is how to access it:
	static MainLoop& get();

	/// takes over control of the current thread
	static void start();

	/// releases control of the current thread
	/// in some implementations, may exit the application
	static void stop();

	/// current scheduler (logical) time
	/// (seconds since MainLoop::start())
	static al_sec now() { return get().mQueue.now(); }

	/// real time
	/// (seconds since MainLoop::start())
	static al_sec realtime() { return al_time() - get().mT0; }

	/// use this to schedule timed functions in this mainloop
	/// (the mainloop itself will take care of updating this queue)
	static MsgQueue& queue() { return get().mQueue; }

	/// set tick period. actual behavior is implementation dependent
	static void interval(al_sec interval);
	static al_sec interval() { return get().mInterval; }

	/// Get actual interval between ticks
	static al_sec intervalActual() { return get().mActualInterval; }

	/// performance monitoring:
	/*
		Measures relationship between ideal tick interval (mInterval),
			and the actual duration between ticks.
		Thus, it measures cost of both mQueue.update(),
			plus every other activity in this thread between successive ticks
		Depending on the implementation, setting the interval to small values
			will report a very high CPU measurement
	*/
	static double cpu() { return get().mCPU; }

	///< al_time() when mainloop was created
	static al_sec T0() { return get().mT0; }

	/// trigger a mainloop step (typically for implementation use only)
	void tick();

protected:
	friend class MainLoopImpl;
	class MainLoopImpl * mImpl;

	al_sec mInterval, mActualInterval;
	al_sec mT0;						/* birth time (wall clock), scheduler time (logical) */
	al_sec mLastTickTime;			/* used to measure performance */
	al_sec mCPU;					/* running average performance monitor: this thread */
	MsgQueue mQueue;				// functor scheduler attached to the main loop
	bool mIsRunning;				/* flag true (1) when in the main loop */

	MainLoop();
	virtual ~MainLoop();
};

} // al::

#endif /* include guard */
<commit_msg>MainLoop: added getter isRunning<commit_after>#ifndef INCLUDE_AL_MAINLOOP_HPP
#define INCLUDE_AL_MAINLOOP_HPP

/*
	Copyright (C) 2006-2008. The Regents of the University of California (REGENTS).
	All Rights Reserved.

	Permission to use, copy, modify, distribute, and distribute modified versions
	of this software and its documentation without fee and without a signed
	licensing agreement, is hereby granted, provided that the above copyright
	notice, the list of contributors, this paragraph and the following two paragraphs
	appear in all copies, modifications, and distributions.

	IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
	SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
	OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
	BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
	HEREUNDER IS PROVIDED "AS IS". REGENTS HAS  NO OBLIGATION TO PROVIDE
	MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/

#include "allocore/system/al_Config.h"
#include "allocore/system/al_Time.h"
#include "allocore/system/al_MainLoop.h"
#include "allocore/types/al_MsgQueue.hpp"

namespace al {

/// Typically a single instance in the main thread
class MainLoop {
public:

	/// mainloop is a singleton; this is how to access it:
	static MainLoop& get();

	/// takes over control of the current thread
	static void start();

	/// releases control of the current thread
	/// in some implementations, may exit the application
	static void stop();

	/// current scheduler (logical) time
	/// (seconds since MainLoop::start())
	static al_sec now() { return get().mQueue.now(); }

	/// real time
	/// (seconds since MainLoop::start())
	static al_sec realtime() { return al_time() - get().mT0; }

	/// use this to schedule timed functions in this mainloop
	/// (the mainloop itself will take care of updating this queue)
	static MsgQueue& queue() { return get().mQueue; }

	/// set tick period. actual behavior is implementation dependent
	static void interval(al_sec interval);
	static al_sec interval() { return get().mInterval; }

	/// Get actual interval between ticks
	static al_sec intervalActual() { return get().mActualInterval; }

	/// performance monitoring:
	/*
		Measures relationship between ideal tick interval (mInterval),
			and the actual duration between ticks.
		Thus, it measures cost of both mQueue.update(),
			plus every other activity in this thread between successive ticks
		Depending on the implementation, setting the interval to small values
			will report a very high CPU measurement
	*/
	static double cpu() { return get().mCPU; }

	/// Returns time when main loop was created
	static al_sec T0() { return get().mT0; }

	/// Returns whether main loop has been started
	static bool isRunning(){ return get().mIsRunning; }

	/// trigger a mainloop step (typically for implementation use only)
	void tick();

protected:
	friend class MainLoopImpl;
	class MainLoopImpl * mImpl;

	al_sec mInterval, mActualInterval;
	al_sec mT0;						/* birth time (wall clock), scheduler time (logical) */
	al_sec mLastTickTime;			/* used to measure performance */
	al_sec mCPU;					/* running average performance monitor: this thread */
	MsgQueue mQueue;				// functor scheduler attached to the main loop
	bool mIsRunning;				/* flag true (1) when in the main loop */

	MainLoop();
	virtual ~MainLoop();
};

} // al::

#endif /* include guard */
<|endoftext|>


<commit_before>// Copyright (C) 2009-2016 National ICT Australia (NICTA)
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// -------------------------------------------------------------------
//
// Written by Conrad Sanderson - http://conradsanderson.id.au

//! \addtogroup arma_version
//! @{

#define ARMA_VERSION_MAJOR 7
#define ARMA_VERSION_MINOR 600
#define ARMA_VERSION_PATCH 2
#define ARMA_VERSION_NAME  "Coup d'Etat Deluxe"

struct arma_version
  {
  static const unsigned int major = ARMA_VERSION_MAJOR;
  static const unsigned int minor = ARMA_VERSION_MINOR;
  static const unsigned int patch = ARMA_VERSION_PATCH;

  static
  inline
  std::string
  as_string()
    {
    const char* nickname = ARMA_VERSION_NAME;

    std::stringstream ss;
    ss << arma_version::major
       << '.'
       << arma_version::minor
       << '.'
       << arma_version::patch
       << " ("
       << nickname
       << ')';

    return ss.str();
    }
  };

//! @}
<commit_msg>bump the patch level due to the hdf5 related commit<commit_after>// Copyright (C) 2009-2016 National ICT Australia (NICTA)
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// -------------------------------------------------------------------
//
// Written by Conrad Sanderson - http://conradsanderson.id.au

//! \addtogroup arma_version
//! @{

#define ARMA_VERSION_MAJOR 7
#define ARMA_VERSION_MINOR 600
#define ARMA_VERSION_PATCH 3
#define ARMA_VERSION_NAME  "Coup d'Etat Deluxe"

struct arma_version
  {
  static const unsigned int major = ARMA_VERSION_MAJOR;
  static const unsigned int minor = ARMA_VERSION_MINOR;
  static const unsigned int patch = ARMA_VERSION_PATCH;

  static
  inline
  std::string
  as_string()
    {
    const char* nickname = ARMA_VERSION_NAME;

    std::stringstream ss;
    ss << arma_version::major
       << '.'
       << arma_version::minor
       << '.'
       << arma_version::patch
       << " ("
       << nickname
       << ')';

    return ss.str();
    }
  };

//! @}
<|endoftext|>


<commit_before>//===-- sanitizer_printf_test.cc ------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Tests for sanitizer_printf.cc
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "gtest/gtest.h"

#include <string.h>
#include <limits.h>

namespace __sanitizer {

TEST(Printf, Basic) {
  char buf[1024];
  uptr len = internal_snprintf(buf, sizeof(buf),
      "a%db%zdc%ue%zuf%xh%zxq%pe%sr",
      (int)-1, (long)-2, // NOLINT
      (unsigned)-4, (unsigned long)5, // NOLINT
      (unsigned)10, (unsigned long)11, // NOLINT
      (void*)0x123, "_string_");
  EXPECT_EQ(len, strlen(buf));
  EXPECT_STREQ("a-1b-2c4294967292e5fahbq"
               "0x000000000123e_string_r", buf);
}

TEST(Printf, OverflowStr) {
  char buf[] = "123456789";
  uptr len = internal_snprintf(buf, 4, "%s", "abcdef");  // NOLINT
  EXPECT_EQ(len, (uptr)6);
  EXPECT_STREQ("abc", buf);
  EXPECT_EQ(buf[3], 0);
  EXPECT_EQ(buf[4], '5');
  EXPECT_EQ(buf[5], '6');
  EXPECT_EQ(buf[6], '7');
  EXPECT_EQ(buf[7], '8');
  EXPECT_EQ(buf[8], '9');
  EXPECT_EQ(buf[9], 0);
}

TEST(Printf, OverflowInt) {
  char buf[] = "123456789";
  internal_snprintf(buf, 4, "%d", -123456789);  // NOLINT
  EXPECT_STREQ("-12", buf);
  EXPECT_EQ(buf[3], 0);
  EXPECT_EQ(buf[4], '5');
  EXPECT_EQ(buf[5], '6');
  EXPECT_EQ(buf[6], '7');
  EXPECT_EQ(buf[7], '8');
  EXPECT_EQ(buf[8], '9');
  EXPECT_EQ(buf[9], 0);
}

TEST(Printf, OverflowUint) {
  char buf[] = "123456789";
  internal_snprintf(buf, 4, "a%zx", (unsigned long)0x123456789);  // NOLINT
  EXPECT_STREQ("a12", buf);
  EXPECT_EQ(buf[3], 0);
  EXPECT_EQ(buf[4], '5');
  EXPECT_EQ(buf[5], '6');
  EXPECT_EQ(buf[6], '7');
  EXPECT_EQ(buf[7], '8');
  EXPECT_EQ(buf[8], '9');
  EXPECT_EQ(buf[9], 0);
}

TEST(Printf, OverflowPtr) {
  char buf[] = "123456789";
  internal_snprintf(buf, 4, "%p", (void*)0x123456789);  // NOLINT
  EXPECT_STREQ("0x0", buf);
  EXPECT_EQ(buf[3], 0);
  EXPECT_EQ(buf[4], '5');
  EXPECT_EQ(buf[5], '6');
  EXPECT_EQ(buf[6], '7');
  EXPECT_EQ(buf[7], '8');
  EXPECT_EQ(buf[8], '9');
  EXPECT_EQ(buf[9], 0);
}

template<typename T>
static void TestMinMax(const char *fmt, T min, T max) {
  char buf[1024];
  uptr len = internal_snprintf(buf, sizeof(buf), fmt, min, max);
  char buf2[1024];
  snprintf(buf2, sizeof(buf2), fmt, min, max);
  EXPECT_EQ(len, strlen(buf));
  EXPECT_STREQ(buf2, buf);
}

TEST(Printf, MinMax) {
  TestMinMax<int>("%d-%d", INT_MIN, INT_MAX);  // NOLINT
  TestMinMax<long>("%zd-%zd", LONG_MIN, LONG_MAX);  // NOLINT
  TestMinMax<unsigned>("%u-%u", 0, UINT_MAX);  // NOLINT
  TestMinMax<unsigned long>("%zu-%zu", 0, ULONG_MAX);  // NOLINT
  TestMinMax<unsigned>("%x-%x", 0, UINT_MAX);  // NOLINT
  TestMinMax<unsigned long>("%zx-%zx", 0, ULONG_MAX);  // NOLINT
}

}  // namespace __sanitizer
<commit_msg>[Sanitizer] fix printf unittest on 32-bit arch<commit_after>//===-- sanitizer_printf_test.cc ------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Tests for sanitizer_printf.cc
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "gtest/gtest.h"

#include <string.h>
#include <limits.h>

namespace __sanitizer {

TEST(Printf, Basic) {
  char buf[1024];
  uptr len = internal_snprintf(buf, sizeof(buf),
      "a%db%zdc%ue%zuf%xh%zxq%pe%sr",
      (int)-1, (long)-2, // NOLINT
      (unsigned)-4, (unsigned long)5, // NOLINT
      (unsigned)10, (unsigned long)11, // NOLINT
      (void*)0x123, "_string_");
  EXPECT_EQ(len, strlen(buf));
  void *ptr;
  if (sizeof(ptr) == 4) {
    EXPECT_STREQ("a-1b-2c4294967292e5fahbq"
                 "0x00000123e_string_r", buf);
  } else {
    EXPECT_STREQ("a-1b-2c4294967292e5fahbq"
                 "0x000000000123e_string_r", buf);
  }
}

TEST(Printf, OverflowStr) {
  char buf[] = "123456789";
  uptr len = internal_snprintf(buf, 4, "%s", "abcdef");  // NOLINT
  EXPECT_EQ(len, (uptr)6);
  EXPECT_STREQ("abc", buf);
  EXPECT_EQ(buf[3], 0);
  EXPECT_EQ(buf[4], '5');
  EXPECT_EQ(buf[5], '6');
  EXPECT_EQ(buf[6], '7');
  EXPECT_EQ(buf[7], '8');
  EXPECT_EQ(buf[8], '9');
  EXPECT_EQ(buf[9], 0);
}

TEST(Printf, OverflowInt) {
  char buf[] = "123456789";
  internal_snprintf(buf, 4, "%d", -123456789);  // NOLINT
  EXPECT_STREQ("-12", buf);
  EXPECT_EQ(buf[3], 0);
  EXPECT_EQ(buf[4], '5');
  EXPECT_EQ(buf[5], '6');
  EXPECT_EQ(buf[6], '7');
  EXPECT_EQ(buf[7], '8');
  EXPECT_EQ(buf[8], '9');
  EXPECT_EQ(buf[9], 0);
}

TEST(Printf, OverflowUint) {
  char buf[] = "123456789";
  uptr val;
  if (sizeof(val) == 4) {
    val = (uptr)0x12345678;
  } else {
    val = (uptr)0x123456789ULL;
  }
  internal_snprintf(buf, 4, "a%zx", val);  // NOLINT
  EXPECT_STREQ("a12", buf);
  EXPECT_EQ(buf[3], 0);
  EXPECT_EQ(buf[4], '5');
  EXPECT_EQ(buf[5], '6');
  EXPECT_EQ(buf[6], '7');
  EXPECT_EQ(buf[7], '8');
  EXPECT_EQ(buf[8], '9');
  EXPECT_EQ(buf[9], 0);
}

TEST(Printf, OverflowPtr) {
  char buf[] = "123456789";
  void *p;
  if (sizeof(p) == 4) {
    p = (void*)0x1234567;
  } else {
    p = (void*)0x123456789ULL;
  }
  internal_snprintf(buf, 4, "%p", p);  // NOLINT
  EXPECT_STREQ("0x0", buf);
  EXPECT_EQ(buf[3], 0);
  EXPECT_EQ(buf[4], '5');
  EXPECT_EQ(buf[5], '6');
  EXPECT_EQ(buf[6], '7');
  EXPECT_EQ(buf[7], '8');
  EXPECT_EQ(buf[8], '9');
  EXPECT_EQ(buf[9], 0);
}

template<typename T>
static void TestMinMax(const char *fmt, T min, T max) {
  char buf[1024];
  uptr len = internal_snprintf(buf, sizeof(buf), fmt, min, max);
  char buf2[1024];
  snprintf(buf2, sizeof(buf2), fmt, min, max);
  EXPECT_EQ(len, strlen(buf));
  EXPECT_STREQ(buf2, buf);
}

TEST(Printf, MinMax) {
  TestMinMax<int>("%d-%d", INT_MIN, INT_MAX);  // NOLINT
  TestMinMax<long>("%zd-%zd", LONG_MIN, LONG_MAX);  // NOLINT
  TestMinMax<unsigned>("%u-%u", 0, UINT_MAX);  // NOLINT
  TestMinMax<unsigned long>("%zu-%zu", 0, ULONG_MAX);  // NOLINT
  TestMinMax<unsigned>("%x-%x", 0, UINT_MAX);  // NOLINT
  TestMinMax<unsigned long>("%zx-%zx", 0, ULONG_MAX);  // NOLINT
}

}  // namespace __sanitizer
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qv4identifiertable_p.h"

QT_BEGIN_NAMESPACE

namespace QV4 {

static const uchar prime_deltas[] = {
    0,  0,  1,  3,  1,  5,  3,  3,  1,  9,  7,  5,  3,  9, 25,  3,
    1, 21,  3, 21,  7, 15,  9,  5,  3, 29, 15,  0,  0,  0,  0,  0
};

static inline int primeForNumBits(int numBits)
{
    return (1 << numBits) + prime_deltas[numBits];
}

IdentifierTable::IdentifierTable(ExecutionEngine *engine)
    : engine(engine)
    , size(0)
    , numBits(8)
{
    alloc = primeForNumBits(numBits);
    entries = (String **)malloc(alloc*sizeof(String *));
    memset(entries, 0, alloc*sizeof(String *));
}

IdentifierTable::~IdentifierTable()
{
    free(entries);
}

void IdentifierTable::addEntry(String *str)
{
    uint hash = str->hashValue();

    if (str->subtype >= String::StringType_UInt)
        return;

    str->identifier = new Identifier;
    str->identifier->string = str->toQString();
    str->identifier->hashValue = hash;

    bool grow = (alloc <= size*2);

    if (grow) {
        ++numBits;
        int newAlloc = primeForNumBits(numBits);
        String **newEntries = (String **)malloc(newAlloc*sizeof(String *));
        memset(newEntries, 0, newAlloc*sizeof(String *));
        for (uint i = 0; i < alloc; ++i) {
            String *e = entries[i];
            if (!e)
                continue;
            uint idx = e->stringHash % newAlloc;
            while (newEntries[idx]) {
                ++idx;
                idx %= newAlloc;
            }
            newEntries[idx] = e;
        }
        free(entries);
        entries = newEntries;
        alloc = newAlloc;
    }

    uint idx = hash % alloc;
    while (entries[idx]) {
        ++idx;
        idx %= alloc;
    }
    entries[idx] = str;
    ++size;
}

String *IdentifierTable::insertString(const QString &s)
{
    uint hash = String::createHashValue(s.constData(), s.length());
    uint idx = hash % alloc;
    while (String *e = entries[idx]) {
        if (e->stringHash == hash && e->toQString() == s)
            return e;
        ++idx;
        idx %= alloc;
    }

    String *str = engine->newString(s);
    addEntry(str);
    return str;
}

Identifier *IdentifierTable::identifier(String *str)
{
    if (str->identifier)
        return str->identifier;
    uint hash = str->hashValue();
    if (str->subtype >= String::StringType_UInt)
        return 0;

    uint idx = hash % alloc;
    while (String *e = entries[idx]) {
        if (e->stringHash == hash && e->isEqualTo(str)) {
            str->identifier = e->identifier;
            return e->identifier;
        }
        ++idx;
        idx %= alloc;
    }

    addEntry(str);
    return str->identifier;
}

Identifier *IdentifierTable::identifier(const QString &s)
{
    return insertString(s)->identifier;
}

Identifier *IdentifierTable::identifier(const char *s, int len)
{
    uint hash = String::createHashValue(s, len);
    if (hash == UINT_MAX)
        return identifier(QString::fromUtf8(s, len));

    QLatin1String latin(s, len);
    uint idx = hash % alloc;
    while (String *e = entries[idx]) {
        if (e->stringHash == hash && e->toQString() == latin)
            return e->identifier;
        ++idx;
        idx %= alloc;
    }

    String *str = engine->newString(QString::fromLatin1(s, len));
    addEntry(str);
    return str->identifier;
}

}

QT_END_NAMESPACE
<commit_msg>We need to allow storing the value of UINT_MAX as an identifier<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qv4identifiertable_p.h"

QT_BEGIN_NAMESPACE

namespace QV4 {

static const uchar prime_deltas[] = {
    0,  0,  1,  3,  1,  5,  3,  3,  1,  9,  7,  5,  3,  9, 25,  3,
    1, 21,  3, 21,  7, 15,  9,  5,  3, 29, 15,  0,  0,  0,  0,  0
};

static inline int primeForNumBits(int numBits)
{
    return (1 << numBits) + prime_deltas[numBits];
}

IdentifierTable::IdentifierTable(ExecutionEngine *engine)
    : engine(engine)
    , size(0)
    , numBits(8)
{
    alloc = primeForNumBits(numBits);
    entries = (String **)malloc(alloc*sizeof(String *));
    memset(entries, 0, alloc*sizeof(String *));
}

IdentifierTable::~IdentifierTable()
{
    free(entries);
}

void IdentifierTable::addEntry(String *str)
{
    uint hash = str->hashValue();

    if (str->subtype == String::StringType_ArrayIndex)
        return;

    str->identifier = new Identifier;
    str->identifier->string = str->toQString();
    str->identifier->hashValue = hash;

    bool grow = (alloc <= size*2);

    if (grow) {
        ++numBits;
        int newAlloc = primeForNumBits(numBits);
        String **newEntries = (String **)malloc(newAlloc*sizeof(String *));
        memset(newEntries, 0, newAlloc*sizeof(String *));
        for (uint i = 0; i < alloc; ++i) {
            String *e = entries[i];
            if (!e)
                continue;
            uint idx = e->stringHash % newAlloc;
            while (newEntries[idx]) {
                ++idx;
                idx %= newAlloc;
            }
            newEntries[idx] = e;
        }
        free(entries);
        entries = newEntries;
        alloc = newAlloc;
    }

    uint idx = hash % alloc;
    while (entries[idx]) {
        ++idx;
        idx %= alloc;
    }
    entries[idx] = str;
    ++size;
}

String *IdentifierTable::insertString(const QString &s)
{
    uint hash = String::createHashValue(s.constData(), s.length());
    uint idx = hash % alloc;
    while (String *e = entries[idx]) {
        if (e->stringHash == hash && e->toQString() == s)
            return e;
        ++idx;
        idx %= alloc;
    }

    String *str = engine->newString(s);
    addEntry(str);
    return str;
}

Identifier *IdentifierTable::identifier(String *str)
{
    if (str->identifier)
        return str->identifier;
    uint hash = str->hashValue();
    if (str->subtype == String::StringType_ArrayIndex)
        return 0;

    uint idx = hash % alloc;
    while (String *e = entries[idx]) {
        if (e->stringHash == hash && e->isEqualTo(str)) {
            str->identifier = e->identifier;
            return e->identifier;
        }
        ++idx;
        idx %= alloc;
    }

    addEntry(str);
    return str->identifier;
}

Identifier *IdentifierTable::identifier(const QString &s)
{
    return insertString(s)->identifier;
}

Identifier *IdentifierTable::identifier(const char *s, int len)
{
    uint hash = String::createHashValue(s, len);
    if (hash == UINT_MAX)
        return identifier(QString::fromUtf8(s, len));

    QLatin1String latin(s, len);
    uint idx = hash % alloc;
    while (String *e = entries[idx]) {
        if (e->stringHash == hash && e->toQString() == latin)
            return e->identifier;
        ++idx;
        idx %= alloc;
    }

    String *str = engine->newString(QString::fromLatin1(s, len));
    addEntry(str);
    return str->identifier;
}

}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>#include "generator.h"

#include <cassert>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>

#include "dictionary.h"
#include "label.h"

#define LPAREN "_28"
#define RPAREN "_29"

static void compileCall(FILE* f, const char* wordName, const Tokens& tokens,
        Tokens::const_iterator* it, bool* state, Dictionary* dictionary) {
    static const char* noTailCallEliminationWords[] = {
        "r@",
        "r>",
        "unloop",
        ">r",
        nullptr
    };
    ++*it;
    bool tailCall = (*it != tokens.end() && (*it)->type == SemiColon);
    const char** tceIt = noTailCallEliminationWords;
    while (*tceIt) {
        tailCall &= !strcmp(wordName, *tceIt);
        ++tceIt;
    }
    --*it;
    fprintf(f, tailCall ? "\tjmp %s\n" : "\tjsr %s\n", label(wordName).c_str());
    if (tailCall) {
        ++*it;  // Skips ;
        *state = false;
    }
    dictionary->markAsUsed(wordName);
}

void generateAsm(FILE* f, const Tokens& tokens, Dictionary* dictionary) {
    std::deque<int> stack;
    std::deque<int> loopStack;
    int loopCounter = 0;
    int localLabel = 0;
    bool state = false;
    std::set<int> undefinedVariables;
    int variableLabel = 0;
    std::map<std::string, int> variableLabels;

    for (auto it = tokens.begin(); it != tokens.end(); ++it) {
        switch (it->type) {
            case Loop:
                fprintf(f, "\tjsr " LPAREN "loop" RPAREN "\n\tjmp .l%i\n.loopexit_%i:\n",
                        stack.back(),
                        loopStack.back());
                loopStack.pop_back();
                dictionary->markAsUsed("(loop)");
                break;
            case Leave:
                fprintf(f, "\tjsr unloop\n\tjmp .loopexit_%i\n", loopStack.back());
                dictionary->markAsUsed("unloop");
                break;
            case I:
                assert(state);
                fprintf(f, "\tjsr r_40\t; i\n");
                dictionary->markAsUsed("r@");
                break;
            case None:
                assert(!"Invalid token");
                break;
            case Do:
                assert(state);
                fprintf(f, "\tjsr " LPAREN "do" RPAREN "\t; loop %i\n.l%i:\n", loopCounter, localLabel);
                dictionary->markAsUsed("(do)");
                loopStack.push_back(loopCounter++);
                stack.push_back(localLabel++);
                break;
            case Cells:
                if (state) {
                    compileCall(f, "2*", tokens, &it, &state, dictionary);
                } else {
                    stack.back() *= 2;
                }
                break;
            case Allot:
                assert(!stack.empty());
                fprintf(f, "* = * + %i\n", stack.back());
                stack.pop_back();
                break;
            case Create:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "create must be followed by a word name!");
                    exit(1);
                }
                // printf("Create '%s'\n", it->stringData);
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                free(it->stringData);
                break;
            case String:
                fprintf(f, "\tjsr " LPAREN "litstring" RPAREN "\n!byte %i\n!text \"%s\"\n",
                        (int)strlen(it->stringData), it->stringData);
                dictionary->markAsUsed("(litstring)");
                free(it->stringData);
                break;
            case Variable:
                // puts("Variable");
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "variable must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #<+\n\tldy #>+\n\tjmp " LPAREN "pushya" RPAREN "\n+\n!word vl_%i\n", variableLabel);
                undefinedVariables.insert(variableLabel);
                variableLabels[it->stringData] = variableLabel;
                ++variableLabel;
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
            case Store:
                if (!state) {
                    int variableLabel = stack.back();
                    stack.pop_back();
                    int value = stack.back();
                    stack.pop_back();
                    fprintf(f, "vl_%i = %i\n", variableLabel, value);
                    undefinedVariables.erase(variableLabel);
                    break;
                } else {
                    compileCall(f, "!", tokens, &it, &state, dictionary);
                }
                break;
            case WordName:
                // printf("WordName %s\n", it->stringData);
                assert(it->stringData);
                if (state) {
                    char* wordName = it->stringData;
                    compileCall(f, wordName, tokens, &it, &state, dictionary);
                    free(wordName);
                } else {
                    char* wordName = it->stringData;
                    if (variableLabels.find(wordName) != variableLabels.end()) {
                        stack.push_back(variableLabels[wordName]);
                        free(it->stringData);
                    } else {
                        fprintf(stderr, "Variable '%s' not defined\n", wordName);
                        exit(1);
                    }
                }
                break;
            case Number:
                // puts("Number");
                if (state) {
                    dictionary->markAsUsed("(lit)");
                    fprintf(f, "\tjsr " LPAREN "lit" RPAREN "\n\t!word %i\n", it->intData);
                } else {
                    stack.push_back(it->intData);
                }
                break;
            case Code:
                // puts("Code");
                {
                    char* p = it->stringData;
                    std::string wordName;
                    while (!isspace(*p)) {
                        wordName.push_back(*p);
                        ++p;
                    }
                    dictionary->addWord(wordName.c_str());
                    if (*p == '\n') {
                        ++p;
                    }
                    if (label(wordName.c_str()) != wordName) {
                        fprintf(f, "%s:\t; %s\n%s\n", label(wordName.c_str()).c_str(),
                                wordName.c_str(), p);
                    } else {
                        fprintf(f, "%s:\n%s\n", wordName.c_str(), p);
                    }
                }
                free(it->stringData);
                break;
            case Colon:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, ": must be followed by a word name! (is type %i)\n", it->type);
                    exit(1);
                }
                fprintf(f, "\n%s:", label(it->stringData).c_str());
                // printf("Colon %s\n", it->stringData);
                dictionary->addWord(it->stringData);
                if (it->stringData != label(it->stringData)) {
                    fprintf(f, "\t; %s", it->stringData);
                }
                fprintf(f, "\n");
                free(it->stringData);
                state = true;
                break;
            case Drop:
                fputs("\tinx\t; drop\n", f);
                break;
            case SemiColon:
                fputs("\trts\n", f);
                state = false;
                break;
            case If:
                fprintf(f, "\tjsr " LPAREN "if" RPAREN "\n\tbeq .l%i\n", localLabel);
                dictionary->markAsUsed("(if)");
                stack.push_back(localLabel++);
                break;
            case Else:
                fprintf(f, "\tjmp .l%i\n.l%i:\n", localLabel, stack.back());
                stack.pop_back();
                stack.push_back(localLabel++);
                break;
            case Then:
                fprintf(f, ".l%i:\n", stack.back());
                stack.pop_back();
                break;
            case Begin:
                stack.push_back(localLabel);
                fprintf(f, ".l%i:\n", localLabel++);
                break;
            case Again:
                fprintf(f, "\tjmp .l%i\n", stack.back());
                stack.pop_back();
                break;
            case Value:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "value must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #%i\n", stack.back() & 0xff);
                fprintf(f, "\tldy #%i\n", stack.back() >> 8);
                fprintf(f, "\tjmp " LPAREN "pushya" RPAREN "\n");
                stack.pop_back();
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
        }
    }
}
<commit_msg>bugfixed loop<commit_after>#include "generator.h"

#include <cassert>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>

#include "dictionary.h"
#include "label.h"

#define LPAREN "_28"
#define RPAREN "_29"

static void compileCall(FILE* f, const char* wordName, const Tokens& tokens,
        Tokens::const_iterator* it, bool* state, Dictionary* dictionary) {
    static const char* noTailCallEliminationWords[] = {
        "r@",
        "r>",
        "unloop",
        ">r",
        nullptr
    };
    ++*it;
    bool tailCall = (*it != tokens.end() && (*it)->type == SemiColon);
    const char** tceIt = noTailCallEliminationWords;
    while (*tceIt) {
        tailCall &= !strcmp(wordName, *tceIt);
        ++tceIt;
    }
    --*it;
    fprintf(f, tailCall ? "\tjmp %s\n" : "\tjsr %s\n", label(wordName).c_str());
    if (tailCall) {
        ++*it;  // Skips ;
        *state = false;
    }
    dictionary->markAsUsed(wordName);
}

void generateAsm(FILE* f, const Tokens& tokens, Dictionary* dictionary) {
    std::deque<int> stack;
    std::deque<int> loopStack;
    int loopCounter = 0;
    int localLabel = 0;
    bool state = false;
    std::set<int> undefinedVariables;
    int variableLabel = 0;
    std::map<std::string, int> variableLabels;

    for (auto it = tokens.begin(); it != tokens.end(); ++it) {
        switch (it->type) {
            case Loop:
                fprintf(f, "\tjsr " LPAREN "loop" RPAREN "\n\tjmp .l%i\n.loopexit_%i:\n",
                        stack.back(),
                        loopStack.back());
                stack.pop_back();
                loopStack.pop_back();
                dictionary->markAsUsed("(loop)");
                break;
            case Leave:
                fprintf(f, "\tjsr unloop\n\tjmp .loopexit_%i\n", loopStack.back());
                dictionary->markAsUsed("unloop");
                break;
            case I:
                assert(state);
                fprintf(f, "\tjsr r_40\t; i\n");
                dictionary->markAsUsed("r@");
                break;
            case None:
                assert(!"Invalid token");
                break;
            case Do:
                assert(state);
                fprintf(f, "\tjsr " LPAREN "do" RPAREN "\t; loop %i\n.l%i:\n", loopCounter, localLabel);
                dictionary->markAsUsed("(do)");
                loopStack.push_back(loopCounter++);
                stack.push_back(localLabel++);
                break;
            case Cells:
                if (state) {
                    compileCall(f, "2*", tokens, &it, &state, dictionary);
                } else {
                    stack.back() *= 2;
                }
                break;
            case Allot:
                assert(!stack.empty());
                fprintf(f, "* = * + %i\n", stack.back());
                stack.pop_back();
                break;
            case Create:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "create must be followed by a word name!");
                    exit(1);
                }
                // printf("Create '%s'\n", it->stringData);
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                free(it->stringData);
                break;
            case String:
                fprintf(f, "\tjsr " LPAREN "litstring" RPAREN "\n!byte %i\n!text \"%s\"\n",
                        (int)strlen(it->stringData), it->stringData);
                dictionary->markAsUsed("(litstring)");
                free(it->stringData);
                break;
            case Variable:
                // puts("Variable");
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "variable must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #<+\n\tldy #>+\n\tjmp " LPAREN "pushya" RPAREN "\n+\n!word vl_%i\n", variableLabel);
                undefinedVariables.insert(variableLabel);
                variableLabels[it->stringData] = variableLabel;
                ++variableLabel;
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
            case Store:
                if (!state) {
                    int variableLabel = stack.back();
                    stack.pop_back();
                    int value = stack.back();
                    stack.pop_back();
                    fprintf(f, "vl_%i = %i\n", variableLabel, value);
                    undefinedVariables.erase(variableLabel);
                    break;
                } else {
                    compileCall(f, "!", tokens, &it, &state, dictionary);
                }
                break;
            case WordName:
                // printf("WordName %s\n", it->stringData);
                assert(it->stringData);
                if (state) {
                    char* wordName = it->stringData;
                    compileCall(f, wordName, tokens, &it, &state, dictionary);
                    free(wordName);
                } else {
                    char* wordName = it->stringData;
                    if (variableLabels.find(wordName) != variableLabels.end()) {
                        stack.push_back(variableLabels[wordName]);
                        free(it->stringData);
                    } else {
                        fprintf(stderr, "Variable '%s' not defined\n", wordName);
                        exit(1);
                    }
                }
                break;
            case Number:
                // puts("Number");
                if (state) {
                    dictionary->markAsUsed("(lit)");
                    fprintf(f, "\tjsr " LPAREN "lit" RPAREN "\n\t!word %i\n", it->intData);
                } else {
                    stack.push_back(it->intData);
                }
                break;
            case Code:
                // puts("Code");
                {
                    char* p = it->stringData;
                    std::string wordName;
                    while (!isspace(*p)) {
                        wordName.push_back(*p);
                        ++p;
                    }
                    dictionary->addWord(wordName.c_str());
                    if (*p == '\n') {
                        ++p;
                    }
                    if (label(wordName.c_str()) != wordName) {
                        fprintf(f, "%s:\t; %s\n%s\n", label(wordName.c_str()).c_str(),
                                wordName.c_str(), p);
                    } else {
                        fprintf(f, "%s:\n%s\n", wordName.c_str(), p);
                    }
                }
                free(it->stringData);
                break;
            case Colon:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, ": must be followed by a word name! (is type %i)\n", it->type);
                    exit(1);
                }
                fprintf(f, "\n%s:", label(it->stringData).c_str());
                // printf("Colon %s\n", it->stringData);
                dictionary->addWord(it->stringData);
                if (it->stringData != label(it->stringData)) {
                    fprintf(f, "\t; %s", it->stringData);
                }
                fprintf(f, "\n");
                free(it->stringData);
                state = true;
                break;
            case Drop:
                fputs("\tinx\t; drop\n", f);
                break;
            case SemiColon:
                fputs("\trts\n", f);
                state = false;
                break;
            case If:
                fprintf(f, "\tjsr " LPAREN "if" RPAREN "\n\tbeq .l%i\n", localLabel);
                dictionary->markAsUsed("(if)");
                stack.push_back(localLabel++);
                break;
            case Else:
                fprintf(f, "\tjmp .l%i\n.l%i:\n", localLabel, stack.back());
                stack.pop_back();
                stack.push_back(localLabel++);
                break;
            case Then:
                fprintf(f, ".l%i:\n", stack.back());
                stack.pop_back();
                break;
            case Begin:
                stack.push_back(localLabel);
                fprintf(f, ".l%i:\n", localLabel++);
                break;
            case Again:
                fprintf(f, "\tjmp .l%i\n", stack.back());
                stack.pop_back();
                break;
            case Value:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "value must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #%i\n", stack.back() & 0xff);
                fprintf(f, "\tldy #%i\n", stack.back() >> 8);
                fprintf(f, "\tjmp " LPAREN "pushya" RPAREN "\n");
                stack.pop_back();
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
        }
    }
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <string>
#include <functional>
#include <unordered_map>
#include <list>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <map>

#if defined(__APPLE__) || defined(__GNUC__) && __GNUC__ * 10  + __GNUC_MINOR__ >= 49
#include <regex>
#endif

#include <assert.h>
#include <vector>
#include <fstream>
#include <future>

#include <ctime>

#define BUF_SIZE 4096
#define MAX_LISTEN 128

namespace Cappuccino{

	class Request;
	class Response;

	struct {

		time_t time;
   		struct tm *t_st;

		int port = 1204;
		int sockfd = 0;
		int sessionfd = 0;
	    fd_set mask1fds, mask2fds;

		std::shared_ptr<std::string> view_root;
		std::shared_ptr<std::string> static_root;

		std::map<std::string,
			std::function<Response(std::shared_ptr<Request>)>
		> routes;
	} context;

	namespace Log{

		std::string current(){
			char timestr[256];
   			time(&context.time);
			strftime(timestr, 255, "%Y-%m-%d %H:%M:%S %X", localtime(&context.time));
			return timestr;
		}

		static int LogLevel = 0;
		static void debug(std::string msg){
			if(LogLevel >= 1){
				std::cout <<current()<<" "<< msg << std::endl;
			}
		}

		static void info(std::string msg){
			if(LogLevel >= 2){
				std::cout <<current()<<" "<< msg << std::endl;
			}
		}
	};

	namespace signal_utils{

		void signal_handler(int signal){
			close(context.sessionfd);
			close(context.sockfd);
			exit(0);
		}

		void signal_handler_child(int SignalName){
			while(waitpid(-1,NULL,WNOHANG)>0){}
	        signal(SIGCHLD, signal_utils::signal_handler_child);
		}

		void init_signal(){
			if(signal(SIGINT, signal_utils::signal_handler) == SIG_ERR){
				exit(1);
			}
			if(signal(SIGCHLD, signal_utils::signal_handler_child) == SIG_ERR){
				exit(1);
			}
		}
	}

	namespace utils{
		std::vector<std::string> split(const std::string& str, std::string delim) noexcept{
			std::vector<std::string> result;
		    std::string::size_type pos = 0;
		    while(pos != std::string::npos ){
		        std::string::size_type p = str.find(delim, pos);
		        if(p == std::string::npos){
		            result.push_back(str.substr(pos));
		            break;
		        }else{
		            result.push_back(str.substr(pos, p - pos));
		        }
		        pos = p + delim.size();
		    }
		    return result;
		}
	};

	void init_socket(){
	    struct sockaddr_in server;
		if((context.sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
			exit(EXIT_FAILURE);
		}
		memset( &server, 0, sizeof(server));
		server.sin_family = AF_INET;
		server.sin_addr.s_addr = INADDR_ANY;
		server.sin_port = htons(context.port);

		char opt = 1;
		setsockopt(context.sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(char));

		int temp = 1;
  		if(setsockopt(context.sockfd, SOL_SOCKET, SO_REUSEADDR,
	        &temp, sizeof(int))){
		}

		if (bind(context.sockfd, (struct sockaddr *) &server, sizeof(server)) < 0) {
			exit(EXIT_FAILURE);
		}

		if(listen(context.sockfd,  MAX_LISTEN) < 0) {
			exit(EXIT_FAILURE);
		}

	    FD_ZERO(&context.mask1fds);
	    FD_SET(context.sockfd, &context.mask1fds);
	}

	using namespace std;

	string openFile(string aFilename){
		auto filename = aFilename;
		std::ifstream ifs( filename, std::ios::in | std::ios::binary);
		if(ifs.fail()){
			throw std::runtime_error("No such file or directory \""+ filename +"\"\n");
		}
		ifs.seekg( 0, std::ios::end);
		auto pos = ifs.tellg();
		ifs.seekg( 0, std::ios::beg);

		std::vector<char> buf(pos);
		ifs.read(buf.data(), pos);
		return string(buf.begin(), buf.end());;
	}

	void option(int argc, char *argv[]) noexcept{
		char result;
		while((result = getopt(argc,argv,"dp:")) != -1){
			switch(result){
			case 'd':
				Log::LogLevel = 1;
				break;
			case 'p':
				context.port = atoi(optarg);
				break;
			}
		}
	}

	class Request{
		map<string, string> headerset;
		map<string, string> paramset;
	  public:
		Request(string method, string url,string protocol):
		method(move(method)),
		url(move(url)),
		protocol(move(protocol))
		{}

		const string method;
		const string url;
		const string protocol;

		void addHeader(string key,string value){
			headerset[key] = move(value);
		}

		void addParams(string key,string value){
			paramset[key] = move(value);
		}

		string header(string key){
			if(headerset.find(key) == headerset.end())
				return "INVALID";
			return headerset[key];
		}

		string params(string key){
			if(paramset.find(key) == paramset.end())
				return "INVALID";
			return paramset[key];
		}
	};

    class Response{
		int status_;
		string message_;
		string url;
		string body;
		string protocol;
      public:

		Response(weak_ptr<Request> req){
			auto r = req.lock();
			if(r){
				url = r->url;
				protocol = r->protocol;
			}else{
				throw std::runtime_error("Request  expired!\n");
			}
		}

		Response(int st,string msg,string pro, string bod){
			status_ = st;
			message_ = msg;
			protocol = pro;
			body = bod;
		}

		Response* message(string msg){
			message_ = msg;
			return this;
		}

		Response* status(int st){
			status_ = st;
			return this;
		}

		Response* file(string filename){
			body = openFile(*context.view_root + "/" + filename);
			return this;
		}

      	operator string(){
      		return protocol + " " + to_string(status_) +" "+ message_ + "\n\n" + body;
      	}
    };

	string createResponse(char* req) noexcept{
		auto lines = utils::split(string(req), "\n");
		if(lines.empty())
			return Response(400, "Bad Request", "HTTP/1.1", "NN");

		auto tops = utils::split(lines[0], " ");
		if(tops.size() < 3)
			return Response(401, "Bad Request", "HTTP/1.1",  "NN");

		cout<< tops[0] << " " << tops[1] << " " <<tops[2] << endl;

		auto request = shared_ptr<Request>(new Request(tops[0],tops[1],tops[2]));

		if(context.routes.find(tops[1]) != context.routes.end()){
			return context.routes[tops[1]](move(request));
		}

		return Response( 404,"Not found", tops[2], "AA");
	}

	string receiveProcess(int sessionfd){
		char buf[BUF_SIZE] = {};

		if (recv(sessionfd, buf, sizeof(buf), 0) < 0) {
			exit(EXIT_FAILURE);
		}
		do{
			if(strstr(buf, "\r\n")){
				break;
			}
			if (strlen(buf) >= sizeof(buf)) {
				memset(&buf, 0, sizeof(buf));
			}
		}while(read(sessionfd, buf+strlen(buf), sizeof(buf) - strlen(buf)) > 0);
		return createResponse(buf);
	}

	void load(string directory, string filename) noexcept{
		if(filename == "." || filename == "..") return;
		if(filename!="")
			directory += "/" + filename;
		DIR* dir = opendir(directory.c_str());
		if(dir != NULL){
			struct dirent* dent;
	        dent = readdir(dir);
		    while(dent!=NULL){
		        dent = readdir(dir);
		        if(dent!=NULL)
			        load(directory, string(dent->d_name));
		    }
		    closedir(dir);
		}else{
			cout<<"add "<<directory<< endl;
			context.routes.insert( make_pair(
				"/" + directory,
				[directory,filename](std::shared_ptr<Request> request) -> Cappuccino::Response{
					return Response(200,"OK","HTTP/1.1",openFile(directory));
				}
			));
		}
	}

	void loadStaticFiles() noexcept{
		load(*context.static_root,"");
	}

	void route(string url,std::function<Response(std::shared_ptr<Request>)> F){
		context.routes.insert( make_pair( url, F ));
	}

	void root(string r){
		context.view_root =  make_shared<string>(move(r));
	}

	void run(){

		init_socket();
		signal_utils::init_signal();
		loadStaticFiles();

	    int cd[FD_SETSIZE];
		struct sockaddr_in client;
        int    fd;
        struct timeval tv;

	    for(int i = 0;i < FD_SETSIZE; i++){
	        cd[i] = 0;
	    }

	    while(1) {
	        tv.tv_sec = 0;
	        tv.tv_usec = 0;

	        memcpy(&context.mask2fds, &context.mask1fds, sizeof(context.mask1fds));

	        int select_result = select(FD_SETSIZE, &context.mask2fds, (fd_set *)0, (fd_set *)0, &tv);
	        if(select_result < 1) {
	            for(fd = 0; fd < FD_SETSIZE; fd++) {
	                if(cd[fd] == 1) {
	                    close(fd);
	                    FD_CLR(fd, &context.mask1fds);
	                    cd[fd] = 0;
	                }
	            }
	            continue;
	        }
			for(fd = 0; fd < FD_SETSIZE; fd++){
	            if(FD_ISSET(fd,&context.mask2fds)) {
	                if(fd == context.sockfd) {
	                	memset( &client, 0, sizeof(client));
						int len = sizeof(client);
	                    int clientfd = accept(context.sockfd,
	                        (struct sockaddr *)&client,(socklen_t *) &len);
	                        FD_SET(clientfd, &context.mask1fds);
	                }else {
	                    if(cd[fd] == 1) {
	                        close(fd);
	                        FD_CLR(fd, &context.mask1fds);
	                        cd[fd] = 0;
	                    } else {
							string response = receiveProcess(fd);
							write(fd, response.c_str(), response.size());
	                        cd[fd] = 1;
	                    }
	                }
	            }
	        }
	    }
	}

	void Cappuccino(int argc, char *argv[]) {
		option(argc, argv);

		context.view_root = make_shared<string>("");
		context.static_root = make_shared<string>("public");
	}
};

namespace Cocoa{
	using namespace Cappuccino;
	using namespace std;

	// Unit Test
	void testOpenFile(){
		string res = openFile("html/index.html");
		auto lines = utils::split(res, "\n");
		assert(!lines.empty());
	}

	void testOpenInvalidFile(){
		try{
			string res = openFile("html/index");
		}catch(std::runtime_error e){
			cout<< e.what() << endl;
		}
	}
};

<commit_msg>[Fix] log format %X -> %Z<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <string>
#include <functional>
#include <unordered_map>
#include <list>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <map>

#if defined(__APPLE__) || defined(__GNUC__) && __GNUC__ * 10  + __GNUC_MINOR__ >= 49
#include <regex>
#endif

#include <assert.h>
#include <vector>
#include <fstream>
#include <future>

#include <ctime>

#define BUF_SIZE 4096
#define MAX_LISTEN 128

namespace Cappuccino{

	class Request;
	class Response;

	struct {

		time_t time;
   		struct tm *t_st;

		int port = 1204;
		int sockfd = 0;
		int sessionfd = 0;
	    fd_set mask1fds, mask2fds;

		std::shared_ptr<std::string> view_root;
		std::shared_ptr<std::string> static_root;

		std::map<std::string,
			std::function<Response(std::shared_ptr<Request>)>
		> routes;

	} context;

	namespace Log{

		std::string current(){
			char timestr[256];
   			time(&context.time);
			strftime(timestr, 255, "%Y-%m-%d %H:%M:%S %Z", localtime(&context.time));
			return timestr;
		}

		static int LogLevel = 0;
		static void debug(std::string msg){
			if(LogLevel >= 1){
				std::cout <<current()<<" "<< msg << std::endl;
			}
		}

		static void info(std::string msg){
			if(LogLevel >= 2){
				std::cout <<current()<<" "<< msg << std::endl;
			}
		}
	};

	namespace signal_utils{

		void signal_handler(int signal){
			close(context.sessionfd);
			close(context.sockfd);
			exit(0);
		}

		void signal_handler_child(int SignalName){
			while(waitpid(-1,NULL,WNOHANG)>0){}
	        signal(SIGCHLD, signal_utils::signal_handler_child);
		}

		void init_signal(){
			if(signal(SIGINT, signal_utils::signal_handler) == SIG_ERR){
				exit(1);
			}
			if(signal(SIGCHLD, signal_utils::signal_handler_child) == SIG_ERR){
				exit(1);
			}
		}
	}

	namespace utils{
		std::vector<std::string> split(const std::string& str, std::string delim) noexcept{
			std::vector<std::string> result;
		    std::string::size_type pos = 0;
		    while(pos != std::string::npos ){
		        std::string::size_type p = str.find(delim, pos);
		        if(p == std::string::npos){
		            result.push_back(str.substr(pos));
		            break;
		        }else{
		            result.push_back(str.substr(pos, p - pos));
		        }
		        pos = p + delim.size();
		    }
		    return result;
		}
	};

	void init_socket(){
	    struct sockaddr_in server;
		if((context.sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
			exit(EXIT_FAILURE);
		}
		memset( &server, 0, sizeof(server));
		server.sin_family = AF_INET;
		server.sin_addr.s_addr = INADDR_ANY;
		server.sin_port = htons(context.port);

		char opt = 1;
		setsockopt(context.sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(char));

		int temp = 1;
  		if(setsockopt(context.sockfd, SOL_SOCKET, SO_REUSEADDR,
	        &temp, sizeof(int))){
		}

		if (bind(context.sockfd, (struct sockaddr *) &server, sizeof(server)) < 0) {
			exit(EXIT_FAILURE);
		}

		if(listen(context.sockfd,  MAX_LISTEN) < 0) {
			exit(EXIT_FAILURE);
		}

	    FD_ZERO(&context.mask1fds);
	    FD_SET(context.sockfd, &context.mask1fds);
	}

	using namespace std;

	string openFile(string aFilename){
		auto filename = aFilename;
		std::ifstream ifs( filename, std::ios::in | std::ios::binary);
		if(ifs.fail()){
			throw std::runtime_error("No such file or directory \""+ filename +"\"\n");
		}
		ifs.seekg( 0, std::ios::end);
		auto pos = ifs.tellg();
		ifs.seekg( 0, std::ios::beg);

		std::vector<char> buf(pos);
		ifs.read(buf.data(), pos);
		return string(buf.begin(), buf.end());;
	}

	void option(int argc, char *argv[]) noexcept{
		char result;
		while((result = getopt(argc,argv,"dp:")) != -1){
			switch(result){
			case 'd':
				Log::LogLevel = 1;
				break;
			case 'p':
				context.port = atoi(optarg);
				break;
			}
		}
	}

	class Request{
		map<string, string> headerset;
		map<string, string> paramset;
	  public:
		Request(string method, string url,string protocol):
		method(move(method)),
		url(move(url)),
		protocol(move(protocol))
		{}

		const string method;
		const string url;
		const string protocol;

		void addHeader(string key,string value){
			headerset[key] = move(value);
		}

		void addParams(string key,string value){
			paramset[key] = move(value);
		}

		string header(string key){
			if(headerset.find(key) == headerset.end())
				return "INVALID";
			return headerset[key];
		}

		string params(string key){
			if(paramset.find(key) == paramset.end())
				return "INVALID";
			return paramset[key];
		}
	};

    class Response{
		int status_;
		string message_;
		string url;
		string body;
		string protocol;
      public:

		Response(weak_ptr<Request> req){
			auto r = req.lock();
			if(r){
				url = r->url;
				protocol = r->protocol;
			}else{
				throw std::runtime_error("Request  expired!\n");
			}
		}

		Response(int st,string msg,string pro, string bod){
			status_ = st;
			message_ = msg;
			protocol = pro;
			body = bod;
		}

		Response* message(string msg){
			message_ = msg;
			return this;
		}

		Response* status(int st){
			status_ = st;
			return this;
		}

		Response* file(string filename){
			body = openFile(*context.view_root + "/" + filename);
			return this;
		}

      	operator string(){
      		return protocol + " " + to_string(status_) +" "+ message_ + "\n\n" + body;
      	}
    };

	string createResponse(char* req) noexcept{
		auto lines = utils::split(string(req), "\n");
		if(lines.empty())
			return Response(400, "Bad Request", "HTTP/1.1", "NN");

		auto tops = utils::split(lines[0], " ");
		if(tops.size() < 3)
			return Response(401, "Bad Request", "HTTP/1.1",  "NN");

		Log::debug(tops[0] +" "+ tops[1] +" "+ tops[2]);

		auto request = shared_ptr<Request>(new Request(tops[0],tops[1],tops[2]));

		if(context.routes.find(tops[1]) != context.routes.end()){
			return context.routes[tops[1]](move(request));
		}

		return Response( 404,"Not found", tops[2], "AA");
	}

	string receiveProcess(int sessionfd){
		char buf[BUF_SIZE] = {};

		if (recv(sessionfd, buf, sizeof(buf), 0) < 0) {
			exit(EXIT_FAILURE);
		}
		do{
			if(strstr(buf, "\r\n")){
				break;
			}
			if (strlen(buf) >= sizeof(buf)) {
				memset(&buf, 0, sizeof(buf));
			}
		}while(read(sessionfd, buf+strlen(buf), sizeof(buf) - strlen(buf)) > 0);
		return createResponse(buf);
	}

	void load(string directory, string filename) noexcept{
		if(filename == "." || filename == "..") return;
		if(filename!="")
			directory += "/" + filename;
		DIR* dir = opendir(directory.c_str());
		if(dir != NULL){
			struct dirent* dent;
	        dent = readdir(dir);
		    while(dent!=NULL){
		        dent = readdir(dir);
		        if(dent!=NULL)
			        load(directory, string(dent->d_name));
		    }
		    closedir(dir);
		}else{
			Log::debug("add "+directory);
			context.routes.insert( make_pair(
				"/" + directory,
				[directory,filename](std::shared_ptr<Request> request) -> Cappuccino::Response{
					return Response(200,"OK","HTTP/1.1",openFile(directory));
				}
			));
		}
	}

	void loadStaticFiles() noexcept{
		load(*context.static_root,"");
	}

	void route(string url,std::function<Response(std::shared_ptr<Request>)> F){
		context.routes.insert( make_pair( url, F ));
	}

	void root(string r){
		context.view_root =  make_shared<string>(move(r));
	}

	void run(){

		init_socket();
		signal_utils::init_signal();
		loadStaticFiles();

	    int cd[FD_SETSIZE];
		struct sockaddr_in client;
        int    fd;
        struct timeval tv;

	    for(int i = 0;i < FD_SETSIZE; i++){
	        cd[i] = 0;
	    }

	    while(1) {
	        tv.tv_sec = 0;
	        tv.tv_usec = 0;

	        memcpy(&context.mask2fds, &context.mask1fds, sizeof(context.mask1fds));

	        int select_result = select(FD_SETSIZE, &context.mask2fds, (fd_set *)0, (fd_set *)0, &tv);
	        if(select_result < 1) {
	            for(fd = 0; fd < FD_SETSIZE; fd++) {
	                if(cd[fd] == 1) {
	                    close(fd);
	                    FD_CLR(fd, &context.mask1fds);
	                    cd[fd] = 0;
	                }
	            }
	            continue;
	        }
			for(fd = 0; fd < FD_SETSIZE; fd++){
	            if(FD_ISSET(fd,&context.mask2fds)) {
	                if(fd == context.sockfd) {
	                	memset( &client, 0, sizeof(client));
						int len = sizeof(client);
	                    int clientfd = accept(context.sockfd,
	                        (struct sockaddr *)&client,(socklen_t *) &len);
	                        FD_SET(clientfd, &context.mask1fds);
	                }else {
	                    if(cd[fd] == 1) {
	                        close(fd);
	                        FD_CLR(fd, &context.mask1fds);
	                        cd[fd] = 0;
	                    } else {
							string response = receiveProcess(fd);
							write(fd, response.c_str(), response.size());
	                        cd[fd] = 1;
	                    }
	                }
	            }
	        }
	    }
	}

	void Cappuccino(int argc, char *argv[]) {
		option(argc, argv);

		context.view_root = make_shared<string>("");
		context.static_root = make_shared<string>("public");
	}
};

namespace Cocoa{
	using namespace Cappuccino;
	using namespace std;

	// Unit Test
	void testOpenFile(){
		string res = openFile("html/index.html");
		auto lines = utils::split(res, "\n");
		assert(!lines.empty());
	}

	void testOpenInvalidFile(){
		try{
			string res = openFile("html/index");
		}catch(std::runtime_error e){
			cout<< e.what() << endl;
		}
	}
};

<|endoftext|>