<commit_before>#include <stdio.h>
#include <stdlib.h>

#include <algorithm>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <utility>
using namespace std;

#include "scx/Dir.h"
#include "scx/FileInfo.h"
using namespace scx;

#include "Utils.h"
#include "TransUnit.h"
#include "Compiler.h"

int main(int argc, char* argv[])
{
    std::vector<KeyValueArgs::Command> cmds = {
        { "jobs",       "set number of jobs",           KeyValueArgs::Setter(), "0" },
        { "out",        "set output binary",            KeyValueArgs::Setter(), "b.out" },
        { "workdir",    "set work directory",           KeyValueArgs::Setter(), "." },
        {},
        { "as",         "set assembler",                KeyValueArgs::Setter(), "as" },
        { "asflags",    "add assembler flags",          KeyValueArgs::Jointer(), "" },
        { "cc",         "set c compiler",               KeyValueArgs::Setter(), "cc" },
        { "cflags",     "add c compiler flags",         KeyValueArgs::Jointer(), "" },
        { "cxx",        "set c++ compiler",             KeyValueArgs::Setter(), "c++" },
        { "cxxflags",   "add c++ compiler flags",       KeyValueArgs::Jointer(), "" },
        { "flags",      "add c & c++ compiler flags",   KeyValueArgs::KeyJointer({"cflags", "cxxflags"}) },
        { "ld",         "set linker",                   KeyValueArgs::Setter(), "cc" },
        { "ldflags",    "add linker flags",             KeyValueArgs::Jointer(), "" },
        { "ldorder",    "set link order",               KeyValueArgs::Setter(), "" },
        { "prefix",     "add search directories",       KeyValueArgs::KeyValueJointer({
                {"flags", [](const std::string& str){ return "-I" + str + "/include"; }},
                {"ldflags", [](const std::string& str){ return "-L" + str + "/lib"; }}
        })},
        {},
        { "verbose",    "verbose output",               KeyValueArgs::ValueSetter("1"), "0" },
        { "clean",      "remove output files",          KeyValueArgs::ValueSetter("1"), "0" },
        { "nolink",     "do not link",                  KeyValueArgs::ValueSetter("1"), "0" },
        { "thread",     "link against pthread",         KeyValueArgs::KeyValueJointer({
                {"flags", "-pthread"},
#ifndef __APPLE__
                {"ldflags", "-pthread"}
#endif
        })},
        { "shared",     "build shared library",         KeyValueArgs::KeyValueJointer({
                {"flags", "-fPIC"}, {"ldflags", "-shared"}
        })},
        { "pipe",       "enable -pipe",                 KeyValueArgs::KeyValueJointer({{"flags", "-pipe"}}) },
        { "debug",      "enable -g",                    KeyValueArgs::KeyValueJointer({{"flags", "-g"}}) },
        { "release",    "enable -DNDEBUG",              KeyValueArgs::KeyValueJointer({{"flags", "-DNDEBUG"}}) },
        { "strict",     "enable -Wall -Wextra -Werror", KeyValueArgs::KeyValueJointer({{"flags", "-Wall -Wextra -Werror"}}) },
        { "c89",        "enable -std=c89",              KeyValueArgs::KeyValueJointer({{"cflags", "-std=c89"}}) },
        { "c99",        "enable -std=c99",              KeyValueArgs::KeyValueJointer({{"cflags", "-std=c99"}}) },
        { "c11",        "enable -std=c11",              KeyValueArgs::KeyValueJointer({{"cflags", "-std=c11"}}) },
        { "c++11",      "enable -std=c++11",            KeyValueArgs::KeyValueJointer({{"cxxflags", "-std=c++11"}}) },
        { "c++1y",      "enable -std=c++1y",            KeyValueArgs::KeyValueJointer({{"cxxflags", "-std=c++1y"}}) },
        { "c++14",      "enable -std=c++14",            KeyValueArgs::KeyValueJointer({{"cxxflags", "-std=c++14"}}) },
        { "c++1z",      "enable -std=c++1z",            KeyValueArgs::KeyValueJointer({{"cxxflags", "-std=c++1z"}}) },
        { "c++17",      "enable -std=c++17",            KeyValueArgs::KeyValueJointer({{"cxxflags", "-std=c++17"}}) },
    };

    // parse command line arguments
    vector<string> inputPaths;
    auto args = KeyValueArgs::Parse(argc, argv, cmds, [&](std::string&& key, std::string&& value) {
        if (key == "help") {
            const size_t n = 8;
            const std::string blank(n, ' ');
            cout << "Usage:" << endl;
            cout << blank << std::string(argv[0]) << " [option...] [file ...] [dir ...]" << endl;
            cout << endl;
            cout << KeyValueArgs::ToString(cmds, n) << endl;
            ::exit(EXIT_SUCCESS);
        } else if (value.empty()) {
            inputPaths.push_back(key);
        } else {
            cerr << "Invalid argument: " << key;
            if (!value.empty()) {
                cerr << "=" << value;
            }
            cerr << endl;
            ::exit(EXIT_FAILURE);
        }
    });
    if (inputPaths.empty()) {
        inputPaths.push_back(".");
    }

    // scan source files
    vector<string> sourcePaths;
    for (const auto& path: inputPaths) {
        switch (FileInfo(path).Type()) {
            case FileType::Regular: {
                sourcePaths.push_back(path);
                break;
            };
            case FileType::Directory: {
                auto subpaths = Dir::ListDir(path);
                sourcePaths.reserve(sourcePaths.size() + subpaths.size());
                for (const auto& subpath: subpaths) {
                    const auto baseName = FileInfo::BaseName(subpath);
                    if (baseName == "." || baseName == "..") {
                        continue;
                    }
                    const auto filePath = path + "/" + subpath;
                    sourcePaths.push_back(filePath);
                }
                break;
            };
            default: {
                break;
            }
        }
    }
    std::sort(sourcePaths.begin(), sourcePaths.end(), [](const auto& a, const auto& b) {
        return std::strcoll(a.c_str(), b.c_str()) < 0 ? true : false;
    });
    if (sourcePaths.empty()) {
        cerr << "FATAL: nothing to build!" << endl;
        ::exit(EXIT_FAILURE);
    }

    // ensure work directory
    if (!args["workdir"].empty()) {
        auto& dir = args["workdir"];
        if (dir[dir.size()-1] != '/') {
            dir += "/";
        }
        const auto& info = FileInfo(dir);
        if (!info.Exists()) {
            if (!Dir::MakeDir(dir, 0744)) {
                cerr << "Failed to create directory!" << endl;
                cerr << "    Directory: " << dir << endl;
                ::exit(EXIT_FAILURE);
            }
        } else if (info.Type() != FileType::Directory) {
            cerr << "Bad work directory! " << endl;
            cerr << "    Directory: " << dir << endl;
            cerr << "    File type: " << FileType::ToString(info.Type()) << endl;
            ::exit(EXIT_FAILURE);
        }
    }

    // scan translation units
    vector<TransUnit> newUnits;
    string allObjects;
    {
        bool hasCpp = false;
        const auto& ldorder = args["ldorder"];
        std::vector<std::pair<size_t, std::string>> headObjects;
        for (const auto& file: sourcePaths) {
            const auto& outdir = args["workdir"];
            bool isCpp = false;
            auto unit = TransUnit::Make(file, outdir, args, isCpp);
            if (!unit) {
                continue;
            }
            hasCpp = hasCpp || isCpp;
            auto pos = ldorder.empty() ? std::string::npos : ldorder.find(FileInfo::BaseName(unit.objfile));
            if (pos != std::string::npos) {
                headObjects.emplace_back(pos, unit.objfile);
            } else {
                allObjects += unit.objfile + ' ';
            }
            if (!unit.command.empty()) {
                newUnits.push_back(std::move(unit));
            }
        }
        std::sort(headObjects.begin(), headObjects.end(), [](const auto& a, const auto& b) {
            return a.first > b.first;
        });
        for (auto&& headObject: headObjects) {
            allObjects.insert(0, std::move(headObject.second) + ' ');
        }
        if (hasCpp) {
            args["ld"] = args["cxx"];
        }
    }

#ifdef DEBUG
    // Debug info.
    {
        std::string split(80, '-');
        cout << "New translation units: " << endl;
        cout << split << endl;
        for (const auto& unit: newUnits) {
            cout << unit.Note(true) << endl;
            for (const auto& dep: unit.deps) {
                cout << dep << ", ";
            }
            cout << endl << split << endl;
        }
    }
#endif

    // clean
    if (args["clean"] == "1") {
        const string& cmd = "rm -f " + args["workdir"] + args["out"] + ' ' + allObjects;
        cout << cmd << endl;
        ::system(cmd.c_str());
        ::exit(EXIT_SUCCESS);
    }

    // compile
    auto verbose = args["verbose"] == "1";
    if (!newUnits.empty()) {
        cout << "* Build: ";
        if (verbose) {
            for (size_t i = 0; i < newUnits.size(); ++i) {
                cout << newUnits[i].srcfile << ((i+1 < newUnits.size()) ? ", " : "");
            }
        } else {
            cout << newUnits.size() << (newUnits.size() > 1 ? " files" : " file");
        }
        cout << endl;
        if (Compiler::Run(newUnits, std::stoi(args["jobs"]), verbose) != 0) {
            ::exit(EXIT_FAILURE);
        }
    }

    // link
    bool hasOut = FileInfo(args["workdir"] + args["out"]).Exists();
    if ((!hasOut || !newUnits.empty()) && args["nolink"] != "1") {
        string ldCmd = Join({args["ld"], args["ldflags"], "-o", args["workdir"] + args["out"], allObjects});
        if (verbose) {
            cout << "- Link - " << ldCmd << endl;
        } else {
            cout << "- Link - " << args["workdir"] + args["out"] << endl;
        }
        if (::system(ldCmd.c_str()) != 0) {
            cerr << "FATAL: failed to link!" << endl;
            cerr << "    file:   " << allObjects << endl;
            cerr << "    ld:     " << args["ld"] << endl;
            cerr << "    ldflags: " << args["ldflags"] << endl;
            ::exit(EXIT_FAILURE);
        }
    }

    ::exit(EXIT_SUCCESS);
}
<commit_msg>Improve invalid argument check<commit_after>#include <stdio.h>
#include <stdlib.h>

#include <algorithm>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <utility>
using namespace std;

#include "scx/Dir.h"
#include "scx/FileInfo.h"
using namespace scx;

#include "Utils.h"
#include "TransUnit.h"
#include "Compiler.h"

