<commit_before>#include <algorithm>
#include <array>
#include <iomanip>
#include <curl/curl.h>
#include <memory>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <vector>
#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include <system_error>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

const std::string listing("http://nwn.efupw.com/rootdir/index.dat");
const std::string patch_dir("http://nwn.efupw.com/rootdir/patch/");
const std::string update_check("");

size_t writefunction(const char *ptr, size_t size, size_t nmemb, void *userdata)
{
    std::string *s = static_cast<std::string *>(userdata);
    s->append(ptr, size * nmemb);
    return size * nmemb;
}

std::vector<std::string> &split(const std::string &s, char delim,
        std::vector<std::string> &elems)
{
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim))
    {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim)
{
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

class Target
{
    public:
        enum class Status {
            Nonexistent,
            Outdated,
            Current
        };
        explicit Target(const std::string &name, const std::string &checksum):
            m_name(name.find_first_of('/') == std::string::npos ?
                    name
                    : name, name.find_first_of('/') + 1, name.size() - 1), m_checksum(checksum)
    {}
        std::string name() const { return m_name; }
        std::string checksum() const { return m_checksum; }
        void fetch()
        {
            std::cout << "pretending to fetch " << name() << std::endl;
            std::string path;
            std::ofstream ofs(name());
            if (!ofs.good())
            {
                auto elems = split(name(), '/');
                for (size_t i = 0, k = elems.size(); i < k; ++i)
                    //for (auto s : elems)
                {
                    const std::string &s(elems[i]);
                    if (s.size() && s != ".")
                    {
                        path.append((i > 0 ? "/" : "") + s);
                        if (k > 1 && i < k - 1)
                        {
                            auto status = mkdir(path.c_str(), S_IRWXU);
                            if (status == -1)
                            {
                                std::error_code err(errno, std::generic_category());
                                if (err == std::errc::file_exists)
                                {
                                    std::cout << "error making dir: "
                                        << err.message() << std::endl;
                                }
                            }
                        }
                        std::cout << "the path: " << path << std::endl;
                    }
                }
                ofs.open(path);
                if (ofs.good())
                {
                    std::cout << "opened path " << path << std::endl;
                }
            }
            if (ofs.good())
            {
                const std::string md5("38eaad974c15e5f3119469f17e8e97a9");
                //if (md5 != checksum())
                {
                    std::cout << "Downloading new " << name() << std::endl;
                    std::string s;
                    std::shared_ptr<CURL *> phandle =
                        std::make_shared<CURL *>(curl_easy_init());
                    std::string url(patch_dir + name());
                    curl_easy_setopt(*phandle, CURLOPT_URL, url.c_str());
                    curl_easy_setopt(*phandle, CURLOPT_WRITEFUNCTION, &writefunction);
                    curl_easy_setopt(*phandle, CURLOPT_WRITEDATA, &s);
                    //curl_easy_setopt(*phandle, CURLOPT_NOPROGRESS, 0);
                    curl_easy_perform(*phandle);
                    curl_easy_cleanup(*phandle);
                    phandle.reset();
                    ofs << s;
                    ofs.close();
                }
                //else
                {
                    std::cout << name() << " already up to date." << std::endl;
                }
            }
        }
        Status status()
        {
            return Status::Nonexistent;
        }

    private:
        std::string m_name;
        std::string m_checksum;
};

std::ostream& operator<<(std::ostream &os, const Target &t)
{
    return os << "name: " << t.name() << ", checksum: " << t.checksum();
}

class CurlGlobalInit
{
    public:
        CurlGlobalInit()
        {
            curl_global_init(CURL_GLOBAL_ALL);
        }

        ~CurlGlobalInit()
        {
            curl_global_cleanup();
        }
};

bool file_checksum_test(const std::string &path,
        const std::string &checksum)
{
#define md_md5
#ifdef md_md5
    auto md = EVP_md5();
    const int md_len = MD5_DIGEST_LENGTH;
#else
    auto md = EVP_sha1();
    const int md_len = SHA_DIGEST_LENGTH;
#endif
    std::array<unsigned char, md_len> result;
    EVP_MD_CTX *mdctx = nullptr;
    std::ifstream is(path, std::ifstream::binary);

    const int length = 8192;
    std::array<unsigned char, length> buffer;
    auto buf = reinterpret_cast<char *>(buffer.data());
    mdctx = EVP_MD_CTX_create();
    int status = EVP_DigestInit_ex(mdctx, md, nullptr);
    while (status && is)
    {
        is.read(buf, length);
        status = EVP_DigestUpdate(mdctx, buffer.data(), is.gcount());
    }
    status = EVP_DigestFinal_ex(mdctx, result.data(), nullptr);
    EVP_MD_CTX_destroy(mdctx);
    std::stringstream calcsum;
    calcsum << std::setfill('0');

    for (unsigned char c : result)
    {
        calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
    }
    /*
    std::for_each(std::begin(result), std::end(result),
            [&calcsum](unsigned char c)
            {
            calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
            });
            */
    std::cout << calcsum.str() << std::endl;
    return calcsum.str() == checksum;
}

int main(int argc, char *argv[])
{
    CurlGlobalInit curl_global;
    std::string fetch;
    std::shared_ptr<CURL *> phandle = std::make_shared<CURL *>(curl_easy_init());
    curl_easy_setopt(*phandle, CURLOPT_URL, listing.c_str());
    curl_easy_setopt(*phandle, CURLOPT_WRITEFUNCTION, &writefunction);
    curl_easy_setopt(*phandle, CURLOPT_WRITEDATA, &fetch);
    //curl_easy_setopt(*phandle, CURLOPT_NOPROGRESS, 0);
    curl_easy_perform(*phandle);
    curl_easy_cleanup(*phandle);
    phandle.reset();
    //std::cout << fetch << std::endl;
    std::vector<std::string> v(split(fetch, '\n'));
    //split(fetch, '\n', v);
    //std::cout << v[1] << std::endl;
    std::vector<Target> new_targets, old_targets;
    for (auto beg = std::begin(v), end = std::end(v);
            beg != end; ++beg)
    {
        auto w(split(*beg, '@'));
        /*
        for (const auto & sss : w)
        {
            std::cout << sss << ", " << std::endl;
        }
        */
        Target t(w[0], w[w.size() - 1]);
        auto status = t.status();
        if (status == Target::Status::Nonexistent)
        {
            new_targets.push_back(std::move(t));
        }
        else if (status == Target::Status::Outdated)
        {
            old_targets.push_back(std::move(t));
        }
        //std::cout << *beg << std::endl;
    }
    std::stringstream ss(fetch);
    std::string item;
    //std::vector<std::pair<std::string, std::string>> new_targets;
    while (std::getline(ss, item))
    {
        //new_targets.push_back(item);
    }
    if (new_targets.size())
    {
        std::cout << "New targets: " << new_targets.size() << std::endl;
        //for (auto &t : new_targets)
        {
            //std::cout << t << std::endl;
            //t.fetch();
        }
        std::cout << new_targets[4] << std::endl;
        new_targets[1].fetch();
        new_targets[4].fetch();
        /*
        for (auto s : split(new_targets[4].name(), '/'))
        {
            if (s.length())
            {
                std::cout << s << ", ";
            }
        }
        */
    }
    else
    {
        std::cout << "No new targets." << std::endl;
    }
    if (old_targets.size())
    {
        std::cout << "Outdated targets: " << old_targets.size() << std::endl;
        for (auto &t : old_targets)
        {
            std::cout << t << std::endl;
        }
    }
    else
    {
        std::cout << "No targets out of date." << std::endl;
    }
    const std::string path = "bin/override/spells.2da";
    const std::string checksum("38eaad974c15e5f3119469f17e8e97a9");
    std::cout << "file checksum test: "
        << path << " = " << checksum
        << " : " << file_checksum_test(path, checksum)
        << std::endl;

    std::cout << std::endl;
    return 0;
}
<commit_msg>Change file_checksum_test() to file_checksum() returning string.<commit_after>#include <algorithm>
#include <array>
#include <iomanip>
#include <curl/curl.h>
#include <memory>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <vector>
#include <sys/stat.h>
#include <cerrno>
#include <cstring>
#include <system_error>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

const std::string listing("http://nwn.efupw.com/rootdir/index.dat");
const std::string patch_dir("http://nwn.efupw.com/rootdir/patch/");
const std::string update_check("");

std::string file_checksum(const std::string &path);

size_t writefunction(const char *ptr, size_t size, size_t nmemb, void *userdata)
{
    std::string *s = static_cast<std::string *>(userdata);
    s->append(ptr, size * nmemb);
    return size * nmemb;
}

std::vector<std::string> &split(const std::string &s, char delim,
        std::vector<std::string> &elems)
{
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim))
    {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim)
{
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

class Target
{
    public:
        enum class Status {
            Nonexistent,
            Outdated,
            Current
        };
        explicit Target(const std::string &name, const std::string &checksum):
            m_name(name.find_first_of('/') == std::string::npos ?
                    name
                    : name, name.find_first_of('/') + 1, name.size() - 1), m_checksum(checksum)
    {}
        std::string name() const { return m_name; }
        std::string checksum() const { return m_checksum; }
        void fetch()
        {
            std::cout << "pretending to fetch " << name() << std::endl;
            std::string path;
            std::ofstream ofs(name());
            if (!ofs.good())
            {
                auto elems = split(name(), '/');
                for (size_t i = 0, k = elems.size(); i < k; ++i)
                    //for (auto s : elems)
                {
                    const std::string &s(elems[i]);
                    if (s.size() && s != ".")
                    {
                        path.append((i > 0 ? "/" : "") + s);
                        if (k > 1 && i < k - 1)
                        {
                            auto status = mkdir(path.c_str(), S_IRWXU);
                            if (status == -1)
                            {
                                std::error_code err(errno, std::generic_category());
                                if (err == std::errc::file_exists)
                                {
                                    std::cout << "error making dir: "
                                        << err.message() << std::endl;
                                }
                            }
                        }
                        std::cout << "the path: " << path << std::endl;
                    }
                }
                ofs.open(path);
                if (ofs.good())
                {
                    std::cout << "opened path " << path << std::endl;
                }
            }
            if (ofs.good())
            {
                const std::string md5("38eaad974c15e5f3119469f17e8e97a9");
                //if (md5 != checksum())
                {
                    std::cout << "Downloading new " << name() << std::endl;
                    std::string s;
                    std::shared_ptr<CURL *> phandle =
                        std::make_shared<CURL *>(curl_easy_init());
                    std::string url(patch_dir + name());
                    curl_easy_setopt(*phandle, CURLOPT_URL, url.c_str());
                    curl_easy_setopt(*phandle, CURLOPT_WRITEFUNCTION, &writefunction);
                    curl_easy_setopt(*phandle, CURLOPT_WRITEDATA, &s);
                    //curl_easy_setopt(*phandle, CURLOPT_NOPROGRESS, 0);
                    curl_easy_perform(*phandle);
                    curl_easy_cleanup(*phandle);
                    phandle.reset();
                    ofs << s;
                    ofs.close();
                }
                //else
                {
                    std::cout << name() << " already up to date." << std::endl;
                }
            }
        }
        Status status()
        {
            return Status::Nonexistent;
        }

    private:
        std::string m_name;
        std::string m_checksum;
};

std::ostream& operator<<(std::ostream &os, const Target &t)
{
    return os << "name: " << t.name() << ", checksum: " << t.checksum();
}

class CurlGlobalInit
{
    public:
        CurlGlobalInit()
        {
            curl_global_init(CURL_GLOBAL_ALL);
        }

        ~CurlGlobalInit()
        {
            curl_global_cleanup();
        }
};

std::string file_checksum(const std::string &path)
{
#define md_md5
#ifdef md_md5
    auto md = EVP_md5();
    const int md_len = MD5_DIGEST_LENGTH;
#else
    auto md = EVP_sha1();
    const int md_len = SHA_DIGEST_LENGTH;
#endif
    std::array<unsigned char, md_len> result;
    EVP_MD_CTX *mdctx = nullptr;
    std::ifstream is(path, std::ifstream::binary);

    const int length = 8192;
    std::array<unsigned char, length> buffer;
    auto buf = reinterpret_cast<char *>(buffer.data());
    mdctx = EVP_MD_CTX_create();
    int status = EVP_DigestInit_ex(mdctx, md, nullptr);
    while (status && is)
    {
        is.read(buf, length);
        status = EVP_DigestUpdate(mdctx, buffer.data(), is.gcount());
    }
    status = EVP_DigestFinal_ex(mdctx, result.data(), nullptr);
    EVP_MD_CTX_destroy(mdctx);
    std::stringstream calcsum;
    calcsum << std::setfill('0');

    for (unsigned char c : result)
    {
        calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
    }
    /*
    std::for_each(std::begin(result), std::end(result),
            [&calcsum](unsigned char c)
            {
            calcsum << std::hex << std::setw(2)
            << static_cast<unsigned int>(c);
            });
            */
    std::cout << calcsum.str() << std::endl;
    return calcsum.str();
}

int main(int argc, char *argv[])
{
    CurlGlobalInit curl_global;
    std::string fetch;
    std::shared_ptr<CURL *> phandle = std::make_shared<CURL *>(curl_easy_init());
    curl_easy_setopt(*phandle, CURLOPT_URL, listing.c_str());
    curl_easy_setopt(*phandle, CURLOPT_WRITEFUNCTION, &writefunction);
    curl_easy_setopt(*phandle, CURLOPT_WRITEDATA, &fetch);
    //curl_easy_setopt(*phandle, CURLOPT_NOPROGRESS, 0);
    curl_easy_perform(*phandle);
    curl_easy_cleanup(*phandle);
    phandle.reset();
    //std::cout << fetch << std::endl;
    std::vector<std::string> v(split(fetch, '\n'));
    //split(fetch, '\n', v);
    //std::cout << v[1] << std::endl;
    std::vector<Target> new_targets, old_targets;
    for (auto beg = std::begin(v), end = std::end(v);
            beg != end; ++beg)
    {
        auto w(split(*beg, '@'));
        /*
        for (const auto & sss : w)
        {
            std::cout << sss << ", " << std::endl;
        }
        */
        Target t(w[0], w[w.size() - 1]);
        auto status = t.status();
        if (status == Target::Status::Nonexistent)
        {
            new_targets.push_back(std::move(t));
        }
        else if (status == Target::Status::Outdated)
        {
            old_targets.push_back(std::move(t));
        }
        //std::cout << *beg << std::endl;
    }
    std::stringstream ss(fetch);
    std::string item;
    //std::vector<std::pair<std::string, std::string>> new_targets;
    while (std::getline(ss, item))
    {
        //new_targets.push_back(item);
    }
    if (new_targets.size())
    {
        std::cout << "New targets: " << new_targets.size() << std::endl;
        //for (auto &t : new_targets)
        {
            //std::cout << t << std::endl;
            //t.fetch();
        }
        std::cout << new_targets[4] << std::endl;
        new_targets[1].fetch();
        new_targets[4].fetch();
        /*
        for (auto s : split(new_targets[4].name(), '/'))
        {
            if (s.length())
            {
                std::cout << s << ", ";
            }
        }
        */
    }
    else
    {
        std::cout << "No new targets." << std::endl;
    }
    if (old_targets.size())
    {
        std::cout << "Outdated targets: " << old_targets.size() << std::endl;
        for (auto &t : old_targets)
        {
            std::cout << t << std::endl;
        }
    }
    else
    {
        std::cout << "No targets out of date." << std::endl;
    }
    const std::string path = "bin/override/spells.2da";
    const std::string checksum("38eaad974c15e5f3119469f17e8e97a9");
    std::cout << "file checksum test: "
        << path << " = " << checksum
        << " : " << (file_checksum(path) == checksum)
        << std::endl;

    std::cout << std::endl;
    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Christian Lockley
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

#include "watchdogd.hpp"

#include "sub.hpp"
#include "main.hpp"
#include "init.hpp"
#include "configfile.hpp"
#include "threads.hpp"
#include "identify.hpp"
#include "bootstatus.hpp"
#include "multicall.hpp"
extern "C" {
#include "dbusapi.h"
}
#include <systemd/sd-event.h>
const bool DISARM_WATCHDOG_BEFORE_REBOOT = true;
static volatile sig_atomic_t quit = 0;

volatile sig_atomic_t stop = 0;
volatile sig_atomic_t stopPing = 0;
ProcessList processes;

static void PrintConfiguration(struct cfgoptions *const cfg)
{
	Logmsg(LOG_INFO,
	       "int=%is realtime=%s sync=%s softboot=%s force=%s mla=%.2f mem=%li pid=%li",
	       cfg->sleeptime, cfg->options & REALTIME ? "yes" : "no",
	       cfg->options & SYNC ? "yes" : "no",
	       cfg->options & SOFTBOOT ? "yes" : "no",
	       cfg->options & FORCE ? "yes" : "no", cfg->maxLoadOne, cfg->minfreepages, getppid());

	if (cfg->options & ENABLEPING) {
		for (int cnt = 0; cnt < config_setting_length(cfg->ipAddresses); cnt++) {
			const char *ipAddress = config_setting_get_string_elem(cfg->ipAddresses,
									       cnt);

			assert(ipAddress != NULL);

			Logmsg(LOG_INFO, "ping: %s", ipAddress);
		}
	} else {
		Logmsg(LOG_INFO, "ping: no ip adresses to ping");
	}

	if (cfg->options & ENABLEPIDCHECKER) {
		for (int cnt = 0; cnt < config_setting_length(cfg->pidFiles); cnt++) {
			const char *pidFilePathName = config_setting_get_string_elem(cfg->pidFiles, cnt);

			assert(pidFilePathName != NULL);

			Logmsg(LOG_DEBUG, "pidfile: %s", pidFilePathName);
		}
	} else {
		Logmsg(LOG_INFO, "pidfile: no server process to check");
	}

	Logmsg(LOG_INFO, "test=%s(%i) repair=%s(%i) no_act=%s",
	       cfg->testexepathname == NULL ? "no" : cfg->testexepathname,
	       cfg->testBinTimeout,
	       cfg->exepathname == NULL ? "no" : cfg->exepathname,
	       cfg->repairBinTimeout, cfg->options & NOACTION ? "yes" : "no");
}

static void BlockSignals()
{
	sigset_t set;

	sigemptyset(&set);

	sigaddset(&set, SIGTERM);
	sigaddset(&set, SIGUSR2);
	sigaddset(&set, SIGINT);
	sigaddset(&set, SIGHUP);

	pthread_sigmask(SIG_BLOCK, &set, NULL);
}

static int SignalHandler(sd_event_source * s, const signalfd_siginfo * si, void *cxt)
{
	switch (sd_event_source_get_signal(s)) {
	case SIGTERM:
	case SIGINT:
		quit = 1;
		sd_event_exit((sd_event *) cxt, 0);
		break;
	case SIGHUP:
		//reload;
		break;
	}
	return 1;
}

static void InstallSignalHandlers(sd_event * event)
{
	int r1 = sd_event_add_signal(event, NULL, SIGTERM, SignalHandler, event);
	int r2 = sd_event_add_signal(event, NULL, SIGHUP, SignalHandler, event);
	int r3 = sd_event_add_signal(event, NULL, SIGUSR2, SignalHandler, event);
	int r4 = sd_event_add_signal(event, NULL, SIGINT, SignalHandler, event);

	if (r1 < 0 || r2 < 0 || r3 < 0 || r4 < 0) {
		abort();
	}
}

static int Pinger(sd_event_source * s, uint64_t usec, void *cxt)
{
	Watchdog *watchdog = (Watchdog *) cxt;
	watchdog->Ping();

	sd_event_now(sd_event_source_get_event(s), CLOCK_REALTIME, &usec);
	usec += watchdog->GetPingInterval() * 1000000;
	sd_event_add_time(sd_event_source_get_event(s), &s, CLOCK_REALTIME, usec, 1, Pinger, (void *)cxt);
	return 0;
}

static bool InstallPinger(sd_event * e, int time, Watchdog * w)
{
	sd_event_source *s = NULL;
	uint64_t usec = 0;
	w->SetPingInterval(time);

	sd_event_now(e, CLOCK_REALTIME, &usec);

	sd_event_add_time(e, &s, CLOCK_REALTIME, usec, 1, Pinger, (void *)w);
	return true;
}

int ServiceMain(int argc, char **argv, int fd)
{
	cfgoptions options;
	Watchdog watchdog;
	cfgoptions *tmp = &options;
	Watchdog *tmp2 = &watchdog;

	struct dbusinfo temp = {.config = &tmp,.wdt = &tmp2 };;
	temp.fd = fd;

	if (MyStrerrorInit() == false) {
		std::perror("Unable to create a new locale object");
		return EXIT_FAILURE;
	}

	int ret = ParseCommandLine(&argc, argv, &options);

	if (ret < 0) {
		return EXIT_FAILURE;
	} else if (ret != 0) {
		return EXIT_SUCCESS;
	}

	if (strcasecmp(GetExeName(), "wd_identify") == 0 || strcasecmp(GetExeName(), "wd_identify.sh") == 0) {
		options.options |= IDENTIFY;
	}

	if (ReadConfigurationFile(&options) < 0) {
		return EXIT_FAILURE;
	}

	if (options.options & IDENTIFY) {
		watchdog.Open(options.devicepath);

		ret = Identify(watchdog.GetRawTimeout(), (const char *)watchdog.GetIdentity(),
			       options.devicepath, options.options & VERBOSE);

		watchdog.Close();
		return ret;
	}

	if (PingInit(&options) < 0) {
		return EXIT_FAILURE;
	}

	Logmsg(LOG_INFO, "starting service (%s)", PACKAGE_VERSION);

	PrintConfiguration(&options);

	if (ExecuteRepairScriptsPreFork(&processes, &options) == false) {
		Logmsg(LOG_ERR, "ExecuteRepairScriptsPreFork failed");
		FatalError(&options);
	}

	sd_event_source *event_source = NULL;
	sd_event *event = NULL;
	sd_event_default(&event);

	BlockSignals();
	InstallSignalHandlers(event);

	if (StartHelperThreads(&options) != 0) {
		FatalError(&options);
	}

	pthread_t dbusThread;

	if (!(options.options & NOACTION)) {
		errno = 0;

		ret = watchdog.Open(options.devicepath);

		if (errno == EBUSY && ret < 0) {
			Logmsg(LOG_ERR, "Unable to open watchdog device");
			return EXIT_FAILURE;
		} else if (ret <= -1) {
			LoadKernelModule();
			ret = watchdog.Open(options.devicepath);
		}

		if (ret <= -1) {
			FatalError(&options);
		}

		if (watchdog.ConfigureWatchdogTimeout(options.watchdogTimeout)
		    < 0 && options.watchdogTimeout != -1) {
			Logmsg(LOG_ERR, "unable to set watchdog device timeout\n");
			Logmsg(LOG_ERR, "program exiting\n");
			EndDaemon(&options, false);
			watchdog.Close();
			return EXIT_FAILURE;
		}

		if (options.sleeptime == -1) {
			options.sleeptime = watchdog.GetOptimalPingInterval();
			Logmsg(LOG_INFO, "ping interval autodetect: %i", options.sleeptime);
		}

		if (options.watchdogTimeout != -1 && watchdog.CheckWatchdogTimeout(options.sleeptime) == true) {
			Logmsg(LOG_ERR, "WDT timeout is less than or equal watchdog daemon ping interval");
			Logmsg(LOG_ERR, "Using this interval may result in spurious reboots");

			if (!(options.options & FORCE)) {
				watchdog.Close();
				Logmsg(LOG_WARNING, "use the -f option to force this configuration");
				return EXIT_FAILURE;
			}
		}

		WriteBootStatus(watchdog.GetStatus(), "/run/watchdogd.status", options.sleeptime,
				watchdog.GetRawTimeout());

		static struct identinfo i;

		strncpy(i.name, (char *)watchdog.GetIdentity(), sizeof(i.name) - 1);
		i.timeout = watchdog.GetRawTimeout();
		strncpy(i.daemonVersion, PACKAGE_VERSION, sizeof(i.daemonVersion) - 1);
		strncpy(i.deviceName, options.devicepath, sizeof(i.deviceName) - 1);
		i.flags = watchdog.GetStatus();
		i.firmwareVersion = watchdog.GetFirmwareVersion();

		CreateDetachedThread(IdentityThread, &i);
		pthread_create(&dbusThread, NULL, DbusHelper, &temp);
		InstallPinger(event, options.sleeptime, &watchdog);

		write(fd, "", sizeof(char));
	}

	if (SetupAuxManagerThread(&options) < 0) {
		FatalError(&options);
	}

	if (PlatformInit() != true) {
		FatalError(&options);
	}

	sd_event_loop(event);

	if (stop == 1) {
		while (true) {
			if (stopPing == 1) {
				if (DISARM_WATCHDOG_BEFORE_REBOOT) {
					watchdog.Close();
				}
			} else {
				watchdog.Ping();
			}

			sleep(1);
		}
	}
	pthread_cancel(dbusThread);
	pthread_join(dbusThread, NULL);
	watchdog.Close();

	unlink("/run/watchdogd.status");

	if (EndDaemon(&options, false) < 0) {
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

sig_atomic_t sigValue = -1;
pid_t pid = 0;
static int ret = 0;

static void SaHandler(int sig)
{
	sigValue = sig;
}

static int sock[2] = { 0 };

int main(int argc, char **argv)
{
	socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sock);
	pid_t pid = fork();

	if (pid == 0) {
		OnParentDeathSend(SIGKILL);
		close(sock[1]);
		DbusApiInit(sock[0]);
		_Exit(0);
	}

	close(sock[0]);

	struct sigaction act = { 0 };

	act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
	act.sa_handler = SaHandler;
	sigfillset(&act.sa_mask);

	sigaction(SIGCHLD, &act, NULL);
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
	sigaction(SIGHUP, &act, NULL);

init:
	pid = fork();
	if (pid == 0) {
		ResetSignalHandlers(64);
		OnParentDeathSend(SIGTERM);
		_Exit(ServiceMain(argc, argv, sock[1]));
	}

	do {
		pause();
		switch (sigValue) {
		case SIGHUP:
			kill(pid, SIGTERM);
			do {
				waitpid(pid, &ret, 0);
			} while (!WIFEXITED(ret) && !WIFSIGNALED(ret));
			goto init;
			break;
		case SIGCHLD:
			do {
				waitpid(pid, &ret, 0);
			} while (!WIFEXITED(ret) && !WIFSIGNALED(ret));
			break;
		case SIGINT:
		case SIGTERM:
			kill(pid, SIGTERM);
			do {
				waitpid(pid, &ret, 0);
			} while (!WIFEXITED(ret) && !WIFSIGNALED(ret));
			break;
		default:
			sigValue = -1;
			break;
		}
	} while (sigValue == -1);

	_Exit(WEXITSTATUS(ret));
}
<commit_msg>Print restarting daemon message when reloading<commit_after>/*
 * Copyright 2016 Christian Lockley
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

#include "watchdogd.hpp"

#include "sub.hpp"
#include "main.hpp"
#include "init.hpp"
#include "configfile.hpp"
#include "threads.hpp"
#include "identify.hpp"
#include "bootstatus.hpp"
#include "multicall.hpp"
extern "C" {
#include "dbusapi.h"
}
#include <systemd/sd-event.h>
const bool DISARM_WATCHDOG_BEFORE_REBOOT = true;
static volatile sig_atomic_t quit = 0;

volatile sig_atomic_t stop = 0;
volatile sig_atomic_t stopPing = 0;
ProcessList processes;

static void PrintConfiguration(struct cfgoptions *const cfg)
{
	Logmsg(LOG_INFO,
	       "int=%is realtime=%s sync=%s softboot=%s force=%s mla=%.2f mem=%li pid=%li",
	       cfg->sleeptime, cfg->options & REALTIME ? "yes" : "no",
	       cfg->options & SYNC ? "yes" : "no",
	       cfg->options & SOFTBOOT ? "yes" : "no",
	       cfg->options & FORCE ? "yes" : "no", cfg->maxLoadOne, cfg->minfreepages, getppid());

	if (cfg->options & ENABLEPING) {
		for (int cnt = 0; cnt < config_setting_length(cfg->ipAddresses); cnt++) {
			const char *ipAddress = config_setting_get_string_elem(cfg->ipAddresses,
									       cnt);

			assert(ipAddress != NULL);

			Logmsg(LOG_INFO, "ping: %s", ipAddress);
		}
	} else {
		Logmsg(LOG_INFO, "ping: no ip adresses to ping");
	}

	if (cfg->options & ENABLEPIDCHECKER) {
		for (int cnt = 0; cnt < config_setting_length(cfg->pidFiles); cnt++) {
			const char *pidFilePathName = config_setting_get_string_elem(cfg->pidFiles, cnt);

			assert(pidFilePathName != NULL);

			Logmsg(LOG_DEBUG, "pidfile: %s", pidFilePathName);
		}
	} else {
		Logmsg(LOG_INFO, "pidfile: no server process to check");
	}

	Logmsg(LOG_INFO, "test=%s(%i) repair=%s(%i) no_act=%s",
	       cfg->testexepathname == NULL ? "no" : cfg->testexepathname,
	       cfg->testBinTimeout,
	       cfg->exepathname == NULL ? "no" : cfg->exepathname,
	       cfg->repairBinTimeout, cfg->options & NOACTION ? "yes" : "no");
}

static void BlockSignals()
{
	sigset_t set;

	sigemptyset(&set);

	sigaddset(&set, SIGTERM);
	sigaddset(&set, SIGUSR2);
	sigaddset(&set, SIGINT);
	sigaddset(&set, SIGHUP);

	pthread_sigmask(SIG_BLOCK, &set, NULL);
}

static int SignalHandler(sd_event_source * s, const signalfd_siginfo * si, void *cxt)
{
	switch (sd_event_source_get_signal(s)) {
	case SIGTERM:
	case SIGINT:
		quit = 1;
		sd_event_exit((sd_event *) cxt, 0);
		break;
	case SIGHUP:
		//reload;
		break;
	}
	return 1;
}

static void InstallSignalHandlers(sd_event * event)
{
	int r1 = sd_event_add_signal(event, NULL, SIGTERM, SignalHandler, event);
	int r2 = sd_event_add_signal(event, NULL, SIGHUP, SignalHandler, event);
	int r3 = sd_event_add_signal(event, NULL, SIGUSR2, SignalHandler, event);
	int r4 = sd_event_add_signal(event, NULL, SIGINT, SignalHandler, event);

	if (r1 < 0 || r2 < 0 || r3 < 0 || r4 < 0) {
		abort();
	}
}

static int Pinger(sd_event_source * s, uint64_t usec, void *cxt)
{
	Watchdog *watchdog = (Watchdog *) cxt;
	watchdog->Ping();

	sd_event_now(sd_event_source_get_event(s), CLOCK_REALTIME, &usec);
	usec += watchdog->GetPingInterval() * 1000000;
	sd_event_add_time(sd_event_source_get_event(s), &s, CLOCK_REALTIME, usec, 1, Pinger, (void *)cxt);
	return 0;
}

static bool InstallPinger(sd_event * e, int time, Watchdog * w)
{
	sd_event_source *s = NULL;
	uint64_t usec = 0;
	w->SetPingInterval(time);

	sd_event_now(e, CLOCK_REALTIME, &usec);

	sd_event_add_time(e, &s, CLOCK_REALTIME, usec, 1, Pinger, (void *)w);
	return true;
}

int ServiceMain(int argc, char **argv, int fd, bool restarted)
{
	cfgoptions options;
	Watchdog watchdog;
	cfgoptions *tmp = &options;
	Watchdog *tmp2 = &watchdog;

	struct dbusinfo temp = {.config = &tmp,.wdt = &tmp2 };;
	temp.fd = fd;

	if (MyStrerrorInit() == false) {
		std::perror("Unable to create a new locale object");
		return EXIT_FAILURE;
	}

	int ret = ParseCommandLine(&argc, argv, &options);

	if (ret < 0) {
		return EXIT_FAILURE;
	} else if (ret != 0) {
		return EXIT_SUCCESS;
	}

	if (strcasecmp(GetExeName(), "wd_identify") == 0 || strcasecmp(GetExeName(), "wd_identify.sh") == 0) {
		options.options |= IDENTIFY;
	}

	if (ReadConfigurationFile(&options) < 0) {
		return EXIT_FAILURE;
	}

	if (options.options & IDENTIFY) {
		watchdog.Open(options.devicepath);

		ret = Identify(watchdog.GetRawTimeout(), (const char *)watchdog.GetIdentity(),
			       options.devicepath, options.options & VERBOSE);

		watchdog.Close();
		return ret;
	}

	if (PingInit(&options) < 0) {
		return EXIT_FAILURE;
	}

	if (restarted) {
		Logmsg(LOG_INFO,"restarting service (%s)", PACKAGE_VERSION);
	} else {
		Logmsg(LOG_INFO, "starting service (%s)", PACKAGE_VERSION);
	}

	PrintConfiguration(&options);

	if (ExecuteRepairScriptsPreFork(&processes, &options) == false) {
		Logmsg(LOG_ERR, "ExecuteRepairScriptsPreFork failed");
		FatalError(&options);
	}

	sd_event_source *event_source = NULL;
	sd_event *event = NULL;
	sd_event_default(&event);

	BlockSignals();
	InstallSignalHandlers(event);

	if (StartHelperThreads(&options) != 0) {
		FatalError(&options);
	}

	pthread_t dbusThread;

	if (!(options.options & NOACTION)) {
		errno = 0;

		ret = watchdog.Open(options.devicepath);

		if (errno == EBUSY && ret < 0) {
			Logmsg(LOG_ERR, "Unable to open watchdog device");
			return EXIT_FAILURE;
		} else if (ret <= -1) {
			LoadKernelModule();
			ret = watchdog.Open(options.devicepath);
		}

		if (ret <= -1) {
			FatalError(&options);
		}

		if (watchdog.ConfigureWatchdogTimeout(options.watchdogTimeout)
		    < 0 && options.watchdogTimeout != -1) {
			Logmsg(LOG_ERR, "unable to set watchdog device timeout\n");
			Logmsg(LOG_ERR, "program exiting\n");
			EndDaemon(&options, false);
			watchdog.Close();
			return EXIT_FAILURE;
		}

		if (options.sleeptime == -1) {
			options.sleeptime = watchdog.GetOptimalPingInterval();
			Logmsg(LOG_INFO, "ping interval autodetect: %i", options.sleeptime);
		}

		if (options.watchdogTimeout != -1 && watchdog.CheckWatchdogTimeout(options.sleeptime) == true) {
			Logmsg(LOG_ERR, "WDT timeout is less than or equal watchdog daemon ping interval");
			Logmsg(LOG_ERR, "Using this interval may result in spurious reboots");

			if (!(options.options & FORCE)) {
				watchdog.Close();
				Logmsg(LOG_WARNING, "use the -f option to force this configuration");
				return EXIT_FAILURE;
			}
		}

		WriteBootStatus(watchdog.GetStatus(), "/run/watchdogd.status", options.sleeptime,
				watchdog.GetRawTimeout());

		static struct identinfo i;

		strncpy(i.name, (char *)watchdog.GetIdentity(), sizeof(i.name) - 1);
		i.timeout = watchdog.GetRawTimeout();
		strncpy(i.daemonVersion, PACKAGE_VERSION, sizeof(i.daemonVersion) - 1);
		strncpy(i.deviceName, options.devicepath, sizeof(i.deviceName) - 1);
		i.flags = watchdog.GetStatus();
		i.firmwareVersion = watchdog.GetFirmwareVersion();

		CreateDetachedThread(IdentityThread, &i);
		pthread_create(&dbusThread, NULL, DbusHelper, &temp);
		InstallPinger(event, options.sleeptime, &watchdog);

		write(fd, "", sizeof(char));
	}

	if (SetupAuxManagerThread(&options) < 0) {
		FatalError(&options);
	}

	if (PlatformInit() != true) {
		FatalError(&options);
	}

	sd_event_loop(event);

	if (stop == 1) {
		while (true) {
			if (stopPing == 1) {
				if (DISARM_WATCHDOG_BEFORE_REBOOT) {
					watchdog.Close();
				}
			} else {
				watchdog.Ping();
			}

			sleep(1);
		}
	}
	pthread_cancel(dbusThread);
	pthread_join(dbusThread, NULL);
	watchdog.Close();

	unlink("/run/watchdogd.status");

	if (EndDaemon(&options, false) < 0) {
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

sig_atomic_t sigValue = -1;
pid_t pid = 0;
static int ret = 0;

static void SaHandler(int sig)
{
	sigValue = sig;
}

static int sock[2] = { 0 };

int main(int argc, char **argv)
{
	socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sock);
	pid_t pid = fork();

	if (pid == 0) {
		OnParentDeathSend(SIGKILL);
		close(sock[1]);
		DbusApiInit(sock[0]);
		_Exit(0);
	}

	close(sock[0]);

	struct sigaction act = { 0 };

	act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
	act.sa_handler = SaHandler;
	sigfillset(&act.sa_mask);

	sigaction(SIGCHLD, &act, NULL);
	sigaction(SIGTERM, &act, NULL);
	sigaction(SIGINT, &act, NULL);
	sigaction(SIGHUP, &act, NULL);
	bool restarted = false;
init:
	pid = fork();
	if (pid == 0) {
		ResetSignalHandlers(64);
		OnParentDeathSend(SIGTERM);
		_Exit(ServiceMain(argc, argv, sock[1], restarted));
	}

	do {
		pause();
		switch (sigValue) {
		case SIGHUP:
			kill(pid, SIGTERM);
			do {
				waitpid(pid, &ret, 0);
			} while (!WIFEXITED(ret) && !WIFSIGNALED(ret));
			restarted = true;
			goto init;
			break;
		case SIGCHLD:
			do {
				waitpid(pid, &ret, 0);
			} while (!WIFEXITED(ret) && !WIFSIGNALED(ret));
			break;
		case SIGINT:
		case SIGTERM:
			kill(pid, SIGTERM);
			do {
				waitpid(pid, &ret, 0);
			} while (!WIFEXITED(ret) && !WIFSIGNALED(ret));
			break;
		default:
			sigValue = -1;
			break;
		}
	} while (sigValue == -1);

	_Exit(WEXITSTATUS(ret));
}
<|endoftext|>


<commit_before>#include "core/Application.h"
#include "core/PluginManager.h"
#include "utils/utils.h"
#include "utils/preprocessor.h"

// TODO: use a smarter allocator - the important methods here are for the mixin data
class global_mixin_allocator : public dynamix::global_allocator
{
    char* alloc_mixin_data(size_t count) override { return new char[count * mixin_data_size]; }
    void dealloc_mixin_data(char* ptr) override { delete[] ptr; }

    void alloc_mixin(size_t mixin_size, size_t mixin_alignment, char*& out_buffer,
                     size_t& out_mixin_offset) override {
        const size_t size = calculate_mem_size_for_mixin(mixin_size, mixin_alignment);
        out_buffer        = new char[size];
        out_mixin_offset  = calculate_mixin_offset(out_buffer, mixin_alignment);
    }
    void dealloc_mixin(char* ptr) override { delete[] ptr; }
};

#include <bx/uint32_t.h>
#include "common.h"
#include "bgfx_utils.h"
#include "logo.h"

class ExampleHelloWorld : public entry::AppI
{
#ifndef EMSCRIPTEN
    PluginManager pluginManager;
#endif // EMSCRIPTEN
    Application app;

    void init(int _argc, char** _argv) BX_OVERRIDE {
#ifndef EMSCRIPTEN
        pluginManager.init();
#endif // EMSCRIPTEN

        Args args(_argc, _argv);

        doctest::Context context(_argc, _argv);
        //int              res =
            context.run();

        //if(context.shouldExit())
        //    return res;

        global_mixin_allocator alloc;
        dynamix::set_global_allocator(&alloc);

        app.init();

        m_width  = 1280;
        m_height = 720;
        m_debug  = BGFX_DEBUG_TEXT;
        m_reset  = BGFX_RESET_VSYNC;

        bgfx::init(args.m_type, args.m_pciId);
        bgfx::reset(m_width, m_height, m_reset);

        // Enable debug text.
        bgfx::setDebug(m_debug);

        // Set view 0 clear state.
        bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x303030ff, 1.0f, 0);
    }

    virtual int shutdown() BX_OVERRIDE {
        // Shutdown bgfx.
        bgfx::shutdown();

        return 0;
    }

    bool update() BX_OVERRIDE {
        if(!entry::processEvents(m_width, m_height, m_debug, m_reset)) {
            Application::get().update();

            // Set view 0 default viewport.
            bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height));

            // This dummy draw call is here to make sure that view 0 is cleared
            // if no other draw calls are submitted to view 0.
            bgfx::touch(0);

            // Use debug font to print information about this example.
            bgfx::dbgTextClear();
            bgfx::dbgTextImage(bx::uint16_max(uint16_t(m_width / 2 / 8), 20) - 20,
                               bx::uint16_max(uint16_t(m_height / 2 / 16), 6) - 6, 40, 12, s_logo,
                               160);
            bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/00-helloworld");
            bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Initialization and debug text.");

            bgfx::dbgTextPrintf(0, 4, 0x0f, "Color can be changed with ANSI "
                                            "\x1b[9;me\x1b[10;ms\x1b[11;mc\x1b[12;ma\x1b[13;mp\x1b["
                                            "14;me\x1b[0m code too.");

            const bgfx::Stats* stats = bgfx::getStats();
            bgfx::dbgTextPrintf(
                    0, 6, 0x0f,
                    "Backbuffer %dW x %dH in pixels, debug text %dW x %dH in characters.",
                    stats->width, stats->height, stats->textWidth, stats->textHeight);

            // Advance to next frame. Rendering thread will be kicked to
            // process submitted rendering primitives.
            bgfx::frame();

            return true;
        }

        return false;
    }

    uint32_t m_width;
    uint32_t m_height;
    uint32_t m_debug;
    uint32_t m_reset;
};

ENTRY_IMPLEMENT_MAIN(ExampleHelloWorld);
<commit_msg>fixed crash<commit_after>#include "core/Application.h"
#include "core/PluginManager.h"
#include "utils/utils.h"
#include "utils/preprocessor.h"

// TODO: use a smarter allocator - the important methods here are for the mixin data
class global_mixin_allocator : public dynamix::global_allocator
{
    char* alloc_mixin_data(size_t count) override { return new char[count * mixin_data_size]; }
    void dealloc_mixin_data(char* ptr) override { delete[] ptr; }

    void alloc_mixin(size_t mixin_size, size_t mixin_alignment, char*& out_buffer,
                     size_t& out_mixin_offset) override {
        const size_t size = calculate_mem_size_for_mixin(mixin_size, mixin_alignment);
        out_buffer        = new char[size];
        out_mixin_offset  = calculate_mixin_offset(out_buffer, mixin_alignment);
    }
    void dealloc_mixin(char* ptr) override { delete[] ptr; }
};

#include <bx/uint32_t.h>
#include "common.h"
#include "bgfx_utils.h"
#include "logo.h"

class ExampleHelloWorld : public entry::AppI
{
#ifndef EMSCRIPTEN
    PluginManager pluginManager;
#endif // EMSCRIPTEN
    global_mixin_allocator alloc;
    Application app;

    void init(int _argc, char** _argv) BX_OVERRIDE {
#ifndef EMSCRIPTEN
        pluginManager.init();
#endif // EMSCRIPTEN

        Args args(_argc, _argv);

        doctest::Context context(_argc, _argv);
        //int              res =
            context.run();

        //if(context.shouldExit())
        //    return res;

        dynamix::set_global_allocator(&alloc);

        app.init();

        m_width  = 1280;
        m_height = 720;
        m_debug  = BGFX_DEBUG_TEXT;
        m_reset  = BGFX_RESET_VSYNC;

        bgfx::init(args.m_type, args.m_pciId);
        bgfx::reset(m_width, m_height, m_reset);

        // Enable debug text.
        bgfx::setDebug(m_debug);

        // Set view 0 clear state.
        bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x303030ff, 1.0f, 0);
    }

    virtual int shutdown() BX_OVERRIDE {
        // Shutdown bgfx.
        bgfx::shutdown();

        return 0;
    }

    bool update() BX_OVERRIDE {
        if(!entry::processEvents(m_width, m_height, m_debug, m_reset)) {
            Application::get().update();

            // Set view 0 default viewport.
            bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height));

            // This dummy draw call is here to make sure that view 0 is cleared
            // if no other draw calls are submitted to view 0.
            bgfx::touch(0);

            // Use debug font to print information about this example.
            bgfx::dbgTextClear();
            bgfx::dbgTextImage(bx::uint16_max(uint16_t(m_width / 2 / 8), 20) - 20,
                               bx::uint16_max(uint16_t(m_height / 2 / 16), 6) - 6, 40, 12, s_logo,
                               160);
            bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/00-helloworld");
            bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Initialization and debug text.");

            bgfx::dbgTextPrintf(0, 4, 0x0f, "Color can be changed with ANSI "
                                            "\x1b[9;me\x1b[10;ms\x1b[11;mc\x1b[12;ma\x1b[13;mp\x1b["
                                            "14;me\x1b[0m code too.");

            const bgfx::Stats* stats = bgfx::getStats();
            bgfx::dbgTextPrintf(
                    0, 6, 0x0f,
                    "Backbuffer %dW x %dH in pixels, debug text %dW x %dH in characters.",
                    stats->width, stats->height, stats->textWidth, stats->textHeight);

            // Advance to next frame. Rendering thread will be kicked to
            // process submitted rendering primitives.
            bgfx::frame();

            return true;
        }

        return false;
    }

    uint32_t m_width;
    uint32_t m_height;
    uint32_t m_debug;
    uint32_t m_reset;
};

ENTRY_IMPLEMENT_MAIN(ExampleHelloWorld);
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//
#include "Video.h"
#include "DisplayEngine.h"
#include "Player.h"
#include "ISurface.h"

#include "../base/Exception.h"
#include "../base/Logger.h"
#include "../base/ScopeTimer.h"
#include "../base/XMLHelper.h"

#include "../graphics/Filterflipuv.h"

#include "../video/AsyncVideoDecoder.h"
#include "../video/FFMpegDecoder.h"

#include "BoostPython.h"

#include <iostream>
#include <sstream>

#ifndef _WIN32
#include <unistd.h>
#endif

using namespace boost::python;
using namespace std;

namespace avg {

bool Video::m_bInitialized = false;

Video::Video (const xmlNodePtr xmlNode, Player * pPlayer)
    : VideoBase(xmlNode, pPlayer),
      m_Filename(""),
      m_bEOFPending(false),
      m_pEOFCallback(0),
      m_FramesTooLate(0),
      m_FramesPlayed(0),
      m_pDecoder(0)
{
    m_href = getDefaultedStringAttr (xmlNode, "href", "");
    m_bLoop = getDefaultedBoolAttr (xmlNode, "loop", false);
    m_bThreaded = getDefaultedBoolAttr (xmlNode, "threaded", false);
    m_FPS = getDefaultedDoubleAttr (xmlNode, "fps", false);
    m_Filename = m_href;
    if (m_Filename != "") {
        initFilename(getPlayer(), m_Filename);
    }
    if (m_bThreaded) {
        VideoDecoderPtr pSyncDecoder = VideoDecoderPtr(new FFMpegDecoder());
        m_pDecoder = new AsyncVideoDecoder(pSyncDecoder);
    } else {
        m_pDecoder = new FFMpegDecoder();
    }
    getPlayer()->registerFrameListener(this);
}

Video::~Video ()
{
    getPlayer()->unregisterFrameListener(this);
    if (m_pDecoder) {
        delete m_pDecoder;
        m_pDecoder = 0;
    }
    if (m_pEOFCallback) {
        Py_DECREF(m_pEOFCallback);
    }
}

int Video::getNumFrames() const
{
    if (getVideoState() != Unloaded) {
        return m_pDecoder->getNumFrames();
    } else {
        AVG_TRACE(Logger::WARNING,
               "Error in Video::getNumFrames: Video not loaded.");
        return -1;
    }
}

int Video::getCurFrame() const
{
    if (getVideoState() != Unloaded) {
        return m_CurFrame;
    } else {
        AVG_TRACE(Logger::WARNING,
                "Error in Video::GetCurFrame: Video not loaded.");
        return -1;
    }
}

void Video::seekToFrame(int FrameNum)
{
    if (getVideoState() != Unloaded) {
        if (FrameNum != m_CurFrame) {
            seek(FrameNum);
        }
    } else {
        AVG_TRACE(Logger::WARNING,
                "Error in Video::SeekToFrame: Video "+getID()+" not loaded.");
    }
}

bool Video::getLoop() const
{
    return m_bLoop;
}

bool Video::isThreaded() const
{
    return m_bThreaded;
}

void Video::setEOFCallback(PyObject * pEOFCallback)
{
    if (m_pEOFCallback) {
        Py_DECREF(m_pEOFCallback);
    }
    Py_INCREF(pEOFCallback);
    m_pEOFCallback = pEOFCallback;
}

void Video::setRenderingEngines(DisplayEngine * pDisplayEngine, AudioEngine * pAudioEngine)
{
    checkReload();
    VideoBase::setRenderingEngines(pDisplayEngine, pAudioEngine);
    getAudioEngine()->addSource(this);
}

void Video::disconnect()
{
    stop();
    getAudioEngine()->removeSource(this);
    VideoBase::disconnect();
}

const string& Video::getHRef() const
{
    return m_Filename;
}

void Video::setHRef(const string& href)
{
    m_href = href;
    checkReload();
}

void Video::checkReload()
{
    string fileName (m_href);
    if (m_href != "") {
        initFilename(getPlayer(), fileName);
        if (fileName != m_Filename) {
            changeVideoState(Unloaded);
            m_Filename = fileName;
            changeVideoState(Paused);
        }
    } else {
        changeVideoState(Unloaded);
        m_Filename = "";
    }
}

string Video::getTypeStr ()
{
    return "Video";
}

void Video::onFrameEnd()
{
    if (m_bEOFPending) {
        onEOF();
        m_bEOFPending = false;
    }
}

void Video::fillAudioFrame(AudioFrame* frame)
{
    m_pDecoder->fillAudioFrame(frame->getBuffer(), frame->getSize(),
            frame->getChannels(), frame->getRate());
}

void Video::changeVideoState(VideoState NewVideoState)
{
    if (isDisplayAvailable()) {
        long long CurTime = getPlayer()->getFrameTime();
        if (NewVideoState != getVideoState()) {
            if (getVideoState() == Unloaded) {
                m_StartTime = CurTime;
                m_PauseTime = 0;
            }
            if (NewVideoState == Paused) {
                m_PauseStartTime = CurTime;
            } else if (NewVideoState == Playing && getVideoState() == Paused) {
                m_PauseTime += (CurTime-m_PauseStartTime
                        - (long long)(1000.0/m_pDecoder->getFPS()));
            }
        }
    }
    VideoBase::changeVideoState(NewVideoState);
}

void Video::seek(int DestFrame)
{

    m_pDecoder->seek(DestFrame);
    m_StartTime = getPlayer()->getFrameTime()
            -(long long)((DestFrame*1000.0)/m_pDecoder->getFPS());
    m_PauseTime = 0;
    m_PauseStartTime = getPlayer()->getFrameTime();
    m_CurFrame = DestFrame;
    setFrameAvailable(false);
}

void Video::open(YCbCrMode ycbcrMode)
{
    m_CurFrame = 0;
    m_FramesTooLate = 0;
    m_FramesPlayed = 0;
    m_pDecoder->open(m_Filename, ycbcrMode, m_bThreaded);
    m_pDecoder->setFPS(m_FPS);
}

void Video::close()
{
    m_pDecoder->close();
    if (m_FramesTooLate > 0) {
        AVG_TRACE(Logger::PROFILE, "Missed video frames for " << getID() << ": "
                << m_FramesTooLate << " of " << m_FramesPlayed);
    }
}

PixelFormat Video::getPixelFormat()
{
    return m_pDecoder->getPixelFormat();
}

IntPoint Video::getMediaSize()
{
    if (m_pDecoder)  {
        return m_pDecoder->getSize();
    } else {
        return IntPoint(0,0);
    }
}

double Video::getFPS()
{
    return m_pDecoder->getFPS();
}

long long Video::getCurTime()
{
    switch (getVideoState()) {
        case Unloaded:
            return 0;
        case Paused:
            return m_PauseStartTime-m_StartTime;
        case Playing:
            return getPlayer()->getFrameTime()-m_StartTime-m_PauseTime;
        default:
            assert(false);
            return 0;
    }
}

static ProfilingZone RenderProfilingZone("Video::render");

bool Video::renderToSurface(ISurface * pSurface)
{
    ScopeTimer Timer(RenderProfilingZone);
    PixelFormat PF = m_pDecoder->getPixelFormat();
    FrameAvailableCode FrameAvailable;
    if (PF == YCbCr420p || PF == YCbCrJ420p) {
        BitmapPtr pBmp = pSurface->lockBmp(0);
        FrameAvailable = m_pDecoder->renderToYCbCr420p(pBmp,
                pSurface->lockBmp(1), pSurface->lockBmp(2), getCurTime());
    } else {
        BitmapPtr pBmp = pSurface->lockBmp();
        FrameAvailable = m_pDecoder->renderToBmp(pBmp, getCurTime());
//        DisplayEngine::YCbCrMode ycbcrMode = getEngine()->getYCbCrMode();
//        if (ycbcrMode == DisplayEngine::OGL_MESA && pBmp->getPixelFormat() == YCbCr422) {
//            FilterFlipUV().applyInPlace(pBmp);
//        }
    }
    pSurface->unlockBmps();
    if (FrameAvailable == FA_NEW_FRAME) {
        m_FramesPlayed++;
        getDisplayEngine()->surfaceChanged(pSurface);
        m_CurFrame++;
    } else if (FrameAvailable == FA_STILL_DECODING) {
        m_FramesPlayed++;
        m_FramesTooLate++;
//        AVG_TRACE(Logger::PROFILE, "Missed video frame.");
//    } else if (FrameAvailable == FA_USE_LAST_FRAME) {
//        AVG_TRACE(Logger::PROFILE, "Video frame reused.");
    }
    if (m_pDecoder->isEOF()) {
        m_bEOFPending = true;
        if (m_bLoop) {
            seek(0);
        } else {
            changeVideoState(Paused);
        }
    }
    return (FrameAvailable == FA_NEW_FRAME);
}

void Video::onEOF()
{
    if (m_pEOFCallback) {
        PyObject * arglist = Py_BuildValue("()");
        PyObject * result = PyEval_CallObject(m_pEOFCallback, arglist);
        Py_DECREF(arglist);
        if (!result) {
            throw error_already_set();
        }
        Py_DECREF(result);
    }
}

}
<commit_msg>Support audio pausing<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//
#include "Video.h"
#include "DisplayEngine.h"
#include "Player.h"
#include "ISurface.h"

#include "../base/Exception.h"
#include "../base/Logger.h"
#include "../base/ScopeTimer.h"
#include "../base/XMLHelper.h"

#include "../graphics/Filterflipuv.h"

#include "../video/AsyncVideoDecoder.h"
#include "../video/FFMpegDecoder.h"

#include "BoostPython.h"

#include <iostream>
#include <sstream>

#ifndef _WIN32
#include <unistd.h>
#endif

using namespace boost::python;
using namespace std;

namespace avg {

bool Video::m_bInitialized = false;

Video::Video (const xmlNodePtr xmlNode, Player * pPlayer)
    : VideoBase(xmlNode, pPlayer),
      m_Filename(""),
      m_bEOFPending(false),
      m_pEOFCallback(0),
      m_FramesTooLate(0),
      m_FramesPlayed(0),
      m_pDecoder(0)
{
    m_href = getDefaultedStringAttr (xmlNode, "href", "");
    m_bLoop = getDefaultedBoolAttr (xmlNode, "loop", false);
    m_bThreaded = getDefaultedBoolAttr (xmlNode, "threaded", false);
    m_FPS = getDefaultedDoubleAttr (xmlNode, "fps", false);
    m_Filename = m_href;
    if (m_Filename != "") {
        initFilename(getPlayer(), m_Filename);
    }
    if (m_bThreaded) {
        VideoDecoderPtr pSyncDecoder = VideoDecoderPtr(new FFMpegDecoder());
        m_pDecoder = new AsyncVideoDecoder(pSyncDecoder);
    } else {
        m_pDecoder = new FFMpegDecoder();
    }
    getPlayer()->registerFrameListener(this);
}

Video::~Video ()
{
    getPlayer()->unregisterFrameListener(this);
    if (m_pDecoder) {
        delete m_pDecoder;
        m_pDecoder = 0;
    }
    if (m_pEOFCallback) {
        Py_DECREF(m_pEOFCallback);
    }
}

int Video::getNumFrames() const
{
    if (getVideoState() != Unloaded) {
        return m_pDecoder->getNumFrames();
    } else {
        AVG_TRACE(Logger::WARNING,
               "Error in Video::getNumFrames: Video not loaded.");
        return -1;
    }
}

int Video::getCurFrame() const
{
    if (getVideoState() != Unloaded) {
        return m_CurFrame;
    } else {
        AVG_TRACE(Logger::WARNING,
                "Error in Video::GetCurFrame: Video not loaded.");
        return -1;
    }
}

void Video::seekToFrame(int FrameNum)
{
    if (getVideoState() != Unloaded) {
        if (FrameNum != m_CurFrame) {
            seek(FrameNum);
        }
    } else {
        AVG_TRACE(Logger::WARNING,
                "Error in Video::SeekToFrame: Video "+getID()+" not loaded.");
    }
}

bool Video::getLoop() const
{
    return m_bLoop;
}

bool Video::isThreaded() const
{
    return m_bThreaded;
}

void Video::setEOFCallback(PyObject * pEOFCallback)
{
    if (m_pEOFCallback) {
        Py_DECREF(m_pEOFCallback);
    }
    Py_INCREF(pEOFCallback);
    m_pEOFCallback = pEOFCallback;
}

void Video::setRenderingEngines(DisplayEngine * pDisplayEngine, AudioEngine * pAudioEngine)
{
    checkReload();
    VideoBase::setRenderingEngines(pDisplayEngine, pAudioEngine);
    getAudioEngine()->addSource(this);
}

void Video::disconnect()
{
    stop();
    getAudioEngine()->removeSource(this);
    VideoBase::disconnect();
}

const string& Video::getHRef() const
{
    return m_Filename;
}

void Video::setHRef(const string& href)
{
    m_href = href;
    checkReload();
}

void Video::checkReload()
{
    string fileName (m_href);
    if (m_href != "") {
        initFilename(getPlayer(), fileName);
        if (fileName != m_Filename) {
            changeVideoState(Unloaded);
            m_Filename = fileName;
            changeVideoState(Paused);
        }
    } else {
        changeVideoState(Unloaded);
        m_Filename = "";
    }
}

string Video::getTypeStr ()
{
    return "Video";
}

void Video::onFrameEnd()
{
    if (m_bEOFPending) {
        onEOF();
        m_bEOFPending = false;
    }
}

void Video::fillAudioFrame(AudioFrame* frame)
{
    if(getVideoState() == Playing) {
        m_pDecoder->fillAudioFrame(frame->getBuffer(), frame->getSize(),
                frame->getChannels(), frame->getRate());
    }
}

void Video::changeVideoState(VideoState NewVideoState)
{
    if (isDisplayAvailable()) {
        long long CurTime = getPlayer()->getFrameTime();
        if (NewVideoState != getVideoState()) {
            if (getVideoState() == Unloaded) {
                m_StartTime = CurTime;
                m_PauseTime = 0;
            }
            if (NewVideoState == Paused) {
                m_PauseStartTime = CurTime;
            } else if (NewVideoState == Playing && getVideoState() == Paused) {
                m_PauseTime += (CurTime-m_PauseStartTime
                        - (long long)(1000.0/m_pDecoder->getFPS()));
            }
        }
    }
    VideoBase::changeVideoState(NewVideoState);
}

void Video::seek(int DestFrame)
{

    m_pDecoder->seek(DestFrame);
    m_StartTime = getPlayer()->getFrameTime()
            -(long long)((DestFrame*1000.0)/m_pDecoder->getFPS());
    m_PauseTime = 0;
    m_PauseStartTime = getPlayer()->getFrameTime();
    m_CurFrame = DestFrame;
    setFrameAvailable(false);
}

void Video::open(YCbCrMode ycbcrMode)
{
    m_CurFrame = 0;
    m_FramesTooLate = 0;
    m_FramesPlayed = 0;
    m_pDecoder->open(m_Filename, ycbcrMode, m_bThreaded);
    m_pDecoder->setFPS(m_FPS);
}

void Video::close()
{
    m_pDecoder->close();
    if (m_FramesTooLate > 0) {
        AVG_TRACE(Logger::PROFILE, "Missed video frames for " << getID() << ": "
                << m_FramesTooLate << " of " << m_FramesPlayed);
    }
}

PixelFormat Video::getPixelFormat()
{
    return m_pDecoder->getPixelFormat();
}

IntPoint Video::getMediaSize()
{
    if (m_pDecoder)  {
        return m_pDecoder->getSize();
    } else {
        return IntPoint(0,0);
    }
}

double Video::getFPS()
{
    return m_pDecoder->getFPS();
}

long long Video::getCurTime()
{
    switch (getVideoState()) {
        case Unloaded:
            return 0;
        case Paused:
            return m_PauseStartTime-m_StartTime;
        case Playing:
            return getPlayer()->getFrameTime()-m_StartTime-m_PauseTime;
        default:
            assert(false);
            return 0;
    }
}

static ProfilingZone RenderProfilingZone("Video::render");

bool Video::renderToSurface(ISurface * pSurface)
{
    ScopeTimer Timer(RenderProfilingZone);
    PixelFormat PF = m_pDecoder->getPixelFormat();
    FrameAvailableCode FrameAvailable;
    if (PF == YCbCr420p || PF == YCbCrJ420p) {
        BitmapPtr pBmp = pSurface->lockBmp(0);
        FrameAvailable = m_pDecoder->renderToYCbCr420p(pBmp,
                pSurface->lockBmp(1), pSurface->lockBmp(2), getCurTime());
    } else {
        BitmapPtr pBmp = pSurface->lockBmp();
        FrameAvailable = m_pDecoder->renderToBmp(pBmp, getCurTime());
//        DisplayEngine::YCbCrMode ycbcrMode = getEngine()->getYCbCrMode();
//        if (ycbcrMode == DisplayEngine::OGL_MESA && pBmp->getPixelFormat() == YCbCr422) {
//            FilterFlipUV().applyInPlace(pBmp);
//        }
    }
    pSurface->unlockBmps();
    if (FrameAvailable == FA_NEW_FRAME) {
        m_FramesPlayed++;
        getDisplayEngine()->surfaceChanged(pSurface);
        m_CurFrame++;
    } else if (FrameAvailable == FA_STILL_DECODING) {
        m_FramesPlayed++;
        m_FramesTooLate++;
//        AVG_TRACE(Logger::PROFILE, "Missed video frame.");
//    } else if (FrameAvailable == FA_USE_LAST_FRAME) {
//        AVG_TRACE(Logger::PROFILE, "Video frame reused.");
    }
    if (m_pDecoder->isEOF()) {
        m_bEOFPending = true;
        if (m_bLoop) {
            seek(0);
        } else {
            changeVideoState(Paused);
        }
    }
    return (FrameAvailable == FA_NEW_FRAME);
}

void Video::onEOF()
{
    if (m_pEOFCallback) {
        PyObject * arglist = Py_BuildValue("()");
        PyObject * result = PyEval_CallObject(m_pEOFCallback, arglist);
        Py_DECREF(arglist);
        if (!result) {
            throw error_already_set();
        }
        Py_DECREF(result);
    }
}

}
<|endoftext|>


<commit_before>// Copyright © 2016-2017, Prosoft Engineering, Inc. (A.K.A "Prosoft")
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Prosoft nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL PROSOFT ENGINEERING, INC. BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef PS_CORE_FILESYSTEM_ITERATOR_HPP
#define PS_CORE_FILESYSTEM_ITERATOR_HPP

#include <iterator>
#include <memory>
#include <type_traits>

namespace prosoft {
namespace filesystem {
inline namespace v1 {

class file_status;

class directory_entry {
    // C++ states that a name within a scope must have a unique meaning.
    // Therefore path() conflicts with the use of the 'path' type from our namespace and is ambigous.
    // GCC warns about this, clang does not.
    using path_type = prosoft::filesystem::path;
    path_type m_path;

public:
    directory_entry() noexcept(std::is_nothrow_constructible<path_type>::value) : m_path() {}
    ~directory_entry() = default;
    PS_DEFAULT_COPY(directory_entry);
    PS_DEFAULT_MOVE(directory_entry);
    explicit directory_entry(const path_type& p)
        : m_path(p) {}
    // Extensions //
    explicit directory_entry(path_type&& p) noexcept(std::is_nothrow_move_constructible<path_type>::value)
        : m_path(std::move(p)) {}

    void assign(path_type&& p) {
        m_path = std::move(p);
    }
    // Extensions //

    void assign(const path_type& p) {
        m_path = p;
    }

    void replace_filename(const path_type& p) {
        m_path.replace_filename(p);
    }

    operator const path_type&() const noexcept {
        return this->path();
    }

    const path_type& path() const & noexcept {
        return m_path;
    }

    path_type path() && noexcept(std::is_nothrow_move_constructible<path_type>::value) {
        return path_type{std::move(m_path)};
    }

    file_status status() const;
    file_status status(error_code&) const noexcept;

    file_status symlink_status() const;
    file_status symlink_status(error_code&) const noexcept;
};

enum class directory_options : unsigned {
    none,
    follow_directory_symlink,
    skip_permission_denied,

    // Extensions
    include_created_events = 1U<<16, // change_iterator
    include_modified_events = 1U<<17, // change_iterator

    skip_subdirectory_descendants = 1U<<20,
    skip_hidden_descendants = 1U<<21,
    skip_package_descendants = 1U<<22, // macOS
    follow_mountpoints = 1U<<23,
    include_postorder_directories = 1U<<24,
    // By default, we mimic the behavior of NSDirectoryEnumerator and skip "._" files.
    // However, unlike NSDE, we only skip "._" files that have a sibling of the same name. Orphan "._" files are always returned.
    // If for some reason you want paired "._" files too, set this. Normally it should not be set as the system automatically handles pairs.
    include_apple_double_files = 1U<<25, // macOS

    // Internal state
    reserved_state_skip_descendants = 1U<<30,
    reserved_state_postorder = 1U<<31,
    reserved_state_mask = 0xf0000000,
};
PS_ENUM_BITMASK_OPS(directory_options);

constexpr directory_options make_public(directory_options opts) {
    return opts & ~directory_options::reserved_state_mask;
}

using iterator_depth_type = int;

namespace ifilesystem {
class iterator_state {
    path m_root;
    directory_entry m_current;
    directory_options m_opts;

protected:
    virtual path next(error_code&) = 0;

    void set(directory_options opts) noexcept {
        m_opts |= opts & directory_options::reserved_state_mask;
    }

    void clear(directory_options opts) noexcept {
        m_opts &= ~(opts & directory_options::reserved_state_mask);
    }

    bool is_current_empty() const {
        return m_current.path().empty();
    }

public:
    iterator_state() = default;
    iterator_state(const path& p, directory_options opts, error_code&)
        : m_root(p)
        , m_current()
        , m_opts(opts) {}
    virtual ~iterator_state() = default;

    const path& root() const noexcept {
        return m_root;
    }

    const directory_entry& current() const noexcept {
        return m_current;
    }

    directory_options options() const noexcept {
        return m_opts;
    }

    void increment(error_code& ec) {
        m_current = directory_entry{next(ec)};
    }

    virtual bool equal_to(const iterator_state*) const;

    virtual void pop() {}

    virtual iterator_depth_type depth() const noexcept {
        return 0;
    }

    virtual void skip_descendants() {}

    virtual bool at_end() const {
        return is_current_empty();
    }
};

using iterator_state_ptr = std::shared_ptr<ifilesystem::iterator_state>;

struct null_iterator_options {};

struct iterator_traits {
    static constexpr directory_options required = directory_options::skip_subdirectory_descendants;
    static constexpr directory_options not_supported = directory_options::none;
    static constexpr directory_options defaults = required;
    using configuration_type = null_iterator_options;
};

struct recursive_iterator_traits {
    static constexpr directory_options required = directory_options::none;
    static constexpr directory_options not_supported = directory_options::skip_subdirectory_descendants;
    static constexpr directory_options defaults = required;
    using configuration_type = null_iterator_options;
};

template <class Traits>
struct is_recursive {
    static constexpr bool value = is_set(Traits::not_supported & directory_options::skip_subdirectory_descendants);
};

static_assert(!is_recursive<iterator_traits>::value, "WTF?");
static_assert(is_recursive<recursive_iterator_traits>::value, "WTF?");

iterator_state_ptr make_iterator_state(const path&, directory_options, iterator_traits::configuration_type, error_code&, iterator_traits);

inline iterator_state_ptr
make_iterator_state(const path& p, directory_options opts, recursive_iterator_traits::configuration_type, error_code& ec, recursive_iterator_traits) {
    return make_iterator_state(p, opts, iterator_traits::configuration_type{}, ec, iterator_traits{});
}

const error_code& permission_denied_error();

template <class Traits>
inline const error_code& permission_denied_error(Traits) {
    return permission_denied_error();
}

template <class Traits>
constexpr directory_options make_options(directory_options opts) {
    return (make_public(opts) | Traits::required) & ~Traits::not_supported;
}
} // ifilesystem

template <class Traits>
class basic_iterator {
    ifilesystem::iterator_state_ptr m_i;

    const path& root_or_empty() const {
        static const path empty;
        return m_i ? m_i->root() : empty;
    }

    void clear_if_denied(error_code& ec) const;

    template <typename Recurse>
    struct resurse_only : public std::enable_if<ifilesystem::is_recursive<Traits>::value, Recurse> {};

    template <typename Recurse>
    using recurse_only_t = typename resurse_only<Recurse>::type;

    friend Traits;
public:
    using traits_type = Traits;
    using configuration_type = typename traits_type::configuration_type;
    using value_type = directory_entry;
    using difference_type = ptrdiff_t;
    using pointer = const value_type*;
    using reference = const value_type&;
    using iterator_category = std::input_iterator_tag;

    basic_iterator() noexcept(std::is_nothrow_constructible<decltype(m_i)>::value) = default;
    explicit basic_iterator(const path&);
    basic_iterator(const path&, error_code&);
    basic_iterator(const path&, directory_options);
    basic_iterator(const path&, directory_options, error_code&);
    basic_iterator(const path&, directory_options, configuration_type&&);
    basic_iterator(const path&, directory_options, configuration_type&&, error_code&);
    basic_iterator(const basic_iterator&) = default;
    basic_iterator(basic_iterator&&) noexcept(std::is_nothrow_move_constructible<decltype(m_i)>::value) = default;
    ~basic_iterator() = default;

    directory_options options() const;
    const directory_entry& operator*() const;
    const directory_entry* operator->() const;

    basic_iterator& operator=(const basic_iterator&) = default;
    basic_iterator& operator=(basic_iterator&&) noexcept(std::is_nothrow_move_constructible<decltype(m_i)>::value) = default;
    basic_iterator& operator++();
    basic_iterator& increment(error_code&);

    bool operator==(const basic_iterator&) const;

    // Recursive only
    template <typename Recurse = void>
    iterator_depth_type depth(recurse_only_t<Recurse>* = 0) const noexcept {
        return m_i ? m_i->depth() : iterator_depth_type{};
    }

    template <typename Recurse = void>
    bool recursion_pending(recurse_only_t<Recurse>* = 0) const noexcept {
        return m_i ? !is_set(m_i->options() & directory_options::reserved_state_skip_descendants) : false;
    }

    template <typename Recurse = void>
    void pop(recurse_only_t<Recurse>* = 0) {
        if (m_i) {
            m_i->pop();
        }
    }

    template <typename Recurse = void>
    void disable_recursion_pending(recurse_only_t<Recurse>* = 0) {
        if (m_i) {
            m_i->skip_descendants();
        }
    }

    // Extensions
    basic_iterator& operator++(int);

    static constexpr directory_options default_options() {
        return Traits::defaults;
    }
};

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p)
    : basic_iterator<Traits>::basic_iterator(p, default_options()) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, error_code& ec)
    : basic_iterator<Traits>::basic_iterator(p, default_options(), ec) {
}

template <class Traits>
basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts)
    : basic_iterator<Traits>::basic_iterator(p, opts, configuration_type{}) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts, error_code& ec)
    : basic_iterator<Traits>::basic_iterator(p, opts, configuration_type{}, ec) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts, configuration_type&& t, error_code& ec)
    : m_i(ifilesystem::make_iterator_state(p, ifilesystem::make_options<Traits>(opts), std::move(t), ec, traits_type{})) {
    increment(ec);
    clear_if_denied(ec);
}

template <class Traits>
const directory_entry& basic_iterator<Traits>::operator*() const {
    static const directory_entry empty{};
    return m_i ? m_i->current() : empty;
}

template <class Traits>
inline const directory_entry* basic_iterator<Traits>::operator->() const {
    return &operator*();
}

template <class Traits>
directory_options basic_iterator<Traits>::options() const {
    return m_i ? make_public(m_i->options()) : directory_options::none;
}

template <class Traits>
basic_iterator<Traits>& basic_iterator<Traits>::increment(error_code& ec) {
    if (m_i) {
        m_i->increment(ec);
        if (m_i->at_end()) {
            m_i.reset(); // become end
        }
    }
    return *this;
}

template <class Traits>
bool basic_iterator<Traits>::operator==(const basic_iterator<Traits>& other) const {
    auto ti = m_i.get();
    auto oi = other.m_i.get();
    return ti == oi || (ti && oi && ti->equal_to(oi));
}

template <class Traits>
inline bool operator!=(const basic_iterator<Traits>& lhs, const basic_iterator<Traits>& rhs) {
    return !lhs.operator==(rhs);
}

template <class Traits>
inline basic_iterator<Traits> begin(basic_iterator<Traits> i) {
    return i;
}

template <class Traits>
inline basic_iterator<Traits> end(const basic_iterator<Traits>&) {
    return basic_iterator<Traits>{};
}

template <class Traits>
void basic_iterator<Traits>::clear_if_denied(error_code& ec) const {
    if (is_set(options() & directory_options::skip_permission_denied) && ec == ifilesystem::permission_denied_error(Traits{})) {
        ec.clear();
    }
}

// Extensions
template <class Traits>
inline basic_iterator<Traits>& basic_iterator<Traits>::operator++(int) {
    return operator++(); // // XXX: Input iter one-pass semantics.
}

} // v1
} // filesystem
} // prosoft

#endif // PS_CORE_FILESYSTEM_ITERATOR_HPP
<commit_msg>Rename null_iterator_options<commit_after>// Copyright © 2016-2017, Prosoft Engineering, Inc. (A.K.A "Prosoft")
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Prosoft nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL PROSOFT ENGINEERING, INC. BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef PS_CORE_FILESYSTEM_ITERATOR_HPP
#define PS_CORE_FILESYSTEM_ITERATOR_HPP

#include <iterator>
#include <memory>
#include <type_traits>

namespace prosoft {
namespace filesystem {
inline namespace v1 {

class file_status;

class directory_entry {
    // C++ states that a name within a scope must have a unique meaning.
    // Therefore path() conflicts with the use of the 'path' type from our namespace and is ambigous.
    // GCC warns about this, clang does not.
    using path_type = prosoft::filesystem::path;
    path_type m_path;

public:
    directory_entry() noexcept(std::is_nothrow_constructible<path_type>::value) : m_path() {}
    ~directory_entry() = default;
    PS_DEFAULT_COPY(directory_entry);
    PS_DEFAULT_MOVE(directory_entry);
    explicit directory_entry(const path_type& p)
        : m_path(p) {}
    // Extensions //
    explicit directory_entry(path_type&& p) noexcept(std::is_nothrow_move_constructible<path_type>::value)
        : m_path(std::move(p)) {}

    void assign(path_type&& p) {
        m_path = std::move(p);
    }
    // Extensions //

    void assign(const path_type& p) {
        m_path = p;
    }

    void replace_filename(const path_type& p) {
        m_path.replace_filename(p);
    }

    operator const path_type&() const noexcept {
        return this->path();
    }

    const path_type& path() const & noexcept {
        return m_path;
    }

    path_type path() && noexcept(std::is_nothrow_move_constructible<path_type>::value) {
        return path_type{std::move(m_path)};
    }

    file_status status() const;
    file_status status(error_code&) const noexcept;

    file_status symlink_status() const;
    file_status symlink_status(error_code&) const noexcept;
};

enum class directory_options : unsigned {
    none,
    follow_directory_symlink,
    skip_permission_denied,

    // Extensions
    include_created_events = 1U<<16, // change_iterator
    include_modified_events = 1U<<17, // change_iterator

    skip_subdirectory_descendants = 1U<<20,
    skip_hidden_descendants = 1U<<21,
    skip_package_descendants = 1U<<22, // macOS
    follow_mountpoints = 1U<<23,
    include_postorder_directories = 1U<<24,
    // By default, we mimic the behavior of NSDirectoryEnumerator and skip "._" files.
    // However, unlike NSDE, we only skip "._" files that have a sibling of the same name. Orphan "._" files are always returned.
    // If for some reason you want paired "._" files too, set this. Normally it should not be set as the system automatically handles pairs.
    include_apple_double_files = 1U<<25, // macOS

    // Internal state
    reserved_state_skip_descendants = 1U<<30,
    reserved_state_postorder = 1U<<31,
    reserved_state_mask = 0xf0000000,
};
PS_ENUM_BITMASK_OPS(directory_options);

constexpr directory_options make_public(directory_options opts) {
    return opts & ~directory_options::reserved_state_mask;
}

using iterator_depth_type = int;

namespace ifilesystem {
class iterator_state {
    path m_root;
    directory_entry m_current;
    directory_options m_opts;

protected:
    virtual path next(error_code&) = 0;

    void set(directory_options opts) noexcept {
        m_opts |= opts & directory_options::reserved_state_mask;
    }

    void clear(directory_options opts) noexcept {
        m_opts &= ~(opts & directory_options::reserved_state_mask);
    }

    bool is_current_empty() const {
        return m_current.path().empty();
    }

public:
    iterator_state() = default;
    iterator_state(const path& p, directory_options opts, error_code&)
        : m_root(p)
        , m_current()
        , m_opts(opts) {}
    virtual ~iterator_state() = default;

    const path& root() const noexcept {
        return m_root;
    }

    const directory_entry& current() const noexcept {
        return m_current;
    }

    directory_options options() const noexcept {
        return m_opts;
    }

    void increment(error_code& ec) {
        m_current = directory_entry{next(ec)};
    }

    virtual bool equal_to(const iterator_state*) const;

    virtual void pop() {}

    virtual iterator_depth_type depth() const noexcept {
        return 0;
    }

    virtual void skip_descendants() {}

    virtual bool at_end() const {
        return is_current_empty();
    }
};

using iterator_state_ptr = std::shared_ptr<ifilesystem::iterator_state>;

struct null_iterator_config {};

struct iterator_traits {
    static constexpr directory_options required = directory_options::skip_subdirectory_descendants;
    static constexpr directory_options not_supported = directory_options::none;
    static constexpr directory_options defaults = required;
    using configuration_type = null_iterator_config;
};

struct recursive_iterator_traits {
    static constexpr directory_options required = directory_options::none;
    static constexpr directory_options not_supported = directory_options::skip_subdirectory_descendants;
    static constexpr directory_options defaults = required;
    using configuration_type = null_iterator_config;
};

template <class Traits>
struct is_recursive {
    static constexpr bool value = is_set(Traits::not_supported & directory_options::skip_subdirectory_descendants);
};

static_assert(!is_recursive<iterator_traits>::value, "WTF?");
static_assert(is_recursive<recursive_iterator_traits>::value, "WTF?");

iterator_state_ptr make_iterator_state(const path&, directory_options, iterator_traits::configuration_type, error_code&, iterator_traits);

inline iterator_state_ptr
make_iterator_state(const path& p, directory_options opts, recursive_iterator_traits::configuration_type, error_code& ec, recursive_iterator_traits) {
    return make_iterator_state(p, opts, iterator_traits::configuration_type{}, ec, iterator_traits{});
}

const error_code& permission_denied_error();

template <class Traits>
inline const error_code& permission_denied_error(Traits) {
    return permission_denied_error();
}

template <class Traits>
constexpr directory_options make_options(directory_options opts) {
    return (make_public(opts) | Traits::required) & ~Traits::not_supported;
}
} // ifilesystem

template <class Traits>
class basic_iterator {
    ifilesystem::iterator_state_ptr m_i;

    const path& root_or_empty() const {
        static const path empty;
        return m_i ? m_i->root() : empty;
    }

    void clear_if_denied(error_code& ec) const;

    template <typename Recurse>
    struct resurse_only : public std::enable_if<ifilesystem::is_recursive<Traits>::value, Recurse> {};

    template <typename Recurse>
    using recurse_only_t = typename resurse_only<Recurse>::type;

    friend Traits;
public:
    using traits_type = Traits;
    using configuration_type = typename traits_type::configuration_type;
    using value_type = directory_entry;
    using difference_type = ptrdiff_t;
    using pointer = const value_type*;
    using reference = const value_type&;
    using iterator_category = std::input_iterator_tag;

    basic_iterator() noexcept(std::is_nothrow_constructible<decltype(m_i)>::value) = default;
    explicit basic_iterator(const path&);
    basic_iterator(const path&, error_code&);
    basic_iterator(const path&, directory_options);
    basic_iterator(const path&, directory_options, error_code&);
    basic_iterator(const path&, directory_options, configuration_type&&);
    basic_iterator(const path&, directory_options, configuration_type&&, error_code&);
    basic_iterator(const basic_iterator&) = default;
    basic_iterator(basic_iterator&&) noexcept(std::is_nothrow_move_constructible<decltype(m_i)>::value) = default;
    ~basic_iterator() = default;

    directory_options options() const;
    const directory_entry& operator*() const;
    const directory_entry* operator->() const;

    basic_iterator& operator=(const basic_iterator&) = default;
    basic_iterator& operator=(basic_iterator&&) noexcept(std::is_nothrow_move_constructible<decltype(m_i)>::value) = default;
    basic_iterator& operator++();
    basic_iterator& increment(error_code&);

    bool operator==(const basic_iterator&) const;

    // Recursive only
    template <typename Recurse = void>
    iterator_depth_type depth(recurse_only_t<Recurse>* = 0) const noexcept {
        return m_i ? m_i->depth() : iterator_depth_type{};
    }

    template <typename Recurse = void>
    bool recursion_pending(recurse_only_t<Recurse>* = 0) const noexcept {
        return m_i ? !is_set(m_i->options() & directory_options::reserved_state_skip_descendants) : false;
    }

    template <typename Recurse = void>
    void pop(recurse_only_t<Recurse>* = 0) {
        if (m_i) {
            m_i->pop();
        }
    }

    template <typename Recurse = void>
    void disable_recursion_pending(recurse_only_t<Recurse>* = 0) {
        if (m_i) {
            m_i->skip_descendants();
        }
    }

    // Extensions
    basic_iterator& operator++(int);

    static constexpr directory_options default_options() {
        return Traits::defaults;
    }
};

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p)
    : basic_iterator<Traits>::basic_iterator(p, default_options()) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, error_code& ec)
    : basic_iterator<Traits>::basic_iterator(p, default_options(), ec) {
}

template <class Traits>
basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts)
    : basic_iterator<Traits>::basic_iterator(p, opts, configuration_type{}) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts, error_code& ec)
    : basic_iterator<Traits>::basic_iterator(p, opts, configuration_type{}, ec) {
}

template <class Traits>
inline basic_iterator<Traits>::basic_iterator(const path& p, directory_options opts, configuration_type&& t, error_code& ec)
    : m_i(ifilesystem::make_iterator_state(p, ifilesystem::make_options<Traits>(opts), std::move(t), ec, traits_type{})) {
    increment(ec);
    clear_if_denied(ec);
}

template <class Traits>
const directory_entry& basic_iterator<Traits>::operator*() const {
    static const directory_entry empty{};
    return m_i ? m_i->current() : empty;
}

template <class Traits>
inline const directory_entry* basic_iterator<Traits>::operator->() const {
    return &operator*();
}

template <class Traits>
directory_options basic_iterator<Traits>::options() const {
    return m_i ? make_public(m_i->options()) : directory_options::none;
}

template <class Traits>
basic_iterator<Traits>& basic_iterator<Traits>::increment(error_code& ec) {
    if (m_i) {
        m_i->increment(ec);
        if (m_i->at_end()) {
            m_i.reset(); // become end
        }
    }
    return *this;
}

template <class Traits>
bool basic_iterator<Traits>::operator==(const basic_iterator<Traits>& other) const {
    auto ti = m_i.get();
    auto oi = other.m_i.get();
    return ti == oi || (ti && oi && ti->equal_to(oi));
}

template <class Traits>
inline bool operator!=(const basic_iterator<Traits>& lhs, const basic_iterator<Traits>& rhs) {
    return !lhs.operator==(rhs);
}

template <class Traits>
inline basic_iterator<Traits> begin(basic_iterator<Traits> i) {
    return i;
}

template <class Traits>
inline basic_iterator<Traits> end(const basic_iterator<Traits>&) {
    return basic_iterator<Traits>{};
}

template <class Traits>
void basic_iterator<Traits>::clear_if_denied(error_code& ec) const {
    if (is_set(options() & directory_options::skip_permission_denied) && ec == ifilesystem::permission_denied_error(Traits{})) {
        ec.clear();
    }
}

// Extensions
template <class Traits>
inline basic_iterator<Traits>& basic_iterator<Traits>::operator++(int) {
    return operator++(); // // XXX: Input iter one-pass semantics.
}

} // v1
} // filesystem
} // prosoft

#endif // PS_CORE_FILESYSTEM_ITERATOR_HPP
<|endoftext|>


<commit_before>#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "MuMaterial.h"
#include "counter_point.hpp"

using namespace std;

void ValidateArguments (int argc, char* argv[]);
void PrintVector (vector<int> v, string message);
vector<int> GetHarmonicRange (int note_pitch);
vector<int> FixPitchsToScale (int scale_pitch, vector<int> pitchs);
vector<int> RemoveUnisonFromPitchs(int unison_pitch, vector<int> pitchs);

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

    string output_path = argc > 2 ? argv[2] : "./";
    string score_file_path = argv[1];

    MuInit();
    MuMaterial material;
    material.LoadScore(argv[1]);

    CounterPoint counter_point(material);
    counter_point.SetScalePitch(60);
    counter_point.PrintHarmonicPitchs();

    MuMaterial counter_point_material = counter_point.GenerateCounterPointMaterial();

    // material.Show();
    // counter_point_material.Show();

    material.AddVoices(1);
    material.SetVoice(1, counter_point_material, 0);

    material.SetInstrument(0, 2);
    material.SetInstrument(1, 3);

    material.Show();

    material.SetDefaultFunctionTables();
    material.Score(output_path + "score");
    material.Orchestra(output_path + "orchestra");

    // counter_point_material.SetDefaultFunctionTables();
    // counter_point_material.Score(output_path + "score_cp");
    // counter_point_material.Orchestra(output_path + "orchestra_cp");

    // MuNote note;
    // MuMaterial material;

    // note.SetPitch(60);
    // material += note;

    // note.SetPitch(62);
    // material += note;

    // note.SetPitch(64);
    // material += note;

    // CounterPoint counter_point(material);
    // counter_point.PrintHarmonicPitchs();

    return 0;
}

void ValidateArguments (int argc, char* argv[])
{
    bool has_arguments = argc < 2;
    if (has_arguments)
    {
        cout << "Usage: " << argv[0] << " [score_file_path] [output_path]" << endl;
        exit(-1);
    }
}

void PrintVector (vector<int> v, string message)
{
    cout << message << ": ";
    for (unsigned int index = 0; index < v.size(); index++)
    {
        cout << v[index] << " ";
    }
    cout << endl;
}

vector<int> GetHarmonicRange (int note_pitch)
{
    int unison = note_pitch;
    int third_minor = note_pitch - 3;
    int third_major = note_pitch - 4;
    int fifith_perfect = note_pitch - 7;
    int sixth_minor = note_pitch - 8;
    int sixth_major = note_pitch - 9;

    vector<int> harmonic_range {unison, third_minor, third_major,
                                  fifith_perfect, sixth_minor, sixth_major};

    return harmonic_range;
}

vector<int> FixPitchsToScale (int scale_pitch, vector<int> pitchs)
{
    scale_pitch = scale_pitch % 12;

    vector<int> scale_pitchs = { 0 + scale_pitch, 2 + scale_pitch,
                                 4 + scale_pitch, 5 + scale_pitch,
                                 7 + scale_pitch, 9 + scale_pitch,
                                 11 + scale_pitch };

    vector<int> pitchs_on_scale;

    for (unsigned int index = 0; index < pitchs.size(); index++)
    {
        int pitch = pitchs[index] % 12;
        bool found_pitch = find(scale_pitchs.begin(), scale_pitchs.end(),
                                pitch) != scale_pitchs.end();

        if(found_pitch)
        {
            pitchs_on_scale.push_back(pitchs[index]);
        }
    }

    return pitchs_on_scale;
}

vector<int> RemoveUnisonFromPitchs(int unison_pitch, vector<int> pitchs)
{
    vector<int> pitchs_without_unison = pitchs;

    pitchs_without_unison.erase(remove(pitchs_without_unison.begin(),
                                       pitchs_without_unison.end(),
                                       unison_pitch),
                                pitchs_without_unison.end());

    return pitchs_without_unison;
}
<commit_msg>Add check to verify a voice to a note<commit_after>#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "MuMaterial.h"
#include "counter_point.hpp"
#include "voice.hpp"

using namespace std;

void ValidateArguments (int argc, char* argv[]);
void PrintVector (vector<int> v, string message);
vector<int> GetHarmonicRange (int note_pitch);
vector<int> FixPitchsToScale (int scale_pitch, vector<int> pitchs);
vector<int> RemoveUnisonFromPitchs(int unison_pitch, vector<int> pitchs);

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

    string output_path = argc > 2 ? argv[2] : "./";
    string score_file_path = argv[1];

    MuInit();
    MuMaterial material;
    material.LoadScore(argv[1]);

    CounterPoint counter_point(material);
    counter_point.SetScalePitch(60);
    counter_point.PrintHarmonicPitchs();

    MuMaterial counter_point_material = counter_point.GenerateCounterPointMaterial();

    // material.Show();
    // counter_point_material.Show();

    material.AddVoices(1);
    material.SetVoice(1, counter_point_material, 0);

    material.SetInstrument(0, 2);
    material.SetInstrument(1, 3);

    material.Show();

    material.SetDefaultFunctionTables();
    material.Score(output_path + "score");
    material.Orchestra(output_path + "orchestra");

    Voice::Manager voice_manager;
    voice_manager.AddVoice("Soprano", 60, 79);
    voice_manager.AddVoice("Contralto", 55, 72);
    voice_manager.AddVoice("Tenor", 47, 67);
    voice_manager.AddVoice("Baixo", 40, 60);

    Voice voice = voice_manager.GetVoice(62);

    cout << "Voice: " << voice.name << endl;

    // counter_point_material.SetDefaultFunctionTables();
    // counter_point_material.Score(output_path + "score_cp");
    // counter_point_material.Orchestra(output_path + "orchestra_cp");

    // MuNote note;
    // MuMaterial material;

    // note.SetPitch(60);
    // material += note;

    // note.SetPitch(62);
    // material += note;

    // note.SetPitch(64);
    // material += note;

    // CounterPoint counter_point(material);
    // counter_point.PrintHarmonicPitchs();

    return 0;
}

void ValidateArguments (int argc, char* argv[])
{
    bool has_arguments = argc < 2;
    if (has_arguments)
    {
        cout << "Usage: " << argv[0] << " [score_file_path] [output_path]" << endl;
        exit(-1);
    }
}

void PrintVector (vector<int> v, string message)
{
    cout << message << ": ";
    for (unsigned int index = 0; index < v.size(); index++)
    {
        cout << v[index] << " ";
    }
    cout << endl;
}

vector<int> GetHarmonicRange (int note_pitch)
{
    int unison = note_pitch;
    int third_minor = note_pitch - 3;
    int third_major = note_pitch - 4;
    int fifith_perfect = note_pitch - 7;
    int sixth_minor = note_pitch - 8;
    int sixth_major = note_pitch - 9;

    vector<int> harmonic_range {unison, third_minor, third_major,
                                  fifith_perfect, sixth_minor, sixth_major};

    return harmonic_range;
}

vector<int> FixPitchsToScale (int scale_pitch, vector<int> pitchs)
{
    scale_pitch = scale_pitch % 12;

    vector<int> scale_pitchs = { 0 + scale_pitch, 2 + scale_pitch,
                                 4 + scale_pitch, 5 + scale_pitch,
                                 7 + scale_pitch, 9 + scale_pitch,
                                 11 + scale_pitch };

    vector<int> pitchs_on_scale;

    for (unsigned int index = 0; index < pitchs.size(); index++)
    {
        int pitch = pitchs[index] % 12;
        bool found_pitch = find(scale_pitchs.begin(), scale_pitchs.end(),
                                pitch) != scale_pitchs.end();

        if(found_pitch)
        {
            pitchs_on_scale.push_back(pitchs[index]);
        }
    }

    return pitchs_on_scale;
}

vector<int> RemoveUnisonFromPitchs(int unison_pitch, vector<int> pitchs)
{
    vector<int> pitchs_without_unison = pitchs;

    pitchs_without_unison.erase(remove(pitchs_without_unison.begin(),
                                       pitchs_without_unison.end(),
                                       unison_pitch),
                                pitchs_without_unison.end());

    return pitchs_without_unison;
}
<|endoftext|>