int main(int argc, char* argv[])
{
    std::vector<KeyValueArgs::Command> cmds = {
        { "jobs",       "set number of jobs",           KeyValueArgs::Setter(), "0" },
        { "out",        "set output binary",            KeyValueArgs::Setter(), "b.out" },
        { "workdir",    "set work directory",           KeyValueArgs::Setter(), "." },
        {},
        { "as",         "set assembler",                KeyValueArgs::Setter(), "as" },
        { "asflags",    "add assembler flags",          KeyValueArgs::Jointer(), "" },
        { "cc",         "set c compiler",               KeyValueArgs::Setter(), "cc" },
        { "cflags",     "add c compiler flags",         KeyValueArgs::Jointer(), "" },
        { "cxx",        "set c++ compiler",             KeyValueArgs::Setter(), "c++" },
        { "cxxflags",   "add c++ compiler flags",       KeyValueArgs::Jointer(), "" },
        { "flags",      "add c & c++ compiler flags",   KeyValueArgs::KeyJointer({"cflags", "cxxflags"}) },
        { "ld",         "set linker",                   KeyValueArgs::Setter(), "cc" },
        { "ldflags",    "add linker flags",             KeyValueArgs::Jointer(), "" },
        { "ldorder",    "set link order",               KeyValueArgs::Setter(), "" },
        { "prefix",     "add search directories",       KeyValueArgs::KeyValueJointer({
                {"flags", [](const std::string& str){ return "-I" + str + "/include"; }},
                {"ldflags", [](const std::string& str){ return "-L" + str + "/lib"; }}
        })},
        {},
        { "verbose",    "verbose output",               KeyValueArgs::ValueSetter("1"), "0" },
        { "clean",      "remove output files",          KeyValueArgs::ValueSetter("1"), "0" },
        { "nolink",     "do not link",                  KeyValueArgs::ValueSetter("1"), "0" },
        { "thread",     "link against pthread",         KeyValueArgs::KeyValueJointer({
                {"flags", "-pthread"},
#ifndef __APPLE__
                {"ldflags", "-pthread"}
#endif
        })},
        { "shared",     "build shared library",         KeyValueArgs::KeyValueJointer({
                {"flags", "-fPIC"}, {"ldflags", "-shared"}
        })},
        { "pipe",       "enable -pipe",                 KeyValueArgs::KeyValueJointer({{"flags", "-pipe"}}) },
        { "debug",      "enable -g",                    KeyValueArgs::KeyValueJointer({{"flags", "-g"}}) },
        { "release",    "enable -DNDEBUG",              KeyValueArgs::KeyValueJointer({{"flags", "-DNDEBUG"}}) },
        { "strict",     "enable -Wall -Wextra -Werror", KeyValueArgs::KeyValueJointer({{"flags", "-Wall -Wextra -Werror"}}) },
        { "c89",        "enable -std=c89",              KeyValueArgs::KeyValueJointer({{"cflags", "-std=c89"}}) },
        { "c99",        "enable -std=c99",              KeyValueArgs::KeyValueJointer({{"cflags", "-std=c99"}}) },
        { "c11",        "enable -std=c11",              KeyValueArgs::KeyValueJointer({{"cflags", "-std=c11"}}) },
        { "c++11",      "enable -std=c++11",            KeyValueArgs::KeyValueJointer({{"cxxflags", "-std=c++11"}}) },
        { "c++1y",      "enable -std=c++1y",            KeyValueArgs::KeyValueJointer({{"cxxflags", "-std=c++1y"}}) },
        { "c++14",      "enable -std=c++14",            KeyValueArgs::KeyValueJointer({{"cxxflags", "-std=c++14"}}) },
        { "c++1z",      "enable -std=c++1z",            KeyValueArgs::KeyValueJointer({{"cxxflags", "-std=c++1z"}}) },
        { "c++17",      "enable -std=c++17",            KeyValueArgs::KeyValueJointer({{"cxxflags", "-std=c++17"}}) },
    };

    // parse command line arguments
    vector<string> inputPaths;
    auto args = KeyValueArgs::Parse(argc, argv, cmds, [&](std::string&& key, std::string&& value) {
        if (key == "help") {
            const size_t n = 8;
            const std::string blank(n, ' ');
            cout << "Usage:" << endl;
            cout << blank << std::string(argv[0]) << " [option...] [file ...] [dir ...]" << endl;
            cout << endl;
            cout << KeyValueArgs::ToString(cmds, n) << endl;
            ::exit(EXIT_SUCCESS);
        } else if (value.empty()) {
            inputPaths.push_back(key);
        } else {
            cerr << "Invalid argument: " << key;
            if (!value.empty()) {
                cerr << "=" << value;
            }
            cerr << endl;
            ::exit(EXIT_FAILURE);
        }
    });
    if (inputPaths.empty()) {
        inputPaths.push_back(".");
    }

    // scan source files
    vector<string> sourcePaths;
    for (const auto& path: inputPaths) {
        switch (FileInfo(path).Type()) {
            case FileType::Regular: {
                sourcePaths.push_back(path);
                break;
            };
            case FileType::Directory: {
                auto subpaths = Dir::ListDir(path);
                sourcePaths.reserve(sourcePaths.size() + subpaths.size());
                for (const auto& subpath: subpaths) {
                    const auto baseName = FileInfo::BaseName(subpath);
                    if (baseName == "." || baseName == "..") {
                        continue;
                    }
                    const auto filePath = path + "/" + subpath;
                    sourcePaths.push_back(filePath);
                }
                break;
            };
            default: {
                cerr << "Invalid argument: " << path << endl;
                ::exit(EXIT_FAILURE);
            }
        }
    }
    std::sort(sourcePaths.begin(), sourcePaths.end(), [](const auto& a, const auto& b) {
        return std::strcoll(a.c_str(), b.c_str()) < 0 ? true : false;
    });
    if (sourcePaths.empty()) {
        cerr << "FATAL: nothing to build!" << endl;
        ::exit(EXIT_FAILURE);
    }

    // ensure work directory
    if (!args["workdir"].empty()) {
        auto& dir = args["workdir"];
        if (dir[dir.size()-1] != '/') {
            dir += "/";
        }
        const auto& info = FileInfo(dir);
        if (!info.Exists()) {
            if (!Dir::MakeDir(dir, 0744)) {
                cerr << "Failed to create directory!" << endl;
                cerr << "    Directory: " << dir << endl;
                ::exit(EXIT_FAILURE);
            }
        } else if (info.Type() != FileType::Directory) {
            cerr << "Bad work directory! " << endl;
            cerr << "    Directory: " << dir << endl;
            cerr << "    File type: " << FileType::ToString(info.Type()) << endl;
            ::exit(EXIT_FAILURE);
        }
    }

    // scan translation units
    vector<TransUnit> newUnits;
    string allObjects;
    {
        bool hasCpp = false;
        const auto& ldorder = args["ldorder"];
        std::vector<std::pair<size_t, std::string>> headObjects;
        for (const auto& file: sourcePaths) {
            const auto& outdir = args["workdir"];
            bool isCpp = false;
            auto unit = TransUnit::Make(file, outdir, args, isCpp);
            if (!unit) {
                continue;
            }
            hasCpp = hasCpp || isCpp;
            auto pos = ldorder.empty() ? std::string::npos : ldorder.find(FileInfo::BaseName(unit.objfile));
            if (pos != std::string::npos) {
                headObjects.emplace_back(pos, unit.objfile);
            } else {
                allObjects += unit.objfile + ' ';
            }
            if (!unit.command.empty()) {
                newUnits.push_back(std::move(unit));
            }
        }
        std::sort(headObjects.begin(), headObjects.end(), [](const auto& a, const auto& b) {
            return a.first > b.first;
        });
        for (auto&& headObject: headObjects) {
            allObjects.insert(0, std::move(headObject.second) + ' ');
        }
        if (hasCpp) {
            args["ld"] = args["cxx"];
        }
    }

#ifdef DEBUG
    // Debug info.
    {
        std::string split(80, '-');
        cout << "New translation units: " << endl;
        cout << split << endl;
        for (const auto& unit: newUnits) {
            cout << unit.Note(true) << endl;
            for (const auto& dep: unit.deps) {
                cout << dep << ", ";
            }
            cout << endl << split << endl;
        }
    }
#endif

    // clean
    if (args["clean"] == "1") {
        const string& cmd = "rm -f " + args["workdir"] + args["out"] + ' ' + allObjects;
        cout << cmd << endl;
        ::system(cmd.c_str());
        ::exit(EXIT_SUCCESS);
    }

    // compile
    auto verbose = args["verbose"] == "1";
    if (!newUnits.empty()) {
        cout << "* Build: ";
        if (verbose) {
            for (size_t i = 0; i < newUnits.size(); ++i) {
                cout << newUnits[i].srcfile << ((i+1 < newUnits.size()) ? ", " : "");
            }
        } else {
            cout << newUnits.size() << (newUnits.size() > 1 ? " files" : " file");
        }
        cout << endl;
        if (Compiler::Run(newUnits, std::stoi(args["jobs"]), verbose) != 0) {
            ::exit(EXIT_FAILURE);
        }
    }

    // link
    bool hasOut = FileInfo(args["workdir"] + args["out"]).Exists();
    if ((!hasOut || !newUnits.empty()) && args["nolink"] != "1") {
        string ldCmd = Join({args["ld"], args["ldflags"], "-o", args["workdir"] + args["out"], allObjects});
        if (verbose) {
            cout << "- Link - " << ldCmd << endl;
        } else {
            cout << "- Link - " << args["workdir"] + args["out"] << endl;
        }
        if (::system(ldCmd.c_str()) != 0) {
            cerr << "FATAL: failed to link!" << endl;
            cerr << "    file:   " << allObjects << endl;
            cerr << "    ld:     " << args["ld"] << endl;
            cerr << "    ldflags: " << args["ldflags"] << endl;
            ::exit(EXIT_FAILURE);
        }
    }

    ::exit(EXIT_SUCCESS);
}
<|endoftext|>


<commit_before>#include <thread>
#include "augs/misc/templated_readwrite.h"
#include "game/bindings/bind_game_and_augs.h"
#include "augs/global_libraries.h"
#include "application/game_window.h"

#include "game/resources/manager.h"

#include "game/scene_managers/resource_setups/all.h"

#include "game/transcendental/types_specification/all_component_includes.h"
#include "game/transcendental/viewing_session.h"
#include "game/transcendental/simulation_broadcast.h"
#include "game/transcendental/cosmos.h"
#include "game/transcendental/cosmic_delta.h"

#include "game/transcendental/step_and_entropy_unpacker.h"

#include "augs/filesystem/file.h"

#include "setups.h"
#include "game/transcendental/network_commands.h"

#include "augs/network/reliable_channel.h"

#include "augs/misc/randomization.h"

#include "application/web_daemon/session_report.h"

#include "augs/templates.h"

#include "game/detail/position_scripts.h"

void server_setup::wait_for_listen_server() {
	std::unique_lock<std::mutex> lck(mtx);
	while (!server_ready) cv.wait(lck);
}

std::string server_setup::endpoint::nick_and_ip() const {
	return typesafe_sprintf("%x (%x)", nickname, addr.get_readable_ip());
}

server_setup::endpoint& server_setup::get_endpoint(const augs::network::endpoint_address addr) {
	return *find_in(endpoints, addr);
}

void server_setup::deinit_endpoint(endpoint& end, const bool gracefully) {
	LOG("%x disconnected.", end.nick_and_ip());

	if (hypersomnia[end.controlled_entity].alive())
		scene.free_character(end.controlled_entity);

	if(!gracefully)
		choose_server(end.addr).forceful_disconnect(end.addr);
	else
		choose_server(end.addr).disconnect(end.addr);
}

void server_setup::deinit_endpoint(const augs::network::endpoint_address addr, const bool gracefully) {
	deinit_endpoint(get_endpoint(addr), gracefully);
}

void server_setup::disconnect(const augs::network::endpoint_address addr, const bool gracefully) {
	deinit_endpoint(addr, gracefully);
	remove_element(endpoints, addr);
}

augs::network::server& server_setup::choose_server(augs::network::endpoint_address addr) {
	if (serv.has_endpoint(addr)) {
		return serv;
	}

	ensure(alternative_serv.has_endpoint(addr));
	return alternative_serv;
}

void server_setup::process(game_window& window, const bool start_alternative_server) {
	const auto& cfg = window.config;

	session_report rep;

	cosmos hypersomnia_last_snapshot(3000);

	cosmos initial_hypersomnia(3000);
	scene_managers::networked_testbed_server().populate_world_with_entities(initial_hypersomnia);

	step_and_entropy_unpacker input_unpacker;

	const bool detailed_step_log = cfg.tickrate <= 2;

	if (!hypersomnia.load_from_file("server_save.state")) {
		hypersomnia.set_fixed_delta(augs::fixed_delta(cfg.tickrate));
		scene.populate_world_with_entities(hypersomnia);
	}

	input_unpacker.try_to_load_or_save_new_session("server_sessions/", "server_recorded.inputs");

	simulation_broadcast server_sim;

	const bool is_replaying = input_unpacker.player.is_replaying();
	const bool launch_webserver = !is_replaying && cfg.server_launch_http_daemon;

	bool daemon_online = false;

	if (launch_webserver)
		daemon_online = rep.start_daemon(cfg.server_http_daemon_html_file_path, cfg.server_http_daemon_port);

	if (is_replaying || serv.listen(cfg.server_port, 32))
		LOG("Listen server setup successful.");
	else
		LOG("Failed to setup a listen server.");

	if (start_alternative_server) {
		if (is_replaying || alternative_serv.listen(cfg.alternative_port, 32))
			LOG("Alternative listen server setup successful.");
		else
			LOG("Failed to setup an alternative listen server.");
	}

	{
		std::unique_lock<std::mutex> lck(mtx);
		server_ready = true;
		cv.notify_all();
	}

	bool resubstantiate = false;

	input_unpacker.timer.reset_timer();

	randomization test_entropy_randomizer;

	while (!should_quit) {
		augs::machine_entropy new_entropy;

		new_entropy.local = window.collect_entropy();
		new_entropy.remote = serv.collect_entropy();

		if (start_alternative_server) {
			augs::machine_entropy alt_entropy;
			alt_entropy.remote = alternative_serv.collect_entropy();

			new_entropy += alt_entropy;
		}

		process_exit_key(new_entropy.local);

		input_unpacker.control(new_entropy);

		auto steps = input_unpacker.unpack_steps(hypersomnia.get_fixed_delta());

		for (auto& s : steps) {
			if (detailed_step_log) {
				LOG("Server step");
			}

			for (auto& net_event : s.total_entropy.remote) {
				if (detailed_step_log) {
					LOG("Server netevent");
				}

				const auto& address = net_event.address;

				bool should_disconnect = false;

				if (net_event.message_type == augs::network::message::type::CONNECT) {
					LOG("%x connected to server on port %x.", address.get_readable_ip(), address.get_port());

					endpoint new_endpoint;
					new_endpoint.addr = net_event.address;
					new_endpoint.commands.set_lower_limit(static_cast<size_t>(cfg.client_commands_jitter_buffer_ms) / hypersomnia.get_fixed_delta().in_milliseconds());
					endpoints.push_back(new_endpoint);
				}

				if (net_event.message_type == augs::network::message::type::DISCONNECT) {
					LOG("Disconnecting due to net event.");
					should_disconnect = true;
				}

				if (net_event.message_type == augs::network::message::type::RECEIVE) {
					auto& stream = net_event.payload;
					auto& endpoint = *find_in(endpoints, address);

					auto to_skip = net_event.messages_to_skip;

					while (stream.get_unread_bytes() > 0) {
						const bool should_skip = to_skip > 0;

						if (should_skip)
							--to_skip;

						network_command command;
						augs::read_object(stream, command);

						if (detailed_step_log && !should_skip)
							LOG("Server received command: %x", int(command));

						switch (command) {
						case network_command::CLIENT_WELCOME_MESSAGE: {
							std::string read_nickname;
							augs::read_object(stream, read_nickname);

							if (!should_skip) {
								if (endpoint.sent_welcome_message) {
									LOG("Welcome message was resent. Disconnecting.");
									should_disconnect = true;
								}
								else {
									endpoint.sent_welcome_message = true;
									endpoint.nickname = read_nickname;

									if (!should_skip) {
										LOG("%x chose nickname %x.", address.get_readable_ip(), endpoint.nickname);

										auto& complete_state = initial_hypersomnia.reserved_memory_for_serialization;
										complete_state.reset_write_pos();

										augs::write_object(complete_state, network_command::COMPLETE_STATE);

										cosmic_delta::encode(initial_hypersomnia, hypersomnia, complete_state);

										hypersomnia.complete_resubstantiation();
										resubstantiate = true;

										endpoint.controlled_entity = scene.assign_new_character();
										augs::write_object(complete_state, hypersomnia[endpoint.controlled_entity].get_guid());

										choose_server(address).send_reliable(complete_state, address);
									}
								}
							}
						}

							break;

						case network_command::CLIENT_REQUESTED_ENTROPY: {
							if (!endpoint.sent_welcome_message) {
								should_disconnect = true;
							}
							else {
								guid_mapped_entropy result;
								augs::read_object(stream, result);

								if (!should_skip)
									//endpoint.commands.push_back(result);
									endpoint.commands.acquire_new_command(result);
							}
						}
							break;
						default:
							LOG("Server received invalid command: %x", int(command)); stream = augs::stream();
							break;
						}
					}
				}

				if (should_disconnect) {
					disconnect(address);
				}
			}

			guid_mapped_entropy total_unpacked_entropy;

			if (cfg.debug_randomize_entropies_in_client_setup) {
				for (size_t i = 1; i < scene.characters.size(); ++i) {
					if (test_entropy_randomizer.randval(0u, cfg.debug_randomize_entropies_in_client_setup_once_every_steps) == 0u) {
						const unsigned which = test_entropy_randomizer.randval(0, 4);

						entity_intent new_intent;

						switch (which) {
						case 0: new_intent.intent = intent_type::MOVE_BACKWARD; break;
						case 1: new_intent.intent = intent_type::MOVE_FORWARD; break;
						case 2: new_intent.intent = intent_type::MOVE_LEFT; break;
						case 3: new_intent.intent = intent_type::MOVE_RIGHT; break;
						//case 4: new_intent.intent = intent_type::CROSSHAIR_PRIMARY_ACTION; break;
						}

						new_intent.pressed_flag = test_entropy_randomizer.randval(0, 1) == 0;

						total_unpacked_entropy.entropy_per_entity[hypersomnia[scene.characters[i].id].get_guid()].push_back(new_intent);
					}
				}
			}

			erase_remove(endpoints, [this](endpoint& e) {
				if (choose_server(e.addr).has_timed_out(e.addr, hypersomnia.get_fixed_delta().in_milliseconds())) {
					LOG("%x has timed out. Disconnecting.", e.nick_and_ip());
					deinit_endpoint(e);
					return true;
				}

				return false;
			});

			for (auto& e : endpoints) {
				guid_mapped_entropy maybe_new_client_commands;
				auto& next_command = e.next_command;
				next_command = step_packaged_for_network();

				if (e.commands.unpack_new_command(maybe_new_client_commands)) {
					total_unpacked_entropy += maybe_new_client_commands;

					e.next_command.next_client_commands_accepted = true;
				}
			}

			for (auto& e : endpoints) {
				auto& next_command = e.next_command;

				next_command.step_type = step_packaged_for_network::type::NEW_ENTROPY;
				next_command.shall_resubstantiate = resubstantiate;
				next_command.entropy = total_unpacked_entropy;
				augs::stream new_data;
				augs::write_object(new_data, network_command::PACKAGED_STEP);
				augs::write_object(new_data, next_command);

				choose_server(e.addr).post_redundant(new_data, e.addr);
			}

			resubstantiate = false;

			serv.send_pending_redundant();
			if(start_alternative_server) alternative_serv.send_pending_redundant();

			cosmic_entropy id_mapped_entropy(total_unpacked_entropy, hypersomnia);
			scene.step_with_callbacks(id_mapped_entropy, hypersomnia);

			if (daemon_online) {
				std::string this_step_stats;
				const char* whb = "";
				const char* whe = "";

				const char* ipb = "";
				const char* ipe = "";

				this_step_stats += typesafe_sprintf("Uptime: %x%x%x seconds\n", whb, hypersomnia.get_total_time_passed_in_seconds(), whe);
				this_step_stats += typesafe_sprintf("Players online: %x%x%x", whb, endpoints.size(), whe);

				if (endpoints.size() > 0) {
					this_step_stats += "\nPlayer list:\n\n";
				}

				for (size_t i = 0; i < endpoints.size(); ++i) {
					const const_entity_handle character = hypersomnia[endpoints[i].controlled_entity];

					if (character.alive()) {
						auto pos = character.logic_transform().pos;
						auto vel = velocity(character);

						this_step_stats += typesafe_sprintf("#%x%x%x %x (%x%x%x)\nPos: %x%x%x\nVel: %x%x%x", whb, i+1, whe, endpoints[i].nickname, ipb, endpoints[i].addr.get_readable_ip(), ipe, whb, pos, whe, whb, vel, whe);
					}

					this_step_stats += "\n\n";
				}

				this_step_stats = replace_all(this_step_stats, "\n", "\n
");

				rep.fetch_stats(this_step_stats);
			}
		}
	}

	if (!is_replaying)
		rep.stop_daemon();
}<commit_msg>build fix<commit_after>#include <thread>
#include "augs/misc/templated_readwrite.h"
#include "game/bindings/bind_game_and_augs.h"
#include "augs/global_libraries.h"
#include "application/game_window.h"

#include "game/resources/manager.h"

#include "game/scene_managers/resource_setups/all.h"

#include "game/transcendental/types_specification/all_component_includes.h"
#include "game/transcendental/viewing_session.h"
#include "game/transcendental/simulation_broadcast.h"
#include "game/transcendental/cosmos.h"
#include "game/transcendental/cosmic_delta.h"

#include "game/transcendental/step_and_entropy_unpacker.h"

#include "augs/filesystem/file.h"

#include "server_setup.h"
#include "game/transcendental/network_commands.h"

#include "augs/network/reliable_channel.h"

#include "augs/misc/randomization.h"

#include "application/web_daemon/session_report.h"

#include "augs/templates.h"

#include "game/detail/position_scripts.h"

void server_setup::wait_for_listen_server() {
	std::unique_lock<std::mutex> lck(mtx);
	while (!server_ready) cv.wait(lck);
}

std::string server_setup::endpoint::nick_and_ip() const {
	return typesafe_sprintf("%x (%x)", nickname, addr.get_readable_ip());
}

server_setup::endpoint& server_setup::get_endpoint(const augs::network::endpoint_address addr) {
	return *find_in(endpoints, addr);
}

void server_setup::deinit_endpoint(endpoint& end, const bool gracefully) {
	LOG("%x disconnected.", end.nick_and_ip());

	if (hypersomnia[end.controlled_entity].alive())
		scene.free_character(end.controlled_entity);

	if(!gracefully)
		choose_server(end.addr).forceful_disconnect(end.addr);
	else
		choose_server(end.addr).disconnect(end.addr);
}

void server_setup::deinit_endpoint(const augs::network::endpoint_address addr, const bool gracefully) {
	deinit_endpoint(get_endpoint(addr), gracefully);
}

void server_setup::disconnect(const augs::network::endpoint_address addr, const bool gracefully) {
	deinit_endpoint(addr, gracefully);
	remove_element(endpoints, addr);
}

augs::network::server& server_setup::choose_server(augs::network::endpoint_address addr) {
	if (serv.has_endpoint(addr)) {
		return serv;
	}

	ensure(alternative_serv.has_endpoint(addr));
	return alternative_serv;
}

void server_setup::process(game_window& window, const bool start_alternative_server) {
	const auto& cfg = window.config;

	session_report rep;

	cosmos hypersomnia_last_snapshot(3000);

	cosmos initial_hypersomnia(3000);
	scene_managers::networked_testbed_server().populate_world_with_entities(initial_hypersomnia);

	step_and_entropy_unpacker input_unpacker;

	const bool detailed_step_log = cfg.tickrate <= 2;

	if (!hypersomnia.load_from_file("server_save.state")) {
		hypersomnia.set_fixed_delta(augs::fixed_delta(cfg.tickrate));
		scene.populate_world_with_entities(hypersomnia);
	}

	input_unpacker.try_to_load_or_save_new_session("server_sessions/", "server_recorded.inputs");

	simulation_broadcast server_sim;

	const bool is_replaying = input_unpacker.player.is_replaying();
	const bool launch_webserver = !is_replaying && cfg.server_launch_http_daemon;

	bool daemon_online = false;

	if (launch_webserver)
		daemon_online = rep.start_daemon(cfg.server_http_daemon_html_file_path, cfg.server_http_daemon_port);

	if (is_replaying || serv.listen(cfg.server_port, 32))
		LOG("Listen server setup successful.");
	else
		LOG("Failed to setup a listen server.");

	if (start_alternative_server) {
		if (is_replaying || alternative_serv.listen(cfg.alternative_port, 32))
			LOG("Alternative listen server setup successful.");
		else
			LOG("Failed to setup an alternative listen server.");
	}

	{
		std::unique_lock<std::mutex> lck(mtx);
		server_ready = true;
		cv.notify_all();
	}

	bool resubstantiate = false;

	input_unpacker.timer.reset_timer();

	randomization test_entropy_randomizer;

	while (!should_quit) {
		augs::machine_entropy new_entropy;

		new_entropy.local = window.collect_entropy();
		new_entropy.remote = serv.collect_entropy();

		if (start_alternative_server) {
			augs::machine_entropy alt_entropy;
			alt_entropy.remote = alternative_serv.collect_entropy();

			new_entropy += alt_entropy;
		}

		process_exit_key(new_entropy.local);

		input_unpacker.control(new_entropy);

		auto steps = input_unpacker.unpack_steps(hypersomnia.get_fixed_delta());

		for (auto& s : steps) {
			if (detailed_step_log) {
				LOG("Server step");
			}

			for (auto& net_event : s.total_entropy.remote) {
				if (detailed_step_log) {
					LOG("Server netevent");
				}

				const auto& address = net_event.address;

				bool should_disconnect = false;

				if (net_event.message_type == augs::network::message::type::CONNECT) {
					LOG("%x connected to server on port %x.", address.get_readable_ip(), address.get_port());

					endpoint new_endpoint;
					new_endpoint.addr = net_event.address;
					new_endpoint.commands.set_lower_limit(static_cast<size_t>(cfg.client_commands_jitter_buffer_ms) / hypersomnia.get_fixed_delta().in_milliseconds());
					endpoints.push_back(new_endpoint);
				}

				if (net_event.message_type == augs::network::message::type::DISCONNECT) {
					LOG("Disconnecting due to net event.");
					should_disconnect = true;
				}

				if (net_event.message_type == augs::network::message::type::RECEIVE) {
					auto& stream = net_event.payload;
					auto& endpoint = *find_in(endpoints, address);

					auto to_skip = net_event.messages_to_skip;

					while (stream.get_unread_bytes() > 0) {
						const bool should_skip = to_skip > 0;

						if (should_skip)
							--to_skip;

						network_command command;
						augs::read_object(stream, command);

						if (detailed_step_log && !should_skip)
							LOG("Server received command: %x", int(command));

						switch (command) {
						case network_command::CLIENT_WELCOME_MESSAGE: {
							std::string read_nickname;
							augs::read_object(stream, read_nickname);

							if (!should_skip) {
								if (endpoint.sent_welcome_message) {
									LOG("Welcome message was resent. Disconnecting.");
									should_disconnect = true;
								}
								else {
									endpoint.sent_welcome_message = true;
									endpoint.nickname = read_nickname;

									if (!should_skip) {
										LOG("%x chose nickname %x.", address.get_readable_ip(), endpoint.nickname);

										auto& complete_state = initial_hypersomnia.reserved_memory_for_serialization;
										complete_state.reset_write_pos();

										augs::write_object(complete_state, network_command::COMPLETE_STATE);

										cosmic_delta::encode(initial_hypersomnia, hypersomnia, complete_state);

										hypersomnia.complete_resubstantiation();
										resubstantiate = true;

										endpoint.controlled_entity = scene.assign_new_character();
										augs::write_object(complete_state, hypersomnia[endpoint.controlled_entity].get_guid());

										choose_server(address).send_reliable(complete_state, address);
									}
								}
							}
						}

							break;

						case network_command::CLIENT_REQUESTED_ENTROPY: {
							if (!endpoint.sent_welcome_message) {
								should_disconnect = true;
							}
							else {
								guid_mapped_entropy result;
								augs::read_object(stream, result);

								if (!should_skip)
									//endpoint.commands.push_back(result);
									endpoint.commands.acquire_new_command(result);
							}
						}
							break;
						default:
							LOG("Server received invalid command: %x", int(command)); stream = augs::stream();
							break;
						}
					}
				}

				if (should_disconnect) {
					disconnect(address);
				}
			}

			guid_mapped_entropy total_unpacked_entropy;

			if (cfg.debug_randomize_entropies_in_client_setup) {
				for (size_t i = 1; i < scene.characters.size(); ++i) {
					if (test_entropy_randomizer.randval(0u, cfg.debug_randomize_entropies_in_client_setup_once_every_steps) == 0u) {
						const unsigned which = test_entropy_randomizer.randval(0, 4);

						entity_intent new_intent;

						switch (which) {
						case 0: new_intent.intent = intent_type::MOVE_BACKWARD; break;
						case 1: new_intent.intent = intent_type::MOVE_FORWARD; break;
						case 2: new_intent.intent = intent_type::MOVE_LEFT; break;
						case 3: new_intent.intent = intent_type::MOVE_RIGHT; break;
						//case 4: new_intent.intent = intent_type::CROSSHAIR_PRIMARY_ACTION; break;
						}

						new_intent.pressed_flag = test_entropy_randomizer.randval(0, 1) == 0;

						total_unpacked_entropy.entropy_per_entity[hypersomnia[scene.characters[i].id].get_guid()].push_back(new_intent);
					}
				}
			}

			erase_remove(endpoints, [this](endpoint& e) {
				if (choose_server(e.addr).has_timed_out(e.addr, hypersomnia.get_fixed_delta().in_milliseconds())) {
					LOG("%x has timed out. Disconnecting.", e.nick_and_ip());
					deinit_endpoint(e);
					return true;
				}

				return false;
			});

			for (auto& e : endpoints) {
				guid_mapped_entropy maybe_new_client_commands;
				auto& next_command = e.next_command;
				next_command = step_packaged_for_network();

				if (e.commands.unpack_new_command(maybe_new_client_commands)) {
					total_unpacked_entropy += maybe_new_client_commands;

					e.next_command.next_client_commands_accepted = true;
				}
			}

			for (auto& e : endpoints) {
				auto& next_command = e.next_command;

				next_command.step_type = step_packaged_for_network::type::NEW_ENTROPY;
				next_command.shall_resubstantiate = resubstantiate;
				next_command.entropy = total_unpacked_entropy;
				augs::stream new_data;
				augs::write_object(new_data, network_command::PACKAGED_STEP);
				augs::write_object(new_data, next_command);

				choose_server(e.addr).post_redundant(new_data, e.addr);
			}

			resubstantiate = false;

			serv.send_pending_redundant();
			if(start_alternative_server) alternative_serv.send_pending_redundant();

			cosmic_entropy id_mapped_entropy(total_unpacked_entropy, hypersomnia);
			scene.step_with_callbacks(id_mapped_entropy, hypersomnia);

			if (daemon_online) {
				std::string this_step_stats;
				const char* whb = "";
				const char* whe = "";

				const char* ipb = "";
				const char* ipe = "";

				this_step_stats += typesafe_sprintf("Uptime: %x%x%x seconds\n", whb, hypersomnia.get_total_time_passed_in_seconds(), whe);
				this_step_stats += typesafe_sprintf("Players online: %x%x%x", whb, endpoints.size(), whe);

				if (endpoints.size() > 0) {
					this_step_stats += "\nPlayer list:\n\n";
				}

				for (size_t i = 0; i < endpoints.size(); ++i) {
					const const_entity_handle character = hypersomnia[endpoints[i].controlled_entity];

					if (character.alive()) {
						auto pos = character.logic_transform().pos;
						auto vel = velocity(character);

						this_step_stats += typesafe_sprintf("#%x%x%x %x (%x%x%x)\nPos: %x%x%x\nVel: %x%x%x", whb, i+1, whe, endpoints[i].nickname, ipb, endpoints[i].addr.get_readable_ip(), ipe, whb, pos, whe, whb, vel, whe);
					}

					this_step_stats += "\n\n";
				}

				this_step_stats = replace_all(this_step_stats, "\n", "\n
");

				rep.fetch_stats(this_step_stats);
			}
		}
	}

	if (!is_replaying)
		rep.stop_daemon();
}<|endoftext|>


<commit_before>

#include <pcap.h>
#include <stdio.h>
#include <poll.h>

#include <vector>
#include <queue>
#include <algorithm>

#include <slankdev/util.h>
#include <slankdev/ncurses.h>
#include <slankdev/exception.h>
#include <slankdev/net/protocol.h>

class Packet {
public:
    uint8_t buf[2000];
    size_t   len;
    uint64_t time;
    size_t   number;

    Packet(const void* p, size_t l, uint64_t t, size_t n) :
        len(l), time(t), number(n)
    {
        memcpy(buf, p, len);
    }
    std::string line()
    {
        using namespace slankdev;
        std::string source;
        std::string dest;
        std::string proto;

        ether* eth = reinterpret_cast<ether*>(buf);

        char str[1000];
        sprintf(str, "%5zd %-13ld %-20s %-20s %6s %5zd %-10s" , number, time,
                eth->src.to_string().c_str(),
                eth->dst.to_string().c_str(),
                "protocol", len, "summry");
        return str;
    }
};

class pane {
protected:
    size_t current_x;
    size_t current_y;
    slankdev::ncurses& screen;
public:
    const size_t x;
    const size_t y;
    const size_t w;
    const size_t h;
    pane(size_t ix, size_t iy, size_t iw, size_t ih, slankdev::ncurses& scr) :
        x(ix), y(iy), w(iw), h(ih), current_x(ix), current_y(iy), screen(scr) {}
    template <class... Arg>
    void println(const char* fmt, Arg... arg)
    {
        screen.mvprintw(current_y++, current_x, fmt, arg...);
        current_x = x;
    }
    template <class... Arg>
    void println_hl(const char* fmt, Arg... arg)
    {
        attron(A_REVERSE);
        screen.mvprintw(current_y++, current_x, fmt, arg...);
        current_x = x;
        attroff(A_REVERSE);
    }
    template <class... Arg>
    void print(const char* fmt, Arg... arg)
    {
        char str[1000];
        sprintf(str, fmt, arg...);
        size_t len = strlen(str);
        screen.mvprintw(current_y, current_x+=len, fmt, arg...);
    }
    void putc(char c)
    {
        if (c == '\n') {
            current_y ++ ;
            current_x = x;
        } else {
            screen.mvprintw(current_y, current_x++, "%c", c);
        }
    }
};

class Pane_list : public pane {
    ssize_t cursor_index;
    size_t  list_start_index;
public:
    std::vector<Packet> packets;
    ssize_t get_cursor() { return cursor_index; }
    void dec_cursor()
    {
        if (cursor_index-1 < list_start_index) scroll_up();
        if (get_cursor()-1 >= 0) cursor_index--;
    }
    void inc_cursor()
    {
        if (cursor_index+1-list_start_index >= h) scroll_down();
        if (get_cursor()+1 < packets.size()) cursor_index++;
    }
    void scroll_up()   { list_start_index --; }
    void scroll_down() { list_start_index ++; }
    Pane_list(size_t ix, size_t iy, size_t iw, size_t ih,
            slankdev::ncurses& scr) : pane(ix, iy, iw, ih, scr),
            cursor_index(0), list_start_index(0) {}
    void push_packet(const void* packet, struct pcap_pkthdr* hdr)
    {
        static int number = 0;
        packets.emplace_back(packet, hdr->len, hdr->ts.tv_sec, number++);
    }
    void refresh()
    {
        current_x = x;
        current_y = y;
        println("%-5s %-13s %-20s %-20s %-6s %-5s %-10s",
                "No.", "Time", "Source", "Destination",
                "Protocol", "Len", "Info");

        size_t start_idx = list_start_index;
        for (size_t i=start_idx, c=0; i<packets.size() && c<h; i++, c++) {
            if (i == get_cursor())
                println_hl(packets[i].line().c_str());
            else
                println(packets[i].line().c_str());
        }
    }
};

class Pane_detail : public pane {
    ssize_t cursor_index;
    size_t  list_start_index;
public:
    std::vector<std::string> lines;

    ssize_t get_cursor() { return cursor_index; }
    void dec_cursor()
    {
        if (cursor_index-1 < list_start_index) scroll_up();
        if (get_cursor()-1 >= 0) cursor_index--;
    }
    void inc_cursor()
    {
        if (cursor_index+1-list_start_index >= h) scroll_down();
        if (get_cursor()+1 < lines.size()) cursor_index++;
    }
    void scroll_up()   { list_start_index --; }
    void scroll_down() { list_start_index ++; }

    Pane_detail(size_t ix, size_t iy, size_t iw, size_t ih,
            slankdev::ncurses& scr) : pane(ix, iy, iw, ih, scr) {}
    void print_packet_detail(Packet* packet)
    {
        char str[1000];
        sprintf(str, "Packet Detail");
        lines.push_back(str);
        sprintf(str, " + number : %zd ", packet->number);
        lines.push_back(str);
        sprintf(str, " + pointer: %p", packet->buf);
        lines.push_back(str);
        sprintf(str, " + length : %zd", packet->len);
        lines.push_back(str);
        sprintf(str, " + time   : %ld", packet->time);
        lines.push_back(str);
    }
    void refresh()
    {
        current_x = x;
        current_y = y;
        println("Detail pane");
        for (size_t i=0, c=0; i<lines.size() && c<h; i++, c++) {
            if (i == get_cursor())
                println_hl("%s", lines[i].c_str());
            else
                println("%s", lines[i].c_str());
        }
        for (size_t i=0; i<h-lines.size(); i++) {
            for (size_t c=0; c<w; c++) print(" ");
            println("");
        }
    }
};

class Pane_binary : public pane {
    ssize_t cursor_index;
    size_t  list_start_index;
public:
    std::vector<std::string> lines;

    ssize_t get_cursor() { return cursor_index; }
    void dec_cursor()
    {
        if (cursor_index-1 < list_start_index) scroll_up();
        if (get_cursor()-1 >= 0) cursor_index--;
    }
    void inc_cursor()
    {
        if (cursor_index+1-list_start_index >= h) scroll_down();
        if (get_cursor()+1 < lines.size()) cursor_index++;
    }
    void scroll_up()   { list_start_index --; }
    void scroll_down() { list_start_index ++; }

    Pane_binary(size_t ix, size_t iy, size_t iw, size_t ih,
            slankdev::ncurses& scr) : pane(ix, iy, iw, ih, scr) {}
    void hex(Packet* packet)
    {
        lines.clear();

        const void* buffer = packet->buf;
        size_t bufferlen   = packet->len;
        char str[1000];

        const uint8_t *data = reinterpret_cast<const uint8_t*>(buffer);
        size_t row = 0;
        std::string line;
        while (bufferlen > 0) {
            line.clear();

            sprintf(str, " %04zx:   ", row);
            line += str;

            size_t n;
            if (bufferlen < 16) n = bufferlen;
            else                n = 16;

            for (size_t i = 0; i < n; i++) {
                if (i == 8) { line += " "; }
                sprintf(str, " %02x", data[i]);
                line += str;
            }
            for (size_t i = n; i < 16; i++) { line += "   "; }
            line += "   ";
            for (size_t i = 0; i < n; i++) {
                if (i == 8) { line += "  "; }
                uint8_t c = data[i];
                if (!(0x20 <= c && c <= 0x7e)) c = '.';
                sprintf(str, "%c", c);
                line += str;
            }
            println("");
            lines.push_back(line);
            bufferlen -= n;
            data += n;
            row  += n;
        }
    }
    void refresh()
    {
        current_x = x;
        current_y = y;
        for (size_t i=0, c=0; i<lines.size() && c<h; i++, c++) {
            if (i == get_cursor())
                println_hl("%s", lines[i].c_str());
            else
                println("%s", lines[i].c_str());
        }
        for (size_t i=0; i<h-lines.size(); i++) {
            for (size_t c=0; c<w; c++) print(" ");
            println("");
        }
    }
};

enum cursor_state {
    LIST,
    DETAIL,
    BINARY,
};

class Statusline {
    const size_t x;
    const size_t y;
    const size_t w;
    const cursor_state& state;
public:
    Statusline(size_t ix, size_t iy, size_t iw, cursor_state& c)
        : x(ix), y(iy), w(iw), state(c) {}
    const char* state2str(cursor_state s)
    {
        switch (s) {
            case LIST:   return "LIST   ";
            case DETAIL: return "DETAIL ";
            case BINARY: return "BINARY ";
            default :    return "UNKNOWN";
        }
    }
    void refresh()
    {
        mvprintw(y, x, "[CUISHARK] pane=%s", state2str(state));
    }
};

size_t a(size_t h) { return (h-1) % 3; }
size_t m(size_t h) { return ((h-1)-((h-1)%3))/3; }
#define H screen.geth()

class display {
    slankdev::ncurses screen;
    pcap_t *handle;
    cursor_state cstate;
public:
    Pane_list   pane_list;
    Pane_detail pane_detail;
    Pane_binary pane_binary;
    Statusline statusline;

    display() :
        cstate(LIST),
        pane_list  (0, 0          , screen.getw(), a(H)+m(H), screen),
        pane_detail(0, a(H)+m(H)  , screen.getw(), m(H)     , screen),
        pane_binary(0, a(H)+2*m(H), screen.getw(), m(H)     , screen),
        statusline (0, a(H)+3*m(H), screen.getw(), cstate)
    {
        char errbuf[PCAP_ERRBUF_SIZE];
        handle = pcap_open_live("lo", BUFSIZ, 0, 0, errbuf);
        // handle = pcap_open_offline("in.pcap", errbuf);
        if (handle == NULL) {
            throw slankdev::exception("pcap_open_live");
        }
        noecho();
        screen.refresh();
    }
    ~display() { pcap_close(handle); }
    void charnge_cstate()
    {
        switch (cstate) {
            case LIST  : cstate = DETAIL; break;
            case DETAIL: cstate = BINARY; break;
            case BINARY: cstate = LIST  ; break;
            default : throw slankdev::exception("UNKNOWN state");
        }
    }
    void press_j()
    {
        switch (cstate) {
            case LIST  : pane_list.inc_cursor()  ; break;
            case DETAIL: pane_detail.inc_cursor(); break;
            case BINARY: pane_binary.inc_cursor(); break;
            defaut: throw slankdev::exception("UNknown state");
        }
    }
    void press_k()
    {
        switch (cstate) {
            case LIST  : pane_list.dec_cursor()  ; break;
            case DETAIL: pane_detail.dec_cursor(); break;
            case BINARY: pane_binary.dec_cursor(); break;
            defaut: throw slankdev::exception("UNknown state");
        }
    }
    void press_enter()
    {
        switch (cstate) {
            case LIST:
            {
                if (pane_list.packets.empty()) return;
                Packet* pack = &pane_list.packets[pane_list.get_cursor()];
                pane_detail.print_packet_detail(pack);
                pane_binary.hex(pack);
                break;
            }
            case DETAIL:
                break;
            case BINARY:
                break;
            defaut:
                throw slankdev::exception("UNknown state");
                break;

        }
    }
    void view_help()
    {
        size_t x = 0;
        size_t y = 0;
        screen.mvprintw(y++, x, "                                                    ");
        screen.mvprintw(y++, x, "    CuiShark version 0.0                            ");
        screen.mvprintw(y++, x, "    Copyright 2017-2020 Hiroki SHIROKURA.           ");
        screen.mvprintw(y++, x, "                                                    ");
        screen.mvprintw(y++, x, "    Avalable Keyboard commands are below.           ");
        screen.mvprintw(y++, x, "    These are Vi-like key-bind because I'm vimmer.  ");
        screen.mvprintw(y++, x, "                                                    ");
        screen.mvprintw(y++, x, "    Commands                                        ");
        screen.mvprintw(y++, x, "    j      :  down                                  ");
        screen.mvprintw(y++, x, "    k      :  up                                    ");
        screen.mvprintw(y++, x, "    tab    :  switch pane                           ");
        screen.mvprintw(y++, x, "    enter  :  select                                ");
        screen.mvprintw(y++, x, "    ?      :  view help                             ");
        screen.mvprintw(y++, x, "    C-c    :  exit                                  ");
        screen.mvprintw(y++, x, "                                                    ");
        screen.getchar();
    }
    void dispatch()
    {
        struct pollfd fds[2];
        fds[0].fd = pcap_get_selectable_fd(handle);
        fds[0].events = POLLIN;
        fds[1].fd = fileno(stdin);
        fds[1].events = POLLIN;
        while (1) {
            if (poll(fds, 2, 100)) {

                if (fds[0].revents & POLLIN) {
                    struct pcap_pkthdr header;
                    const u_char *packet;
                    packet = pcap_next(handle, &header);
                    pane_list.push_packet(packet, &header);
                }

                if (fds[1].revents & POLLIN) {
                    int c = screen.getchar();
                    switch (c) {
                        case 'j':
                            press_j();
                            break;
                        case 'k':
                            press_k();
                            break;
                        case '\t':
                            charnge_cstate();
                            break;
                        case '\n':
                            press_enter();
                            break;
                        case '?':
                            view_help();
                            break;
                    }
                }
            }
            refresh();
        }
    }
    void refresh()
    {
        pane_list.refresh();
        pane_detail.refresh();
        pane_binary.refresh();
        statusline.refresh();
        screen.refresh();
    }
};

int main(int argc, char *argv[])
{
    display dsp0;
    dsp0.dispatch();
}

<commit_msg>Refact<commit_after>

#include <pcap.h>
#include <stdio.h>
#include <poll.h>

#include <vector>
#include <queue>
#include <algorithm>

#include <slankdev/util.h>
#include <slankdev/ncurses.h>
#include <slankdev/exception.h>
#include <slankdev/net/protocol.h>

class Packet {
public:
    uint8_t buf[2000];
    size_t   len;
    uint64_t time;
    size_t   number;

    Packet(const void* p, size_t l, uint64_t t, size_t n) :
        len(l), time(t), number(n)
    {
        memcpy(buf, p, len);
    }
    std::string line()
    {
        using namespace slankdev;
        std::string source;
        std::string dest;
        std::string proto;

        ether* eth = reinterpret_cast<ether*>(buf);

        char str[1000];
        sprintf(str, "%5zd %-13ld %-20s %-20s %6s %5zd %-10s" , number, time,
                eth->src.to_string().c_str(),
                eth->dst.to_string().c_str(),
                "protocol", len, "summry");
        return str;
    }
};

class pane {
protected:
    size_t current_x;
    size_t current_y;
    slankdev::ncurses& screen;
public:
    const size_t x;
    const size_t y;
    const size_t w;
    const size_t h;
    pane(size_t ix, size_t iy, size_t iw, size_t ih, slankdev::ncurses& scr) :
        x(ix), y(iy), w(iw), h(ih), current_x(ix), current_y(iy), screen(scr) {}
    template <class... Arg>
    void println(const char* fmt, Arg... arg)
    {
        screen.mvprintw(current_y++, current_x, fmt, arg...);
        current_x = x;
    }
    template <class... Arg>
    void println_hl(const char* fmt, Arg... arg)
    {
        attron(A_REVERSE);
        screen.mvprintw(current_y++, current_x, fmt, arg...);
        current_x = x;
        attroff(A_REVERSE);
    }
    template <class... Arg>
    void print(const char* fmt, Arg... arg)
    {
        char str[1000];
        sprintf(str, fmt, arg...);
        size_t len = strlen(str);
        screen.mvprintw(current_y, current_x+=len, fmt, arg...);
    }
    void putc(char c)
    {
        if (c == '\n') {
            current_y ++ ;
            current_x = x;
        } else {
            screen.mvprintw(current_y, current_x++, "%c", c);
        }
    }
};

class Pane_list : public pane {
    ssize_t cursor_index;
    size_t  list_start_index;
public:
    std::vector<Packet> packets;
    ssize_t get_cursor() { return cursor_index; }
    void dec_cursor()
    {
        if (cursor_index-1 < list_start_index) scroll_up();
        if (get_cursor()-1 >= 0) cursor_index--;
    }
    void inc_cursor()
    {
        if (cursor_index+1-list_start_index >= h) scroll_down();
        if (get_cursor()+1 < packets.size()) cursor_index++;
    }
    void scroll_up()   { list_start_index --; }
    void scroll_down() { list_start_index ++; }
    Pane_list(size_t ix, size_t iy, size_t iw, size_t ih,
            slankdev::ncurses& scr) : pane(ix, iy, iw, ih, scr),
            cursor_index(0), list_start_index(0) {}
    void push_packet(const void* packet, struct pcap_pkthdr* hdr)
    {
        static int number = 0;
        packets.emplace_back(packet, hdr->len, hdr->ts.tv_sec, number++);
    }
    void refresh()
    {
        current_x = x;
        current_y = y;
        println("%-5s %-13s %-20s %-20s %-6s %-5s %-10s",
                "No.", "Time", "Source", "Destination",
                "Protocol", "Len", "Info");

        size_t start_idx = list_start_index;
        for (size_t i=start_idx, c=0; i<packets.size() && c<h; i++, c++) {
            if (i == get_cursor())
                println_hl(packets[i].line().c_str());
            else
                println(packets[i].line().c_str());
        }
    }
};

class Pane_detail : public pane {
    ssize_t cursor_index;
    size_t  list_start_index;
public:
    std::vector<std::string> lines;

    ssize_t get_cursor() { return cursor_index; }
    void dec_cursor()
    {
        if (cursor_index-1 < list_start_index) scroll_up();
        if (get_cursor()-1 >= 0) cursor_index--;
    }
    void inc_cursor()
    {
        if (cursor_index+1-list_start_index >= h) scroll_down();
        if (get_cursor()+1 < lines.size()) cursor_index++;
    }
    void scroll_up()   { list_start_index --; }
    void scroll_down() { list_start_index ++; }

    Pane_detail(size_t ix, size_t iy, size_t iw, size_t ih,
            slankdev::ncurses& scr) : pane(ix, iy, iw, ih, scr) {}
    void print_packet_detail(Packet* packet)
    {
        char str[1000];
        sprintf(str, "Packet Detail");
        lines.push_back(str);
        sprintf(str, " + number : %zd ", packet->number);
        lines.push_back(str);
        sprintf(str, " + pointer: %p", packet->buf);
        lines.push_back(str);
        sprintf(str, " + length : %zd", packet->len);
        lines.push_back(str);
        sprintf(str, " + time   : %ld", packet->time);
        lines.push_back(str);
    }
    void refresh()
    {
        current_x = x;
        current_y = y;
        for (size_t i=0, c=0; i<lines.size() && c<h; i++, c++) {
            if (i == get_cursor())
                println_hl("%s", lines[i].c_str());
            else
                println("%s", lines[i].c_str());
        }
        for (size_t i=0; i<h-lines.size(); i++) {
            for (size_t c=0; c<w; c++) print(" ");
            println("");
        }
    }
};

class Pane_binary : public pane {
    ssize_t cursor_index;
    size_t  list_start_index;
public:
    std::vector<std::string> lines;

    ssize_t get_cursor() { return cursor_index; }
    void dec_cursor()
    {
        if (cursor_index-1 < list_start_index) scroll_up();
        if (get_cursor()-1 >= 0) cursor_index--;
    }
    void inc_cursor()
    {
        if (cursor_index+1-list_start_index >= h) scroll_down();
        if (get_cursor()+1 < lines.size()) cursor_index++;
    }
    void scroll_up()   { list_start_index --; }
    void scroll_down() { list_start_index ++; }

    Pane_binary(size_t ix, size_t iy, size_t iw, size_t ih,
            slankdev::ncurses& scr) : pane(ix, iy, iw, ih, scr) {}
    void hex(Packet* packet)
    {
        lines.clear();

        const void* buffer = packet->buf;
        size_t bufferlen   = packet->len;
        char str[1000];

        const uint8_t *data = reinterpret_cast<const uint8_t*>(buffer);
        size_t row = 0;
        std::string line;
        while (bufferlen > 0) {
            line.clear();

            sprintf(str, " %04zx:   ", row);
            line += str;

            size_t n;
            if (bufferlen < 16) n = bufferlen;
            else                n = 16;

            for (size_t i = 0; i < n; i++) {
                if (i == 8) { line += " "; }
                sprintf(str, " %02x", data[i]);
                line += str;
            }
            for (size_t i = n; i < 16; i++) { line += "   "; }
            line += "   ";
            for (size_t i = 0; i < n; i++) {
                if (i == 8) { line += "  "; }
                uint8_t c = data[i];
                if (!(0x20 <= c && c <= 0x7e)) c = '.';
                sprintf(str, "%c", c);
                line += str;
            }
            println("");
            lines.push_back(line);
            bufferlen -= n;
            data += n;
            row  += n;
        }
    }
    void refresh()
    {
        current_x = x;
        current_y = y;
        for (size_t i=0, c=0; i<lines.size() && c<h; i++, c++) {
            if (i == get_cursor())
                println_hl("%s", lines[i].c_str());
            else
                println("%s", lines[i].c_str());
        }
        for (size_t i=0; i<h-lines.size(); i++) {
            for (size_t c=0; c<w; c++) print(" ");
            println("");
        }
    }
};

enum cursor_state {
    LIST,
    DETAIL,
    BINARY,
};

class Statusline {
    const size_t x;
    const size_t y;
    const size_t w;
    const cursor_state& state;
public:
    Statusline(size_t ix, size_t iy, size_t iw, cursor_state& c)
        : x(ix), y(iy), w(iw), state(c) {}
    const char* state2str(cursor_state s)
    {
        switch (s) {
            case LIST:   return "LIST   ";
            case DETAIL: return "DETAIL ";
            case BINARY: return "BINARY ";
            default :    return "UNKNOWN";
        }
    }
    void refresh()
    {
        mvprintw(y, x, "[CUISHARK] pane=%s", state2str(state));
    }
};

size_t a(size_t h) { return (h-1) % 3; }
size_t m(size_t h) { return ((h-1)-((h-1)%3))/3; }
#define H screen.geth()

class display {
    slankdev::ncurses screen;
    pcap_t *handle;
    cursor_state cstate;
public:
    Pane_list   pane_list;
    Pane_detail pane_detail;
    Pane_binary pane_binary;
    Statusline statusline;

    display() :
        cstate(LIST),
        pane_list  (0, 0            , screen.getw(), a(H)+m(H), screen),
        pane_detail(0, a(H)+m(H)+1  , screen.getw(), m(H)     , screen),
        pane_binary(0, a(H)+2*m(H)+1, screen.getw(), m(H)     , screen),
        statusline (0, a(H)+3*m(H)  , screen.getw(), cstate)
    {
        char errbuf[PCAP_ERRBUF_SIZE];
        handle = pcap_open_live("lo", BUFSIZ, 0, 0, errbuf);
        // handle = pcap_open_offline("in.pcap", errbuf);
        if (handle == NULL) {
            throw slankdev::exception("pcap_open_live");
        }
        noecho();
        screen.refresh();
    }
    ~display() { pcap_close(handle); }
    void charnge_cstate()
    {
        switch (cstate) {
            case LIST  : cstate = DETAIL; break;
            case DETAIL: cstate = BINARY; break;
            case BINARY: cstate = LIST  ; break;
            default : throw slankdev::exception("UNKNOWN state");
        }
    }
    void press_j()
    {
        switch (cstate) {
            case LIST  : pane_list.inc_cursor()  ; break;
            case DETAIL: pane_detail.inc_cursor(); break;
            case BINARY: pane_binary.inc_cursor(); break;
            defaut: throw slankdev::exception("UNknown state");
        }
    }
    void press_k()
    {
        switch (cstate) {
            case LIST  : pane_list.dec_cursor()  ; break;
            case DETAIL: pane_detail.dec_cursor(); break;
            case BINARY: pane_binary.dec_cursor(); break;
            defaut: throw slankdev::exception("UNknown state");
        }
    }
    void press_enter()
    {
        switch (cstate) {
            case LIST:
            {
                if (pane_list.packets.empty()) return;
                Packet* pack = &pane_list.packets[pane_list.get_cursor()];
                pane_detail.print_packet_detail(pack);
                pane_binary.hex(pack);
                break;
            }
            case DETAIL:
                break;
            case BINARY:
                break;
            defaut:
                throw slankdev::exception("UNknown state");
                break;

        }
    }
    void view_help()
    {
        size_t x = 0;
        size_t y = 0;
        screen.mvprintw(y++, x, "                                                    ");
        screen.mvprintw(y++, x, "    CuiShark version 0.0                            ");
        screen.mvprintw(y++, x, "    Copyright 2017-2020 Hiroki SHIROKURA.           ");
        screen.mvprintw(y++, x, "                                                    ");
        screen.mvprintw(y++, x, "    Avalable Keyboard commands are below.           ");
        screen.mvprintw(y++, x, "    These are Vi-like key-bind because I'm vimmer.  ");
        screen.mvprintw(y++, x, "                                                    ");
        screen.mvprintw(y++, x, "    Commands                                        ");
        screen.mvprintw(y++, x, "    j      :  down                                  ");
        screen.mvprintw(y++, x, "    k      :  up                                    ");
        screen.mvprintw(y++, x, "    tab    :  switch pane                           ");
        screen.mvprintw(y++, x, "    enter  :  select                                ");
        screen.mvprintw(y++, x, "    ?      :  view help                             ");
        screen.mvprintw(y++, x, "    C-c    :  exit                                  ");
        screen.mvprintw(y++, x, "                                                    ");
        screen.getchar();
    }
    void dispatch()
    {
        struct pollfd fds[2];
        fds[0].fd = pcap_get_selectable_fd(handle);
        fds[0].events = POLLIN;
        fds[1].fd = fileno(stdin);
        fds[1].events = POLLIN;
        while (1) {
            if (poll(fds, 2, 100)) {

                if (fds[0].revents & POLLIN) {
                    struct pcap_pkthdr header;
                    const u_char *packet;
                    packet = pcap_next(handle, &header);
                    pane_list.push_packet(packet, &header);
                }

                if (fds[1].revents & POLLIN) {
                    int c = screen.getchar();
                    switch (c) {
                        case 'j':
                            press_j();
                            break;
                        case 'k':
                            press_k();
                            break;
                        case '\t':
                            charnge_cstate();
                            break;
                        case '\n':
                            press_enter();
                            break;
                        case '?':
                            view_help();
                            break;
                    }
                }
            }
            refresh();
        }
    }
    void refresh()
    {
        pane_list.refresh();
        pane_detail.refresh();
        pane_binary.refresh();
        statusline.refresh();
        screen.refresh();
    }
};

int main(int argc, char *argv[])
{
    display dsp0;
    dsp0.dispatch();
}

<|endoftext|>


<commit_before>#include <cstdlib>

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>

#include "fasta_parser.h"
#include "sa_is.h"
#include "search.h"

struct suffix {
  unsigned int index;
  std::string suffix_string;
};

bool compare(suffix i, suffix j) {
  return i.suffix_string < j.suffix_string ;
}

// Creates a sufix array for the given string using a simple and slow method
void suffix_array(std::string str, std::vector<int> &sa) {
  std::vector<suffix> suffixes;

  for (unsigned int i = 0; i < str.size(); ++i) {
    suffix *s = new suffix;
    s->index = i;
    s->suffix_string = str.substr(i);
    suffixes.push_back(*s);
    delete s;
  }

  std::sort(suffixes.begin(), suffixes.end(), compare);
  for (unsigned int i = 0; i < suffixes.size(); ++i) {
    sa.push_back(suffixes[i].index);
  }
}

int main(int argc, char *argv[]) {

  if(argc != 5) {
    std::cerr << "Usage: " << argv[0] << " <file containing reference string> <file containing query string> <index level of sparseSA, K-SA> <size of minimal match>" << std::endl;
    exit(-1);
  }

  std::ifstream ref_file(argv[1]);
	std::ifstream query_file(argv[2]);

  if(!ref_file.is_open()) {
    std::cerr << "There was a problem openning the file \"" << argv[1] << "\"!\nAborting." << std::endl;
    exit(-2);
  }

  if(!query_file.is_open()) {
    std::cerr << "There was a problem openning the file \"" << argv[2] << "\"!\nAborting." << std::endl;
    exit(-2);
  }

  // Read in reference string (fasta format)
	std::string ref_string;
	std::vector<string> refdescr;
	std::vector<long> startpos;
	fasta_parser(argv[1], ref_string, refdescr, startpos);

  // Read in query string (fasta format)
	std::string query_string;
	std::vector<string> querydescr;
	std::vector<long> q_startpos;
  fasta_parser(argv[2], query_string, querydescr, q_startpos);

  int K = atoi(argv[3]);
  int L = atoi(argv[4]);
  int N = ref_string.length();

  std::vector<int> sa;
  sa.reserve(N);
  bool *types = new bool[N];

  suffix_array(ref_string, sa);
  type_array(ref_string.c_str(), types, N, sizeof(char));

  for (unsigned int i = 0; i < sa.size() ; ++i) {
    std::cout << "[" << i << "]\t" << sa[i] << (types[sa[i]] ? "\tS\t" : "\tL\t")
    << ref_string.substr(sa[i]) << std::endl;
  }

  int *SA = new int[N];
  int *sparseSA = new int[N / K];
  int *sparseISA = new int[N / K];
  int *sparseLCP = new int[N / K];
  short int A_, C_, T_, G_, BROJ;
  A_ = C_ = T_ = G_ = BROJ = 0;
  // Creates Suffix Array using SA_IS algorithm
  sa_is(ref_string.c_str(), SA, N, 256, sizeof(char));
  for (int i = 0; i < N; i++){
	if (ref_string.substr(sa[i])[0] == 'A') A_++;
	if (ref_string.substr(sa[i])[0] == 'C') C_++;
	if (ref_string.substr(sa[i])[0] == 'T') T_++;
	if (ref_string.substr(sa[i])[0] == 'G') G_++;
  }

  sparseSA[0] = SA[0 * K];

  // Generate Sparse Suffix Array, A, C, T, G
  int j =1;
  for (int i = 1; i < N; ++i) {

    if(A_>0){
      sparseSA[j] = SA[i * K  - (K-1)];
      A_ = A_-K;
    }

    else if (C_>0){
      sparseSA[j] = SA[i * K + A_ - (K-1) ];
      C_ = C_-K;
    }

    else if (G_ >0){
      sparseSA[j] = SA[i * K + A_ + C_ + T_  - (K-1)];
      G_ = G_ -K;
    }

    else if (T_>0){
      sparseSA[j] = SA[i * K + A_ + C_  - (K-1)];
      T_ = T_-K;
      cout << T_ << endl;
    }

    else break;

    j++;
	//sparseSA[i] = SA[i * K];
  }

  BROJ = j;

  for(int i = 0; i < j; i++) {
    cout << sparseSA[i] << " ";
  }
  cout << endl;
  // Generate ISA A
  for(int i = 0; i < j; i++) {
		sparseISA[sparseSA[i] % (j-1)] = i;
  }
cout << endl;
  for(int i = 0; i < j; i++) {
    cout << sparseISA[sparseSA[i]] << " ";
  }

  // Generate LCP
  int h = 0;
  for(int i = 0; i < N/K ; i+=K) {
    int m = sparseISA[i];
    if(m==0) {
      sparseLCP[m] = 0;
    }
    else {
      int j = sparseSA[m-1];
      while(i+h < N && j+h < N && ref_string[i+h] == ref_string[j+h]) {
        h++;
      }
      sparseLCP[m] = h;
    }
    h = std::max(0, h - K);
  }

  printf("\nSparse SA: ");
  for (int i = 0; i < N/K; ++i)
    printf("%d ", sparseSA[i]);

  printf("\nSparse ISA: ");
  for (int i = 0; i < N/K; ++i)
    printf("%d ", sparseISA[i]);

  printf("\nSparse LCP: ");
  for (int i = 0; i < N/K; ++i)
    printf("%d ", sparseLCP[i]);
  printf("\n");

  // Search for MEMs:
  printf("\tRef.\tQuery\tLength\n");
  int p0 = 0;
  MEM(p0, ref_string, sparseISA, sparseLCP, sparseSA, query_string, K, N, L);

  return 0;
}

<commit_msg>print mod<commit_after>#include <cstdlib>

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>

#include "fasta_parser.h"
#include "sa_is.h"
#include "search.h"

struct suffix {
  unsigned int index;
  std::string suffix_string;
};

bool compare(suffix i, suffix j) {
  return i.suffix_string < j.suffix_string ;
}

// Creates a sufix array for the given string using a simple and slow method
void suffix_array(std::string str, std::vector<int> &sa) {
  std::vector<suffix> suffixes;

  for (unsigned int i = 0; i < str.size(); ++i) {
    suffix *s = new suffix;
    s->index = i;
    s->suffix_string = str.substr(i);
    suffixes.push_back(*s);
    delete s;
  }

  std::sort(suffixes.begin(), suffixes.end(), compare);
  for (unsigned int i = 0; i < suffixes.size(); ++i) {
    sa.push_back(suffixes[i].index);
  }
}

int main(int argc, char *argv[]) {

  if(argc != 5) {
    std::cerr << "Usage: " << argv[0] << " <file containing reference string> <file containing query string> <index level of sparseSA, K-SA> <size of minimal match>" << std::endl;
    exit(-1);
  }

  std::ifstream ref_file(argv[1]);
	std::ifstream query_file(argv[2]);

  if(!ref_file.is_open()) {
    std::cerr << "There was a problem openning the file \"" << argv[1] << "\"!\nAborting." << std::endl;
    exit(-2);
  }

  if(!query_file.is_open()) {
    std::cerr << "There was a problem openning the file \"" << argv[2] << "\"!\nAborting." << std::endl;
    exit(-2);
  }

  // Read in reference string (fasta format)
	std::string ref_string;
	std::vector<string> refdescr;
	std::vector<long> startpos;
	fasta_parser(argv[1], ref_string, refdescr, startpos);

  // Read in query string (fasta format)
	std::string query_string;
	std::vector<string> querydescr;
	std::vector<long> q_startpos;
  fasta_parser(argv[2], query_string, querydescr, q_startpos);

  int K = atoi(argv[3]);
  int L = atoi(argv[4]);
  int N = ref_string.length();

  std::vector<int> sa;
  sa.reserve(N);
  bool *types = new bool[N];

  suffix_array(ref_string, sa);
  type_array(ref_string.c_str(), types, N, sizeof(char));

  for (unsigned int i = 0; i < sa.size() ; ++i) {
    std::cout << "[" << i << "]\t" << sa[i] << (types[sa[i]] ? "\tS\t" : "\tL\t")
    << ref_string.substr(sa[i]) << std::endl;
  }

  int *SA = new int[N];
  int *sparseSA = new int[N / K];
  int *sparseISA = new int[N / K];
  int *sparseLCP = new int[N / K];
  short int A_, C_, T_, G_, BROJ;
  A_ = C_ = T_ = G_ = BROJ = 0;
  // Creates Suffix Array using SA_IS algorithm
  sa_is(ref_string.c_str(), SA, N, 256, sizeof(char));
  for (int i = 0; i < N; i++){
	if (ref_string.substr(sa[i])[0] == 'A') A_++;
	if (ref_string.substr(sa[i])[0] == 'C') C_++;
	if (ref_string.substr(sa[i])[0] == 'T') T_++;
	if (ref_string.substr(sa[i])[0] == 'G') G_++;
  }

  sparseSA[0] = SA[0 * K];

  // Generate Sparse Suffix Array, A, C, T, G
  int j =1;
  for (int i = 1; i < N; ++i) {

    if(A_>0){
      sparseSA[j] = SA[i * K  - (K-1)];
      A_ = A_-K;
    }

    else if (C_>0){
      sparseSA[j] = SA[i * K + A_ - (K-1) ];
      C_ = C_-K;
    }

    else if (G_ >0){
      sparseSA[j] = SA[i * K + A_ + C_ + T_  - (K-1)];
      G_ = G_ -K;
    }

    else if (T_>0){
      sparseSA[j] = SA[i * K + A_ + C_  - (K-1)];
      T_ = T_-K;
      cout << T_ << endl;
    }

    else break;

    j++;
	//sparseSA[i] = SA[i * K];
  }

  BROJ = j;

  for(int i = 0; i < j; i++) {
    cout << sparseSA[i] << " ";
  }
  cout << endl;
  // Generate ISA A
  for(int i = 0; i < j; i++) {
		sparseISA[sparseSA[i] % (j-1)] = i;
  }
cout << endl;
  for(int i = 0; i < j; i++) {
    cout << sparseISA[sparseSA[i] % (j-1)] << " ";
  }

  // Generate LCP
  int h = 0;
  for(int i = 0; i < N/K ; i+=K) {
    int m = sparseISA[i];
    if(m==0) {
      sparseLCP[m] = 0;
    }
    else {
      int j = sparseSA[m-1];
      while(i+h < N && j+h < N && ref_string[i+h] == ref_string[j+h]) {
        h++;
      }
      sparseLCP[m] = h;
    }
    h = std::max(0, h - K);
  }

  printf("\nSparse SA: ");
  for (int i = 0; i < N/K; ++i)
    printf("%d ", sparseSA[i]);

  printf("\nSparse ISA: ");
  for (int i = 0; i < N/K; ++i)
    printf("%d ", sparseISA[i]);

  printf("\nSparse LCP: ");
  for (int i = 0; i < N/K; ++i)
    printf("%d ", sparseLCP[i]);
  printf("\n");

  // Search for MEMs:
  printf("\tRef.\tQuery\tLength\n");
  int p0 = 0;
  MEM(p0, ref_string, sparseISA, sparseLCP, sparseSA, query_string, K, N, L);

  return 0;
}

<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2015-2016 The Bitcoin Unlimited developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "pow.h"

#include "arith_uint256.h"
#include "chain.h"
#include "primitives/block.h"
#include "uint256.h"
#include "util.h"

unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
    unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();

    // Genesis block
    if (pindexLast == NULL)
        return nProofOfWorkLimit;

    // mvhf-bu genesis block reset the difficulty target
    if (pindexLast->nHeight == params.MVFActivateForkHeight() )
    {
    	return nProofOfWorkLimit;
    }

    // Only change once per difficulty adjustment interval
    if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval(pindexLast->nHeight) != 0)
    {
        if (params.fPowAllowMinDifficultyBlocks)
        {
            // Special difficulty rule for testnet:
            // If the new block's timestamp is more than 2* 10 minutes
            // then allow mining of a min-difficulty block.
            if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
                return nProofOfWorkLimit;
            else
            {
                // Return the last non-special-min-difficulty-rules-block
                const CBlockIndex* pindex = pindexLast;
                while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval(pindexLast->nHeight) != 0 && pindex->nBits == nProofOfWorkLimit)
                    pindex = pindex->pprev;
                return pindex->nBits;
            }
        }
        return pindexLast->nBits;
    }

    // Go back by what we want to be 14 days worth of blocks
    int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval(pindexLast->nHeight)-1);
    assert(nHeightFirst >= 0);
    const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
    assert(pindexFirst);

    return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
}

unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
{
    if (params.fPowNoRetargeting)
        return pindexLast->nBits;

    // Limit adjustment step
    int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
    LogPrintf("  nActualTimespan = %d  before bounds\n", nActualTimespan);

    //mvhf-bu target time span while within the re-target period
	int64_t nTargetTimespan = params.nPowTargetTimespan; // the original 2016 blocks

	// During the MVF Re-target Period after the fork block the target time span starts at 1 block until 12 blocks
	if (pindexLast->nHeight > params.MVFActivateForkHeight() && pindexLast->nHeight < params.nMVFRetargetPeriodEnd() )
	{
		nTargetTimespan = params.nPowTargetSpacing * (pindexLast->nHeight - params.MVFActivateForkHeight());
		if (nTargetTimespan > params.nPowTargetSpacing * 12) nTargetTimespan = params.nPowTargetSpacing * 12;
	}

	// During the first 12 blocks after the fork abrupt changes are permitted
	if (nTargetTimespan >= params.nPowTargetSpacing * 12)
	{
		// prevent abrupt changes to target
		if (nActualTimespan < params.nPowTargetTimespan/4)
			nActualTimespan = params.nPowTargetTimespan/4;
		if (nActualTimespan > params.nPowTargetTimespan*4)
			nActualTimespan = params.nPowTargetTimespan*4;
	}

    // Retarget
    const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
    arith_uint256 bnNew;
    arith_uint256 bnOld;
    bnNew.SetCompact(pindexLast->nBits);
    bnOld = bnNew;
    bnNew *= nActualTimespan;
    bnNew /= nTargetTimespan;

    if (bnNew > bnPowLimit)
        bnNew = bnPowLimit;

    /// debug print
    LogPrintf("GetNextWorkRequired RETARGET\n");
    LogPrintf("nTargetTimespan = %d    nActualTimespan = %d\n", nTargetTimespan, nActualTimespan);
    LogPrintf("Before: %08x  %s\n", pindexLast->nBits, bnOld.ToString());
    LogPrintf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString());

    return bnNew.GetCompact();
}

bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params)
{
    bool fNegative;
    bool fOverflow;
    arith_uint256 bnTarget;

    bnTarget.SetCompact(nBits, &fNegative, &fOverflow);

    // Check range
    if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit))
        return error("CheckProofOfWork(): nBits below minimum work");

    // Check proof of work matches claimed amount
    if (UintToArith256(hash) > bnTarget)
      return error("CheckProofOfWork(): hash %s doesn't match nBits 0x%x",hash.ToString(),nBits);

    return true;
}

arith_uint256 GetBlockProof(const CBlockIndex& block)
{
    arith_uint256 bnTarget;
    bool fNegative;
    bool fOverflow;
    bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
    if (fNegative || fOverflow || bnTarget == 0)
        return 0;
    // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
    // as it's too large for a arith_uint256. However, as 2**256 is at least as large
    // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
    // or ~bnTarget / (nTarget+1) + 1.
    return (~bnTarget / (bnTarget + 1)) + 1;
}

int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
{
    arith_uint256 r;
    int sign = 1;
    if (to.nChainWork > from.nChainWork) {
        r = to.nChainWork - from.nChainWork;
    } else {
        r = from.nChainWork - to.nChainWork;
        sign = -1;
    }
    r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip);
    if (r.bits() > 63) {
        return sign * std::numeric_limits<int64_t>::max();
    }
    return sign * r.GetLow64();
}
<commit_msg>formatting<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2015-2016 The Bitcoin Unlimited developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "pow.h"

#include "arith_uint256.h"
#include "chain.h"
#include "primitives/block.h"
#include "uint256.h"
#include "util.h"

unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
    unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();

    // Genesis block
    if (pindexLast == NULL)
        return nProofOfWorkLimit;

    // mvhf-bu genesis block reset the difficulty target
    if (pindexLast->nHeight == params.MVFActivateForkHeight() )
    {
    	return nProofOfWorkLimit;
    }

    // Only change once per difficulty adjustment interval
    if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval(pindexLast->nHeight) != 0)
    {
        if (params.fPowAllowMinDifficultyBlocks)
        {
            // Special difficulty rule for testnet:
            // If the new block's timestamp is more than 2* 10 minutes
            // then allow mining of a min-difficulty block.
            if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
                return nProofOfWorkLimit;
            else
            {
                // Return the last non-special-min-difficulty-rules-block
                const CBlockIndex* pindex = pindexLast;
                while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval(pindexLast->nHeight) != 0 && pindex->nBits == nProofOfWorkLimit)
                    pindex = pindex->pprev;
                return pindex->nBits;
            }
        }
        return pindexLast->nBits;
    }

    // Go back by what we want to be 14 days worth of blocks
    int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval(pindexLast->nHeight)-1);
    assert(nHeightFirst >= 0);
    const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
    assert(pindexFirst);

    return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
}

unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
{
    if (params.fPowNoRetargeting)
        return pindexLast->nBits;

    // Limit adjustment step
    int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
    LogPrintf("  nActualTimespan = %d  before bounds\n", nActualTimespan);

    //mvhf-bu target time span while within the re-target period
    int64_t nTargetTimespan = params.nPowTargetTimespan; // the original 2016 blocks

	// During the MVF Re-target Period after the fork block the target time span starts at 1 block until 12 blocks
	if (pindexLast->nHeight > params.MVFActivateForkHeight() && pindexLast->nHeight < params.nMVFRetargetPeriodEnd() )
	{
		nTargetTimespan = params.nPowTargetSpacing * (pindexLast->nHeight - params.MVFActivateForkHeight());
		if (nTargetTimespan > params.nPowTargetSpacing * 12) nTargetTimespan = params.nPowTargetSpacing * 12;
	}

	// During the first 12 blocks after the fork abrupt changes are permitted
	if (nTargetTimespan >= params.nPowTargetSpacing * 12)
	{
		// prevent abrupt changes to target
		if (nActualTimespan < params.nPowTargetTimespan/4)
			nActualTimespan = params.nPowTargetTimespan/4;
		if (nActualTimespan > params.nPowTargetTimespan*4)
			nActualTimespan = params.nPowTargetTimespan*4;
	}

    // Retarget
    const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
    arith_uint256 bnNew;
    arith_uint256 bnOld;
    bnNew.SetCompact(pindexLast->nBits);
    bnOld = bnNew;
    bnNew *= nActualTimespan;
    bnNew /= nTargetTimespan;

    if (bnNew > bnPowLimit)
        bnNew = bnPowLimit;

    /// debug print
    LogPrintf("GetNextWorkRequired RETARGET\n");
    LogPrintf("nTargetTimespan = %d    nActualTimespan = %d\n", nTargetTimespan, nActualTimespan);
    LogPrintf("Before: %08x  %s\n", pindexLast->nBits, bnOld.ToString());
    LogPrintf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString());

    return bnNew.GetCompact();
}

bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params)
{
    bool fNegative;
    bool fOverflow;
    arith_uint256 bnTarget;

    bnTarget.SetCompact(nBits, &fNegative, &fOverflow);

    // Check range
    if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit))
        return error("CheckProofOfWork(): nBits below minimum work");

    // Check proof of work matches claimed amount
    if (UintToArith256(hash) > bnTarget)
      return error("CheckProofOfWork(): hash %s doesn't match nBits 0x%x",hash.ToString(),nBits);

    return true;
}

arith_uint256 GetBlockProof(const CBlockIndex& block)
{
    arith_uint256 bnTarget;
    bool fNegative;
    bool fOverflow;
    bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
    if (fNegative || fOverflow || bnTarget == 0)
        return 0;
    // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
    // as it's too large for a arith_uint256. However, as 2**256 is at least as large
    // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
    // or ~bnTarget / (nTarget+1) + 1.
    return (~bnTarget / (bnTarget + 1)) + 1;
}

int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
{
    arith_uint256 r;
    int sign = 1;
    if (to.nChainWork > from.nChainWork) {
        r = to.nChainWork - from.nChainWork;
    } else {
        r = from.nChainWork - to.nChainWork;
        sign = -1;
    }
    r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip);
    if (r.bits() > 63) {
        return sign * std::numeric_limits<int64_t>::max();
    }
    return sign * r.GetLow64();
}
<|endoftext|>


<commit_before>#ifndef CCC_HPP
#define CCC_HPP

#include <iostream>

#if defined(__unix) || defined(__unix__) || defined(unix) ||\
    defined(__linux) || defined(__linux__) || defined(linux) ||\
    defined(__MACH__) || defined(BSD) || defined(__GNU__)
        #define CCC_UNIX
#endif

#if defined(_WIN64) || defined(_WIN32) || defined(_WIN16) ||\
    defined(__WIN64__) || defined(__WIN32__) || defined(__WIN16__) ||\
    defined(WINDOWS) || defined(__WINDOWS__)
        #define CCC_WINDOWS
        #include <windows.h>

        #error "not supported yet"
#endif

namespace ccc {

enum font {
    f_0, // the same as d_font
    f_1,
    f_2,
    f_3,
    f_4,
    f_5,
    f_6,
    f_7,
    f_8,
    f_9
};

enum color_f {
    cf_black,
    cf_red,
    cf_green,
    cf_yellow,
    cf_blue,
    cf_magenta,
    cf_cyan,
    cf_white
};

enum color_b {
    cb_black,
    cb_red,
    cb_green,
    cb_yellow,
    cb_blue,
    cb_magenta,
    cb_cyan,
    cb_white
};

enum style {
    s_font = 10,
    s_color_f = 30,
    s_color_b = 40,

    s_bold = 1,
    s_faint = 2,

    s_italic = 3,
    s_fraktur = 20,

    s_underline_single = 4,
    s_underline_double = 21,

    s_blink_slow = 5,
    s_blink_rapid = 6,

    s_framed = 51,
    s_encircled = 52,

    s_negative = 7,
    s_conceal = 8,
    s_delete = 9,
    s_overlined = 53
};

enum disable {
    d_all = 0,
    d_font = 10,
    d_color_f = 39,
    d_color_b = 49,

    d_intensity = 22,
    d_fontstyle = 23,
    d_underline = 24,
    d_blink = 25,
    d_border = 54,

    d_negative = 27,
    d_conceal = 28,
    d_delete = 29,
    d_overlined = 55
};

inline std::ostream &operator<<(std::ostream &s, const font &c) {
    #if defined(CCC_UNIX)
        return s << '\e' << '[' << (int) (s_font + c) << 'm';
    #elif defined(CCC_WINDOWS)
        // TODO

        assert(s == std::cout);

        HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
        CONSOLE_SCREEN_BUFFER_INFO buf_info;
        GetConsoleScreenBufferInfo(handle, &buf_info);
        SetConsoleTextAttribute(hStdOut, /* TODO */);

        return s;
    #endif
}

inline std::ostream &operator<<(std::ostream &s, const color_f &c) {
    #if defined(CCC_UNIX)
        return s << '\e' << '[' << (int) (s_color_f + c) << 'm';
    #elif defined(CCC_WINDOWS)
        // TODO

        assert(s == std::cout);

        HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
        CONSOLE_SCREEN_BUFFER_INFO buf_info;
        GetConsoleScreenBufferInfo(handle, &buf_info);
        SetConsoleTextAttribute(hStdOut, /* TODO */);

        return s;
    #endif
}

inline std::ostream &operator<<(std::ostream &s, const color_b &c) {
    #if defined(CCC_UNIX)
        return s << '\e' << '[' << (int) (s_color_b + c) << 'm';
    #elif defined(CCC_WINDOWS)
        // TODO

        assert(s == std::cout);

        HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
        CONSOLE_SCREEN_BUFFER_INFO buf_info;
        GetConsoleScreenBufferInfo(handle, &buf_info);
        SetConsoleTextAttribute(hStdOut, /* TODO */);

        return s;
    #endif
}

inline std::ostream &operator<<(std::ostream &s, const style &c) {
    #if defined(CCC_UNIX)
        return s << '\e' << '[' << (int) c << 'm';
    #elif defined(CCC_WINDOWS)
        // TODO

        assert(s == std::cout);

        HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
        CONSOLE_SCREEN_BUFFER_INFO buf_info;
        GetConsoleScreenBufferInfo(handle, &buf_info);
        SetConsoleTextAttribute(hStdOut, /* TODO */);

        return s;
    #endif
}

inline std::ostream &operator<<(std::ostream &s, const disable &c) {
    #if defined(CCC_UNIX)
        return s << '\e' << '[' << (int) c << 'm';
    #elif defined(CCC_WINDOWS)
        // TODO

        assert(s == std::cout);

        HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
        CONSOLE_SCREEN_BUFFER_INFO buf_info;
        GetConsoleScreenBufferInfo(handle, &buf_info);
        SetConsoleTextAttribute(hStdOut, /* TODO */);

        return s;
    #endif
}

}

#endif
<commit_msg>add class alsoStyle and make it simpler<commit_after>#ifndef CCC_HPP
#define CCC_HPP

#include <iostream>

#if defined(__unix) || defined(__unix__) || defined(unix) ||\
    defined(__linux) || defined(__linux__) || defined(linux) ||\
    defined(__MACH__) || defined(BSD) || defined(__GNU__)
        #define CCC_UNIX
#endif

#if defined(_WIN64) || defined(_WIN32) || defined(_WIN16) ||\
    defined(__WIN64__) || defined(__WIN32__) || defined(__WIN16__) ||\
    defined(WINDOWS) || defined(__WINDOWS__)
        #define CCC_WINDOWS
        #include <windows.h>

        #error "not supported yet"
#endif

namespace ccc {

enum Style {
    // font
    f_0 = 10,
    f_1,
    f_2,
    f_3,
    f_4,
    f_5,
    f_6,
    f_7,
    f_8,
    f_9,

    // foreground color
    cf_black = 30,
    cf_red,
    cf_green,
    cf_yellow,
    cf_blue,
    cf_magenta,
    cf_cyan,
    cf_white,

    // background color
    cb_black = 40,
    cb_red,
    cb_green,
    cb_yellow,
    cb_blue,
    cb_magenta,
    cb_cyan,
    cb_white,

    // enable style
    s_bold = 1,
    s_faint = 2,

    s_italic = 3,
    s_fraktur = 20,

    s_underline_single = 4,
    s_underline_double = 21,

    s_blink_slow = 5,
    s_blink_rapid = 6,

    s_framed = 51,
    s_encircled = 52,

    s_negative = 7,
    s_conceal = 8,
    s_delete = 9,
    s_overlined = 53,

    // disable style
    d_all = 0,
    d_font = 10,
    d_color_f = 39,
    d_color_b = 49,

    d_intensity = 22,
    d_fontstyle = 23,
    d_underline = 24,
    d_blink = 25,
    d_border = 54,

    d_negative = 27,
    d_conceal = 28,
    d_delete = 29,
    d_overlined = 55
};

static std::ostream &operator<<(std::ostream &s, const Style &style) {
    #if defined(CCC_UNIX)
        return s << '\x1b' << '[' << (int) style << 'm';
    #elif defined(CCC_WINDOWS)
        // TODO

        assert(s == std::cout);

        HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
        CONSOLE_SCREEN_BUFFER_INFO buf_info;
        GetConsoleScreenBufferInfo(handle, &buf_info);
        SetConsoleTextAttribute(hStdOut, /* TODO */);

        return s;
    #endif
}

template <class T>
class alsoStyle {
public:
    const T _object;
    const Style _style;

    inline alsoStyle(const T &object, const Style &style):
        _object(object), _style(style) {}
};

template <class T>
static const alsoStyle<T> operator+(const T &object, const Style &style) {
    return alsoStyle<T>(object, style);
}

template <class T>
inline std::ostream &operator<<(std::ostream &s, const alsoStyle<T> &target) {
    return s << target._object << target._style;
}

}

#endif
<|endoftext|>