<commit_before>// Copyright (C) 2016 xaizek <xaizek@openmailbox.org>
//
// This file is part of uncov.
//
// uncov is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// uncov 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with uncov.  If not, see <http://www.gnu.org/licenses/>.

#include <sys/ioctl.h>
#include <sys/wait.h>
#include <termios.h>

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/optional.hpp>
#include <boost/scope_exit.hpp>

#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <vector>

#include "BuildHistory.hpp"
#include "FilePrinter.hpp"
#include "Repository.hpp"
#include "SubCommand.hpp"
#include "TablePrinter.hpp"
#include "decoration.hpp"

static void printBuildHeader(const Build &build);
static void printFile(const Repository *repo, const Build &build,
                      const File &file, FilePrinter &printer);
static void printFileHeader(const File &file);
static void printLineSeparator();

class CovInfo
{
public:
    CovInfo() = default;
    template <typename T>
    explicit CovInfo(const T &coverable)
        : coveredCount(coverable.getCoveredCount()),
          uncoveredCount(coverable.getUncoveredCount())
    {
    }

public:
    void addCovered(int num)
    {
        coveredCount += num;
    }

    void addUncovered(int num)
    {
        uncoveredCount += num;
    }

    int getCoveredCount() const
    {
        return coveredCount;
    }

    int getUncoveredCount() const
    {
        return uncoveredCount;
    }

    std::string formatCoverageRate() const
    {
        if (getRelevantLines() == 0) {
            return "100";
        }

        auto rate = 100*coveredCount/static_cast<float>(getRelevantLines());

        std::ostringstream oss;
        oss << std::fixed << std::right
            << std::setprecision(2) << rate;
        return oss.str();
    }

    std::string formatLines(const std::string &separator) const
    {
        return std::to_string(coveredCount) + separator
             + std::to_string(getRelevantLines());
    }

private:
    int getRelevantLines() const
    {
        return coveredCount + uncoveredCount;
    }

private:
    int coveredCount = 0;
    int uncoveredCount = 0;
};

class RedirectToPager
{
    template <typename T>
    using stream_buffer = boost::iostreams::stream_buffer<T>;
    using file_descriptor_sink = boost::iostreams::file_descriptor_sink;

public:
    RedirectToPager()
    {
        int pipePair[2];
        if (pipe(pipePair) != 0) {
            throw std::runtime_error("Failed to create a pipe");
        }
        BOOST_SCOPE_EXIT_ALL(pipePair) { close(pipePair[0]); };

        pid = fork();
        if (pid == -1) {
            close(pipePair[1]);
            throw std::runtime_error("Fork has failed");
        }
        if (pid == 0) {
            close(pipePair[1]);
            if (dup2(pipePair[0], STDIN_FILENO) == -1) {
                _Exit(EXIT_FAILURE);
            }
            close(pipePair[0]);
            // XXX: hard-coded invocation of less.
            execlp("less", "less", "-R", static_cast<char *>(nullptr));
            _Exit(127);
        }

        out.open(file_descriptor_sink(pipePair[1],
                                      boost::iostreams::close_handle));
        rdbuf = std::cout.rdbuf(&out);
    }

    ~RedirectToPager()
    {
        std::cout.rdbuf(rdbuf);
        out.close();
        int wstatus;
        waitpid(pid, &wstatus, 0);
    }

private:
    stream_buffer<file_descriptor_sink> out;
    std::streambuf *rdbuf;
    pid_t pid;
};

/**
 * @brief Retrieves terminal width.
 *
 * @returns Actual terminal width, or maximum possible value for the type.
 */
static unsigned int
getTerminalWidth()
{
    winsize ws;
    if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != 0) {
        return std::numeric_limits<unsigned int>::max();
    }

    return ws.ws_col;
}

class BuildsCmd : public AutoSubCommand<BuildsCmd>
{
public:
    BuildsCmd() : parent("builds")
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &/*args*/) override
    {
        // TODO: calculate and display change of coverage (both in percents and
        //       in covered/relevant lines).
        // TODO: by default limit number of builds to display to N (e.g., 10).

        // TODO: colorize percents?
        TablePrinter tablePrinter {
            { "Build", "Coverage", "Lines", "Branch", "Commit" },
            getTerminalWidth()
        };

        std::string sharp("#"), percent(" %"), sep(" / ");
        for (const Build &build : bh->getBuilds()) {
            CovInfo covInfo(build);

            tablePrinter.append({
                sharp + std::to_string(build.getId()),
                covInfo.formatCoverageRate() + percent,
                covInfo.formatLines(sep),
                build.getRefName(),
                build.getRef()
            });
        }

        tablePrinter.print(std::cout);
    }
};

class DiffCmd : public AutoSubCommand<DiffCmd>
{
public:
    DiffCmd() : parent("diff", 3U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        // TODO: allow diffing whole builds.

        const int oldBuildId = std::stoi(args[0]);
        const int newBuildId = std::stoi(args[1]);

        boost::optional<Build> oldBuild = bh->getBuild(oldBuildId);
        boost::optional<Build> newBuild = bh->getBuild(newBuildId);
        if (!oldBuild) {
            std::cerr << "Can't find build #" << oldBuildId << '\n';
            error();
        }
        if (!newBuild) {
            std::cerr << "Can't find build #" << newBuildId << '\n';
            error();
        }
        if (isFailed()) {
            return;
        }

        boost::optional<File &> oldFile = oldBuild->getFile(args[2]);
        boost::optional<File &> newFile = newBuild->getFile(args[2]);
        if (!oldFile) {
            std::cerr << "Can't find file " << args[2] << " in " << args[0]
                      << '\n';
            error();
        }
        if (!newFile) {
            std::cerr << "Can't find file " << args[2] << " in " << args[1]
                      << '\n';
            error();
        }
        if (isFailed()) {
            return;
        }

        Text oldVersion = repo->readFile(oldBuild->getRef(),
                                         oldFile->getPath());
        Text newVersion = repo->readFile(newBuild->getRef(),
                                         newFile->getPath());
        const std::vector<int> &oldCov = oldFile->getCoverage();
        const std::vector<int> &newCov = newFile->getCoverage();

        if (oldVersion.size() != oldCov.size() ||
            newVersion.size() != newCov.size()) {
            std::cerr << "Coverage information is not accurate\n";
            return error();
        }

        RedirectToPager redirectToPager;

        printLineSeparator();
        printBuildHeader(*oldBuild);
        printFileHeader(*oldFile);
        printLineSeparator();
        printBuildHeader(*newBuild);
        printFileHeader(*newFile);
        printLineSeparator();

        FilePrinter filePrinter;
        filePrinter.printDiff(args[2], oldVersion, oldCov, newVersion, newCov);

        // TODO: print some totals/stats here.
    }
};

class DirsCmd : public AutoSubCommand<DirsCmd>
{
public:
    DirsCmd() : parent("dirs", 1U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        namespace fs = boost::filesystem;

        const int buildId = std::stoi(args[0]);
        if (boost::optional<Build> build = bh->getBuild(buildId)) {
            std::map<std::string, CovInfo> dirs;
            for (const std::string &filePath : build->getPaths()) {
                fs::path dirPath = filePath;
                dirPath.remove_filename();

                File &file = *build->getFile(filePath);
                CovInfo &info = dirs[dirPath.string()];

                info.addCovered(file.getCoveredCount());
                info.addUncovered(file.getUncoveredCount());
            }

            // TODO: colorize percents?
            TablePrinter tablePrinter({ "-Directory", "Coverage", "#" },
                                      getTerminalWidth());

            std::string slash("/"), percent(" %"), sep(" / ");
            for (const auto &entry : dirs) {
                const CovInfo &covInfo = entry.second;
                tablePrinter.append({
                    entry.first + slash,
                    covInfo.formatCoverageRate() + percent,
                    covInfo.formatLines(sep)
                });
            }

            tablePrinter.print(std::cout);
        } else {
            std::cerr << "Can't find build #" << buildId << '\n';
            error();
        }
    }
};

class FilesCmd : public AutoSubCommand<FilesCmd>
{
public:
    FilesCmd() : parent("files", 1U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        const int buildId = std::stoi(args[0]);
        boost::optional<Build> build = bh->getBuild(buildId);
        if (!build) {
            std::cerr << "Can't find build #" << buildId << '\n';
            return error();
        }

        // TODO: colorize percents?
        TablePrinter tablePrinter({ "-File", "Coverage", "#" },
                                  getTerminalWidth());

        std::string percent(" %"), sep(" / ");
        for (const std::string &filePath : build->getPaths()) {
            CovInfo covInfo(*build->getFile(filePath));
            tablePrinter.append({
                filePath,
                covInfo.formatCoverageRate() + percent,
                covInfo.formatLines(sep)
            });
        }

        tablePrinter.print(std::cout);
    }
};

class GetCmd : public AutoSubCommand<GetCmd>
{
public:
    GetCmd() : parent("get", 2U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        const int buildId = std::stoi(args[0]);
        boost::optional<Build> build = bh->getBuild(buildId);
        if (!build) {
            std::cerr << "Can't find build #" << buildId << '\n';
            return error();
        }

        boost::optional<File &> file = build->getFile(args[1]);
        if (!file) {
            std::cerr << "Can't find file: " << args[1] << '\n';
            return error();
        }

        std::cout << build->getRef() << '\n';
        for (int hits : file->getCoverage()) {
            std::cout << hits << '\n';
        }
    }
};

class NewCmd : public AutoSubCommand<NewCmd>
{
public:
    NewCmd() : parent("new")
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &/*args*/) override
    {
        std::string ref, refName;
        std::cin >> ref >> refName;

        const std::unordered_map<std::string, std::string> files =
            repo->listFiles(ref);

        BuildData bd(std::move(ref), refName);

        for (std::string path, sha1Hash; std::cin >> path >> sha1Hash; ) {
            int nLines;
            std::cin >> nLines;

            std::vector<int> coverage;
            coverage.reserve(nLines);

            while (nLines-- > 0) {
                int i;
                std::cin >> i;
                coverage.push_back(i);
            }

            const auto file = files.find(path);
            if (file == files.cend()) {
                std::cerr << "Skipping file missing in " << refName << ": "
                          << path << '\n';
            } else if (!boost::iequals(file->second, sha1Hash)) {
                std::cerr << path << " file at " << refName
                          << " doesn't match reported SHA-1\n";
                error();
            } else {
                bd.addFile(File(std::move(path), std::move(coverage)));
            }
        }

        if (!isFailed()) {
            Build build = bh->addBuild(bd);
            printBuildHeader(build);
            // TODO: display change of coverage since previous build.
        }
    }
};

class ShowCmd : public AutoSubCommand<ShowCmd>
{
public:
    ShowCmd() : parent("show", 1U, 2U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        // TODO: maybe allow passing in path to directory, which would cause
        //       printing all files in that sub-tree (or only directly in it?).

        const int buildId = std::stoi(args[0]);
        if (boost::optional<Build> build = bh->getBuild(buildId)) {
            FilePrinter printer;

            if (args.size() == 1U) {
                RedirectToPager redirectToPager;
                printBuildHeader(*build);
                for (const std::string &path : build->getPaths()) {
                    printFile(repo, *build, *build->getFile(path), printer);
                }
            } else if (boost::optional<File &> file = build->getFile(args[1])) {
                RedirectToPager redirectToPager;
                printBuildHeader(*build);
                printFile(repo, *build, *file, printer);
            } else {
                std::cerr << "Can't find file: " << args[1] << '\n';
                error();
            }
        } else {
            std::cerr << "Can't find build #" << buildId << '\n';
            error();
        }
    }
};

static void
printBuildHeader(const Build &build)
{
    CovInfo covInfo(build);
    // TODO: colorize percents?
    std::cout << (decor::bold << "Build:") << " #" << build.getId() << ", "
              << covInfo.formatCoverageRate() << "% "
              << '(' << covInfo.formatLines("/") << "), "
              << build.getRefName() << " (" << build.getRef() << ")\n";
}

static void
printFile(const Repository *repo, const Build &build, const File &file,
          FilePrinter &printer)
{
    printLineSeparator();
    printFileHeader(file);
    printLineSeparator();

    const std::string &path = file.getPath();
    const std::string &ref = build.getRef();
    printer.print(path, repo->readFile(ref, path), file.getCoverage());
}

static void
printFileHeader(const File &file)
{
    CovInfo covInfo(file);
    // TODO: colorize percents?
    std::cout << (decor::bold << "File: ") << file.getPath() << ", "
              << covInfo.formatCoverageRate() << "% "
              << '(' << covInfo.formatLines("/") << ")\n";
}

static void
printLineSeparator()
{
    std::cout << std::setfill('-') << std::setw(80) << '\n'
              << std::setfill(' ');
}
<commit_msg>Flatten some if-else statements that use optional<commit_after>// Copyright (C) 2016 xaizek <xaizek@openmailbox.org>
//
// This file is part of uncov.
//
// uncov is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// uncov 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with uncov.  If not, see <http://www.gnu.org/licenses/>.

#include <sys/ioctl.h>
#include <sys/wait.h>
#include <termios.h>

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/optional.hpp>
#include <boost/scope_exit.hpp>

#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <vector>

#include "BuildHistory.hpp"
#include "FilePrinter.hpp"
#include "Repository.hpp"
#include "SubCommand.hpp"
#include "TablePrinter.hpp"
#include "decoration.hpp"

static void printBuildHeader(const Build &build);
static void printFile(const Repository *repo, const Build &build,
                      const File &file, FilePrinter &printer);
static void printFileHeader(const File &file);
static void printLineSeparator();

class CovInfo
{
public:
    CovInfo() = default;
    template <typename T>
    explicit CovInfo(const T &coverable)
        : coveredCount(coverable.getCoveredCount()),
          uncoveredCount(coverable.getUncoveredCount())
    {
    }

public:
    void addCovered(int num)
    {
        coveredCount += num;
    }

    void addUncovered(int num)
    {
        uncoveredCount += num;
    }

    int getCoveredCount() const
    {
        return coveredCount;
    }

    int getUncoveredCount() const
    {
        return uncoveredCount;
    }

    std::string formatCoverageRate() const
    {
        if (getRelevantLines() == 0) {
            return "100";
        }

        auto rate = 100*coveredCount/static_cast<float>(getRelevantLines());

        std::ostringstream oss;
        oss << std::fixed << std::right
            << std::setprecision(2) << rate;
        return oss.str();
    }

    std::string formatLines(const std::string &separator) const
    {
        return std::to_string(coveredCount) + separator
             + std::to_string(getRelevantLines());
    }

private:
    int getRelevantLines() const
    {
        return coveredCount + uncoveredCount;
    }

private:
    int coveredCount = 0;
    int uncoveredCount = 0;
};

class RedirectToPager
{
    template <typename T>
    using stream_buffer = boost::iostreams::stream_buffer<T>;
    using file_descriptor_sink = boost::iostreams::file_descriptor_sink;

public:
    RedirectToPager()
    {
        int pipePair[2];
        if (pipe(pipePair) != 0) {
            throw std::runtime_error("Failed to create a pipe");
        }
        BOOST_SCOPE_EXIT_ALL(pipePair) { close(pipePair[0]); };

        pid = fork();
        if (pid == -1) {
            close(pipePair[1]);
            throw std::runtime_error("Fork has failed");
        }
        if (pid == 0) {
            close(pipePair[1]);
            if (dup2(pipePair[0], STDIN_FILENO) == -1) {
                _Exit(EXIT_FAILURE);
            }
            close(pipePair[0]);
            // XXX: hard-coded invocation of less.
            execlp("less", "less", "-R", static_cast<char *>(nullptr));
            _Exit(127);
        }

        out.open(file_descriptor_sink(pipePair[1],
                                      boost::iostreams::close_handle));
        rdbuf = std::cout.rdbuf(&out);
    }

    ~RedirectToPager()
    {
        std::cout.rdbuf(rdbuf);
        out.close();
        int wstatus;
        waitpid(pid, &wstatus, 0);
    }

private:
    stream_buffer<file_descriptor_sink> out;
    std::streambuf *rdbuf;
    pid_t pid;
};

/**
 * @brief Retrieves terminal width.
 *
 * @returns Actual terminal width, or maximum possible value for the type.
 */
static unsigned int
getTerminalWidth()
{
    winsize ws;
    if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != 0) {
        return std::numeric_limits<unsigned int>::max();
    }

    return ws.ws_col;
}

class BuildsCmd : public AutoSubCommand<BuildsCmd>
{
public:
    BuildsCmd() : parent("builds")
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &/*args*/) override
    {
        // TODO: calculate and display change of coverage (both in percents and
        //       in covered/relevant lines).
        // TODO: by default limit number of builds to display to N (e.g., 10).

        // TODO: colorize percents?
        TablePrinter tablePrinter {
            { "Build", "Coverage", "Lines", "Branch", "Commit" },
            getTerminalWidth()
        };

        std::string sharp("#"), percent(" %"), sep(" / ");
        for (const Build &build : bh->getBuilds()) {
            CovInfo covInfo(build);

            tablePrinter.append({
                sharp + std::to_string(build.getId()),
                covInfo.formatCoverageRate() + percent,
                covInfo.formatLines(sep),
                build.getRefName(),
                build.getRef()
            });
        }

        tablePrinter.print(std::cout);
    }
};

class DiffCmd : public AutoSubCommand<DiffCmd>
{
public:
    DiffCmd() : parent("diff", 3U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        // TODO: allow diffing whole builds.

        const int oldBuildId = std::stoi(args[0]);
        const int newBuildId = std::stoi(args[1]);

        boost::optional<Build> oldBuild = bh->getBuild(oldBuildId);
        boost::optional<Build> newBuild = bh->getBuild(newBuildId);
        if (!oldBuild) {
            std::cerr << "Can't find build #" << oldBuildId << '\n';
            error();
        }
        if (!newBuild) {
            std::cerr << "Can't find build #" << newBuildId << '\n';
            error();
        }
        if (isFailed()) {
            return;
        }

        boost::optional<File &> oldFile = oldBuild->getFile(args[2]);
        boost::optional<File &> newFile = newBuild->getFile(args[2]);
        if (!oldFile) {
            std::cerr << "Can't find file " << args[2] << " in " << args[0]
                      << '\n';
            error();
        }
        if (!newFile) {
            std::cerr << "Can't find file " << args[2] << " in " << args[1]
                      << '\n';
            error();
        }
        if (isFailed()) {
            return;
        }

        Text oldVersion = repo->readFile(oldBuild->getRef(),
                                         oldFile->getPath());
        Text newVersion = repo->readFile(newBuild->getRef(),
                                         newFile->getPath());
        const std::vector<int> &oldCov = oldFile->getCoverage();
        const std::vector<int> &newCov = newFile->getCoverage();

        if (oldVersion.size() != oldCov.size() ||
            newVersion.size() != newCov.size()) {
            std::cerr << "Coverage information is not accurate\n";
            return error();
        }

        RedirectToPager redirectToPager;

        printLineSeparator();
        printBuildHeader(*oldBuild);
        printFileHeader(*oldFile);
        printLineSeparator();
        printBuildHeader(*newBuild);
        printFileHeader(*newFile);
        printLineSeparator();

        FilePrinter filePrinter;
        filePrinter.printDiff(args[2], oldVersion, oldCov, newVersion, newCov);

        // TODO: print some totals/stats here.
    }
};

class DirsCmd : public AutoSubCommand<DirsCmd>
{
public:
    DirsCmd() : parent("dirs", 1U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        namespace fs = boost::filesystem;

        const int buildId = std::stoi(args[0]);
        boost::optional<Build> build = bh->getBuild(buildId);
        if (!build) {
            std::cerr << "Can't find build #" << buildId << '\n';
            return error();
        }

        std::map<std::string, CovInfo> dirs;
        for (const std::string &filePath : build->getPaths()) {
            fs::path dirPath = filePath;
            dirPath.remove_filename();

            File &file = *build->getFile(filePath);
            CovInfo &info = dirs[dirPath.string()];

            info.addCovered(file.getCoveredCount());
            info.addUncovered(file.getUncoveredCount());
        }

        // TODO: colorize percents?
        TablePrinter tablePrinter({ "-Directory", "Coverage", "#" },
                                  getTerminalWidth());

        std::string slash("/"), percent(" %"), sep(" / ");
        for (const auto &entry : dirs) {
            const CovInfo &covInfo = entry.second;
            tablePrinter.append({
                entry.first + slash,
                covInfo.formatCoverageRate() + percent,
                covInfo.formatLines(sep)
            });
        }

        tablePrinter.print(std::cout);
    }
};

class FilesCmd : public AutoSubCommand<FilesCmd>
{
public:
    FilesCmd() : parent("files", 1U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        const int buildId = std::stoi(args[0]);
        boost::optional<Build> build = bh->getBuild(buildId);
        if (!build) {
            std::cerr << "Can't find build #" << buildId << '\n';
            return error();
        }

        // TODO: colorize percents?
        TablePrinter tablePrinter({ "-File", "Coverage", "#" },
                                  getTerminalWidth());

        std::string percent(" %"), sep(" / ");
        for (const std::string &filePath : build->getPaths()) {
            CovInfo covInfo(*build->getFile(filePath));
            tablePrinter.append({
                filePath,
                covInfo.formatCoverageRate() + percent,
                covInfo.formatLines(sep)
            });
        }

        tablePrinter.print(std::cout);
    }
};

class GetCmd : public AutoSubCommand<GetCmd>
{
public:
    GetCmd() : parent("get", 2U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        const int buildId = std::stoi(args[0]);
        boost::optional<Build> build = bh->getBuild(buildId);
        if (!build) {
            std::cerr << "Can't find build #" << buildId << '\n';
            return error();
        }

        boost::optional<File &> file = build->getFile(args[1]);
        if (!file) {
            std::cerr << "Can't find file: " << args[1] << '\n';
            return error();
        }

        std::cout << build->getRef() << '\n';
        for (int hits : file->getCoverage()) {
            std::cout << hits << '\n';
        }
    }
};

class NewCmd : public AutoSubCommand<NewCmd>
{
public:
    NewCmd() : parent("new")
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &/*args*/) override
    {
        std::string ref, refName;
        std::cin >> ref >> refName;

        const std::unordered_map<std::string, std::string> files =
            repo->listFiles(ref);

        BuildData bd(std::move(ref), refName);

        for (std::string path, sha1Hash; std::cin >> path >> sha1Hash; ) {
            int nLines;
            std::cin >> nLines;

            std::vector<int> coverage;
            coverage.reserve(nLines);

            while (nLines-- > 0) {
                int i;
                std::cin >> i;
                coverage.push_back(i);
            }

            const auto file = files.find(path);
            if (file == files.cend()) {
                std::cerr << "Skipping file missing in " << refName << ": "
                          << path << '\n';
            } else if (!boost::iequals(file->second, sha1Hash)) {
                std::cerr << path << " file at " << refName
                          << " doesn't match reported SHA-1\n";
                error();
            } else {
                bd.addFile(File(std::move(path), std::move(coverage)));
            }
        }

        if (!isFailed()) {
            Build build = bh->addBuild(bd);
            printBuildHeader(build);
            // TODO: display change of coverage since previous build.
        }
    }
};

class ShowCmd : public AutoSubCommand<ShowCmd>
{
public:
    ShowCmd() : parent("show", 1U, 2U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        // TODO: maybe allow passing in path to directory, which would cause
        //       printing all files in that sub-tree (or only directly in it?).

        const int buildId = std::stoi(args[0]);
        boost::optional<Build> build = bh->getBuild(buildId);
        if (!build) {
            std::cerr << "Can't find build #" << buildId << '\n';
            return error();
        }

        FilePrinter printer;

        if (args.size() == 1U) {
            RedirectToPager redirectToPager;
            printBuildHeader(*build);
            for (const std::string &path : build->getPaths()) {
                printFile(repo, *build, *build->getFile(path), printer);
            }
        } else if (boost::optional<File &> file = build->getFile(args[1])) {
            RedirectToPager redirectToPager;
            printBuildHeader(*build);
            printFile(repo, *build, *file, printer);
        } else {
            std::cerr << "Can't find file: " << args[1] << '\n';
            error();
        }
    }
};

static void
printBuildHeader(const Build &build)
{
    CovInfo covInfo(build);
    // TODO: colorize percents?
    std::cout << (decor::bold << "Build:") << " #" << build.getId() << ", "
              << covInfo.formatCoverageRate() << "% "
              << '(' << covInfo.formatLines("/") << "), "
              << build.getRefName() << " (" << build.getRef() << ")\n";
}

static void
printFile(const Repository *repo, const Build &build, const File &file,
          FilePrinter &printer)
{
    printLineSeparator();
    printFileHeader(file);
    printLineSeparator();

    const std::string &path = file.getPath();
    const std::string &ref = build.getRef();
    printer.print(path, repo->readFile(ref, path), file.getCoverage());
}

static void
printFileHeader(const File &file)
{
    CovInfo covInfo(file);
    // TODO: colorize percents?
    std::cout << (decor::bold << "File: ") << file.getPath() << ", "
              << covInfo.formatCoverageRate() << "% "
              << '(' << covInfo.formatLines("/") << ")\n";
}

static void
printLineSeparator()
{
    std::cout << std::setfill('-') << std::setw(80) << '\n'
              << std::setfill(' ');
}
<|endoftext|>


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

#include "TableMatrix.h"

namespace rty
{
	TableMatrix::TableMatrix(int l, int c)
		: rows(l), cols(c)
	{
		mat = new Table*[l];
		for(int i = 0; i < l; i++)
			mat[i] = new Table[c];
		ngrupos = 0;
		int table_num = 0;
		for(int i = 0; i < l; i++)
		{
			for(int j = 0; j < c; j++)
				mat[i][j].num = table_num++;
		}
	}

	htl::vector<Table*> TableMatrix::getTableGroup(unsigned int s)
	{
		htl::vector<Table*> vec;
		vec.reserve(s + s%Table::MAX_OCCUPANTS / Table::MAX_OCCUPANTS);

		if(s == 0)
			return vec;

		if(s <= 2)
		{
			for(int i = 0; i < rows; i++)
			{
				for(int j = 0; j < cols; j++)
				{
					if(mat[i][j].free == mat[i][j].MAX_OCCUPANTS)
					{
						vec.push_back(&mat[i][j]);
						break;
					}
				}
				if(!vec.empty())
					break;
			}
		}

		if(s > 2)
		{
			for(int i = 0; i < rows; i++)
			{
				for(int j = 0; j < cols; j++)
				{
					vec = findAround(i, j, s);
					if(!vec.empty())
						break;
				}
				if(!vec.empty())
					break;
			}
		}

		for(htl::vector<Table*>::iterator it = vec.begin(); it != vec.end(); it++)
		{
			(*it)->free -= (*it)->MAX_OCCUPANTS - s%2;
			s -= (*it)->MAX_OCCUPANTS - s%2;
		}

		return vec;
	}

	htl::vector<Table*>	TableMatrix::findAround(int row, int column, int n)
	{
		htl::vector<Table*> tab;
		for (int i = 0; i + row < rows; ++i)
		{
			if(mat[i + row][column].free == Table::MAX_OCCUPANTS)
			{
				tab.push_back(&mat[i + row][column]);
				if(int(tab.size()) >= n/Table::MAX_OCCUPANTS)
				{
					return tab;
				}
			}
		}

		for (int i = -1; i + row > 0; --i)
		{
			if(mat[i + row][column].free == Table::MAX_OCCUPANTS)
			{
				tab.push_back(&mat[i + row][column]);
				if(int(tab.size()) >= n/Table::MAX_OCCUPANTS)
					return tab;
			}
			else
				break;
		}

		for (int i = 0; i + column < column; ++i)
		{
			if(mat[row][column + i].free == Table::MAX_OCCUPANTS)
			{
				tab.push_back(&mat[i + row][column]);
				if(int(tab.size()) >= n/Table::MAX_OCCUPANTS)
					return tab;

			}
			else
				break;
		}

		for (int i = -1; i + column > 0; i--)
		{
			if(mat[row][column + i].free == Table::MAX_OCCUPANTS)
			{
				tab.push_back(&mat[i + row][column]);
				if(int(tab.size()) >= n/Table::MAX_OCCUPANTS)
					return tab;
			}
			else
				break;
		}

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

#include "TableMatrix.h"

namespace rty
{
	TableMatrix::TableMatrix(int l, int c)
		: rows(l), cols(c)
	{
		mat = new Table*[l];
		for(int i = 0; i < l; i++)
			mat[i] = new Table[c];
		ngrupos = 0;
		int table_num = 0;
		for(int i = 0; i < l; i++)
		{
			for(int j = 0; j < c; j++)
				mat[i][j].num = table_num++;
		}
	}

	htl::vector<Table*> TableMatrix::getTableGroup(unsigned int s)
	{
		htl::vector<Table*> vec;
		vec.reserve(s + s%Table::MAX_OCCUPANTS / Table::MAX_OCCUPANTS);

		if(s == 0)
			return vec;

		if(s <= 2)
		{
			for(int i = 0; i < rows; i++)
			{
				for(int j = 0; j < cols; j++)
				{
					if(mat[i][j].free == mat[i][j].MAX_OCCUPANTS)
					{
						vec.push_back(&mat[i][j]);
						break;
					}
				}
				if(!vec.empty())
					break;
			}
		}

		if(s > 2)
		{
			for(int i = 0; i < rows; i++)
			{
				for(int j = 0; j < cols; j++)
				{
					vec = findAround(i, j, s);
					if(!vec.empty())
						break;
				}
				if(!vec.empty())
					break;
			}
		}

		for(htl::vector<Table*>::iterator it = vec.begin(); it != vec.end(); it++)
		{
			(*it)->free -= (*it)->MAX_OCCUPANTS - s%2;
			s -= (*it)->MAX_OCCUPANTS - s%2;
		}

		return vec;
	}

	htl::vector<Table*>	TableMatrix::findAround(int row, int column, int n)
	{
		htl::vector<Table*> tab;
		for (int i = 0; i + row < rows; ++i)
		{
			if(mat[i + row][column].free == Table::MAX_OCCUPANTS)
			{
				tab.push_back(&mat[i + row][column]);
				if(int(tab.size()) >= n/Table::MAX_OCCUPANTS)
				{
					return tab;
				}
			}
		}

		for (int i = -1; i + row > 0; --i)
		{
			if(mat[i + row][column].free == Table::MAX_OCCUPANTS)
			{
				tab.push_back(&mat[i + row][column]);
				if(int(tab.size()) >= n/Table::MAX_OCCUPANTS)
					return tab;
			}
			else
				break;
		}

		for (int i = 0; i + column < cols; ++i)
		{
			if(mat[row][column + i].free == Table::MAX_OCCUPANTS)
			{
				tab.push_back(&mat[i + row][column]);
				if(int(tab.size()) >= n/Table::MAX_OCCUPANTS)
					return tab;

			}
			else
				break;
		}

		for (int i = -1; i + column > 0; i--)
		{
			if(mat[row][column + i].free == Table::MAX_OCCUPANTS)
			{
				tab.push_back(&mat[i + row][column]);
				if(int(tab.size()) >= n/Table::MAX_OCCUPANTS)
					return tab;
			}
			else
				break;
		}

		tab.clear();
		return tab;
	}
}<|endoftext|>


<commit_before>#ifndef ALARM_HPP_INCLUDED
#define ALARM_HPP_INCLUDED

#include "Singleton.hpp"
#include "Graphic.hpp"

class Alarm: public Graphic, public Singleton<Alarm>
{
    struct schedule
    {
        float time;
        Poco::AbstractDelegate<float> * delegate;
    };
    struct CompareSchedule
    {
        bool operator()(const schedule & s1, const schedule & s2)
        {
            return s1.time < s2.time;
        }
    };
    std::set<schedule,CompareSchedule> schedules;
    public:
    void update()
    {
        std::set<schedule,CompareSchedule>::iterator lastit;
        bool will_erase = false;
        float now = ofGetElapsedTimef();
        for(std::set<schedule,CompareSchedule>::iterator it(schedules.begin()); it != schedules.end(); ++it)
        {
            if( (*it).time < now  )
            {
                (*it).delegate->notify(NULL,now);
                lastit = it;
                will_erase = true;
            }
            else
                break;
        }
        if(will_erase)
        {
            schedules.erase(schedules.begin(),++lastit);
        }

    }
    template<class ListenerClass>
    void Setup(float time, ListenerClass * target, void (ListenerClass::*listenerMethod)(float&) )
    {
        schedule s;
        s.time = time;
        s.delegate = new Poco::Delegate<ListenerClass,float,false>(target,listenerMethod);
        schedules.insert(s);
    }
};

#endif // ALARM_HPP_INCLUDED
<commit_msg>bugfix: couldn't make several alarm setups for the same time<commit_after>#ifndef ALARM_HPP_INCLUDED
#define ALARM_HPP_INCLUDED

#include "Singleton.hpp"
#include "Graphic.hpp"

class Alarm: public Graphic, public Singleton<Alarm>
{
    struct schedule
    {
        float time;
        Poco::AbstractDelegate<float> * delegate;
    };
    struct CompareSchedule
    {
        bool operator()(const schedule & s1, const schedule & s2)
        {
            if(s1.time == s2.time)
                return &s1 < &s2;
            return s1.time < s2.time;
        }
    };
    std::set<schedule,CompareSchedule> schedules;
    public:
    void update()
    {
        std::set<schedule,CompareSchedule>::iterator lastit;
        bool will_erase = false;
        float now = ofGetElapsedTimef();
        for(std::set<schedule,CompareSchedule>::iterator it(schedules.begin()); it != schedules.end(); ++it)
        {
            if( (*it).time < now  )
            {
                (*it).delegate->notify(NULL,now);
                lastit = it;
                will_erase = true;
            }
            else
                break;
        }
        if(will_erase)
        {
            schedules.erase(schedules.begin(),++lastit);
        }

    }
    template<class ListenerClass>
    void Setup(float time, ListenerClass * target, void (ListenerClass::*listenerMethod)(float&) )
    {
        schedule s;
        s.time = time;
        s.delegate = new Poco::Delegate<ListenerClass,float,false>(target,listenerMethod);
        schedules.insert(s);
    }
};

#endif // ALARM_HPP_INCLUDED
<|endoftext|>


<commit_before>// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <openssl/ecdsa.h>
#include <openssl/rand.h>
#include <openssl/obj_mac.h>
#include "Crypto.h" // i2pd
#include "Gost.h" // i2pd

#include "key.h"

// anonymous namespace with local implementation code (OpenSSL interaction)
namespace {

// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
    int ok = 0;
    BN_CTX *ctx = NULL;
    EC_POINT *pub_key = NULL;

    if (!eckey) return 0;

    const EC_GROUP *group = EC_KEY_get0_group(eckey);

    if ((ctx = BN_CTX_new()) == NULL)
        goto err;

    pub_key = EC_POINT_new(group);

    if (pub_key == NULL)
        goto err;

    if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
        goto err;

    EC_KEY_set_private_key(eckey,priv_key);
    EC_KEY_set_public_key(eckey,pub_key);

    ok = 1;

err:

    if (pub_key)
        EC_POINT_free(pub_key);
    if (ctx != NULL)
        BN_CTX_free(ctx);

    return(ok);
}

// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
// recid selects which key is recovered
// if check is non-zero, additional checks are performed
static int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
{
    if (!eckey) return 0;
	BIGNUM * d = BN_bin2bn (msg, msglen, nullptr);
	const auto& curve = i2p::crypto::GetGOSTR3410Curve (i2p::crypto::eGOSTR3410CryptoProA);
	EC_POINT * pub = curve->RecoverPublicKey (d, ecsig->r, ecsig->s, recid % 2);
	BN_free (d);
	if (!pub) return 0;
	EC_KEY_set_public_key(eckey, pub);
	EC_POINT_free (pub);
	return 1;
}

// RAII Wrapper around OpenSSL's EC_KEY
class CECKey {
private:
    EC_KEY *pkey;

public:
    CECKey()
	{
		pkey = EC_KEY_new ();
		// GOST 34.10-2012
		auto ret = EC_KEY_set_group(pkey, i2p::crypto::GetGOSTR3410Curve (i2p::crypto::eGOSTR3410CryptoProA)->GetGroup ());
		assert (ret == 1);
    }

    ~CECKey() {
        EC_KEY_free(pkey);
    }

    void GetSecretBytes(unsigned char vch[32]) const {
        const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
        assert(bn);
        int nBytes = BN_num_bytes(bn);
        int n=BN_bn2bin(bn,&vch[32 - nBytes]);
        assert(n == nBytes);
        memset(vch, 0, 32 - nBytes);
    }

    void SetSecretBytes(const unsigned char vch[32]) {
        BIGNUM bn;
        BN_init(&bn);
        assert(BN_bin2bn(vch, 32, &bn));
        assert(EC_KEY_regenerate_key(pkey, &bn));
        BN_clear_free(&bn);
    }

    void GetPrivKey(CPrivKey &privkey, bool fCompressed) {
        EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
        int nSize = i2d_ECPrivateKey(pkey, NULL);
        assert(nSize);
        privkey.resize(nSize);
        unsigned char* pbegin = &privkey[0];
        int nSize2 = i2d_ECPrivateKey(pkey, &pbegin);
        assert(nSize == nSize2);
    }

    bool SetPrivKey(const CPrivKey &privkey) {
        const unsigned char* pbegin = &privkey[0];
        if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) {
            // d2i_ECPrivateKey returns true if parsing succeeds.
            // This doesn't necessarily mean the key is valid.
            if (EC_KEY_check_key(pkey))
                return true;
        }
        return false;
    }

    void GetPubKey(CPubKey &pubkey, bool fCompressed) {
        EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
        int nSize = i2o_ECPublicKey(pkey, NULL);
        assert(nSize);
        assert(nSize <= 65);
        unsigned char c[65];
        unsigned char *pbegin = c;
        int nSize2 = i2o_ECPublicKey(pkey, &pbegin);
        assert(nSize == nSize2);
        pubkey.Set(&c[0], &c[nSize]);
    }

    bool SetPubKey(const CPubKey &pubkey) {
        const unsigned char* pbegin = pubkey.begin();
        return o2i_ECPublicKey(&pkey, &pbegin, pubkey.size());
    }

    bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig)
	{
		const BIGNUM * priv = EC_KEY_get0_private_key(pkey);
		BIGNUM * d = BN_bin2bn (hash.begin (), 32, nullptr);
		ECDSA_SIG *sig = ECDSA_SIG_new ();
		i2p::crypto::GetGOSTR3410Curve (i2p::crypto::eGOSTR3410CryptoProA)->Sign (priv, d, sig->r, sig->s);
		// encode signature is in DER format
		auto nSize = ECDSA_size (pkey); // max size
		vchSig.resize(nSize);
		auto p = &vchSig[0];
		nSize = i2d_ECDSA_SIG (sig, &p);
		vchSig.resize(nSize); // acutal size
		BN_free (d);
		ECDSA_SIG_free(sig);
        return true;
    }

    bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig)
	{
		const EC_POINT * pub = EC_KEY_get0_public_key(pkey);
		BIGNUM * d = BN_bin2bn (hash.begin (), 32, nullptr);
		BIGNUM * r = BN_bin2bn (&vchSig[0], 32, NULL);
		BIGNUM * s = BN_bin2bn (&vchSig[32], 32, NULL);
		bool ret = i2p::crypto::GetGOSTR3410Curve (i2p::crypto::eGOSTR3410CryptoProA)->Verify (pub, d, r, s);
		BN_free (d); BN_free (r); BN_free (s);
		return ret;
    }

    bool SignCompact(const uint256 &hash, unsigned char *p64, int &rec)
	{
        bool fOk = false;
        ECDSA_SIG *sig = ECDSA_SIG_new ();
		const BIGNUM * priv = EC_KEY_get0_private_key(pkey);
		BIGNUM * d = BN_bin2bn (hash.begin (), 32, nullptr);
		i2p::crypto::GetGOSTR3410Curve (i2p::crypto::eGOSTR3410CryptoProA)->Sign (priv, d, sig->r, sig->s);
		BN_free (d);
        if (sig==NULL)
            return false;
        memset(p64, 0, 64);
        int nBitsR = BN_num_bits(sig->r);
        int nBitsS = BN_num_bits(sig->s);
        if (nBitsR <= 256 && nBitsS <= 256) {
            CPubKey pubkey;
            GetPubKey(pubkey, true);
            for (int i=0; i<2; i++) {
                CECKey keyRec;
                if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) {
                    CPubKey pubkeyRec;
                    keyRec.GetPubKey(pubkeyRec, true);
                    if (pubkeyRec == pubkey) {
                        rec = i;
                        fOk = true;
                        break;
                    }
                }
            }
            assert(fOk);
            BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]);
            BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]);
        }
        ECDSA_SIG_free(sig);
        return fOk;
    }

    // reconstruct public key from a compact signature
    // This is only slightly more CPU intensive than just verifying it.
    // If this function succeeds, the recovered public key is guaranteed to be valid
    // (the signature is a valid signature of the given data for that key)
    bool Recover(const uint256 &hash, const unsigned char *p64, int rec)
    {
        if (rec<0 || rec>=3)
            return false;
        ECDSA_SIG *sig = ECDSA_SIG_new();
        BN_bin2bn(&p64[0],  32, sig->r);
        BN_bin2bn(&p64[32], 32, sig->s);
        bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
        ECDSA_SIG_free(sig);
        return ret;
    }
};

}; // end of anonymous namespace

bool CKey::Check(const unsigned char *vch) {
    // Do not convert to OpenSSL's data structures for range-checking keys,
    // it's easy enough to do directly.
    static const unsigned char vchMax[32] = {
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
        0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
        0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
    };
    bool fIsZero = true;
    for (int i=0; i<32 && fIsZero; i++)
        if (vch[i] != 0)
            fIsZero = false;
    if (fIsZero)
        return false;
    for (int i=0; i<32; i++) {
        if (vch[i] < vchMax[i])
            return true;
        if (vch[i] > vchMax[i])
            return false;
    }
    return true;
}

void CKey::MakeNewKey(bool fCompressedIn) {
    do {
        RAND_bytes(vch, sizeof(vch));
    } while (!Check(vch));
    fValid = true;
    fCompressed = fCompressedIn;
}

bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
    CECKey key;
    if (!key.SetPrivKey(privkey))
        return false;
    key.GetSecretBytes(vch);
    fCompressed = fCompressedIn;
    fValid = true;
    return true;
}

CPrivKey CKey::GetPrivKey() const {
    assert(fValid);
    CECKey key;
    key.SetSecretBytes(vch);
    CPrivKey privkey;
    key.GetPrivKey(privkey, fCompressed);
    return privkey;
}

CPubKey CKey::GetPubKey() const {
    assert(fValid);
    CECKey key;
    key.SetSecretBytes(vch);
    CPubKey pubkey;
    key.GetPubKey(pubkey, fCompressed);
    return pubkey;
}

bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
    if (!fValid)
        return false;
    CECKey key;
    key.SetSecretBytes(vch);
    return key.Sign(hash, vchSig);
}

bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
    if (!fValid)
        return false;
    CECKey key;
    key.SetSecretBytes(vch);
    vchSig.resize(65);
    int rec = -1;
    if (!key.SignCompact(hash, &vchSig[1], rec))
        return false;
    assert(rec != -1);
    vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
    return true;
}

bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
    if (!IsValid())
        return false;
    CECKey key;
    if (!key.SetPubKey(*this))
        return false;
    if (!key.Verify(hash, vchSig))
        return false;
    return true;
}

bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
    if (vchSig.size() != 65)
        return false;
    CECKey key;
    if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
        return false;
    key.GetPubKey(*this, (vchSig[0] - 27) & 4);
    return true;
}

bool CPubKey::VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
    if (!IsValid())
        return false;
    if (vchSig.size() != 65)
        return false;
    CECKey key;
    if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
        return false;
    CPubKey pubkeyRec;
    key.GetPubKey(pubkeyRec, IsCompressed());
    if (*this != pubkeyRec)
        return false;
    return true;
}

bool CPubKey::IsFullyValid() const {
    if (!IsValid())
        return false;
    CECKey key;
    if (!key.SetPubKey(*this))
        return false;
    return true;
}

bool CPubKey::Decompress() {
    if (!IsValid())
        return false;
    CECKey key;
    if (!key.SetPubKey(*this))
        return false;
    key.GetPubKey(*this, false);
    return true;
}
<commit_msg>verify signature in DER format<commit_after>// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <openssl/ecdsa.h>
#include <openssl/rand.h>
#include <openssl/obj_mac.h>
#include "Crypto.h" // i2pd
#include "Gost.h" // i2pd

#include "key.h"

// anonymous namespace with local implementation code (OpenSSL interaction)
namespace {

// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
    int ok = 0;
    BN_CTX *ctx = NULL;
    EC_POINT *pub_key = NULL;

    if (!eckey) return 0;

    const EC_GROUP *group = EC_KEY_get0_group(eckey);

    if ((ctx = BN_CTX_new()) == NULL)
        goto err;

    pub_key = EC_POINT_new(group);

    if (pub_key == NULL)
        goto err;

    if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
        goto err;

    EC_KEY_set_private_key(eckey,priv_key);
    EC_KEY_set_public_key(eckey,pub_key);

    ok = 1;

err:

    if (pub_key)
        EC_POINT_free(pub_key);
    if (ctx != NULL)
        BN_CTX_free(ctx);

    return(ok);
}

// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
// recid selects which key is recovered
// if check is non-zero, additional checks are performed
static int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
{
    if (!eckey) return 0;
	BIGNUM * d = BN_bin2bn (msg, msglen, nullptr);
	const auto& curve = i2p::crypto::GetGOSTR3410Curve (i2p::crypto::eGOSTR3410CryptoProA);
	EC_POINT * pub = curve->RecoverPublicKey (d, ecsig->r, ecsig->s, recid % 2);
	BN_free (d);
	if (!pub) return 0;
	EC_KEY_set_public_key(eckey, pub);
	EC_POINT_free (pub);
	return 1;
}

// RAII Wrapper around OpenSSL's EC_KEY
class CECKey {
private:
    EC_KEY *pkey;

public:
    CECKey()
	{
		pkey = EC_KEY_new ();
		// GOST 34.10-2012
		auto ret = EC_KEY_set_group(pkey, i2p::crypto::GetGOSTR3410Curve (i2p::crypto::eGOSTR3410CryptoProA)->GetGroup ());
		assert (ret == 1);
    }

    ~CECKey() {
        EC_KEY_free(pkey);
    }

    void GetSecretBytes(unsigned char vch[32]) const {
        const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
        assert(bn);
        int nBytes = BN_num_bytes(bn);
        int n=BN_bn2bin(bn,&vch[32 - nBytes]);
        assert(n == nBytes);
        memset(vch, 0, 32 - nBytes);
    }

    void SetSecretBytes(const unsigned char vch[32]) {
        BIGNUM bn;
        BN_init(&bn);
        assert(BN_bin2bn(vch, 32, &bn));
        assert(EC_KEY_regenerate_key(pkey, &bn));
        BN_clear_free(&bn);
    }

    void GetPrivKey(CPrivKey &privkey, bool fCompressed) {
        EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
        int nSize = i2d_ECPrivateKey(pkey, NULL);
        assert(nSize);
        privkey.resize(nSize);
        unsigned char* pbegin = &privkey[0];
        int nSize2 = i2d_ECPrivateKey(pkey, &pbegin);
        assert(nSize == nSize2);
    }

    bool SetPrivKey(const CPrivKey &privkey) {
        const unsigned char* pbegin = &privkey[0];
        if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) {
            // d2i_ECPrivateKey returns true if parsing succeeds.
            // This doesn't necessarily mean the key is valid.
            if (EC_KEY_check_key(pkey))
                return true;
        }
        return false;
    }

    void GetPubKey(CPubKey &pubkey, bool fCompressed) {
        EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED);
        int nSize = i2o_ECPublicKey(pkey, NULL);
        assert(nSize);
        assert(nSize <= 65);
        unsigned char c[65];
        unsigned char *pbegin = c;
        int nSize2 = i2o_ECPublicKey(pkey, &pbegin);
        assert(nSize == nSize2);
        pubkey.Set(&c[0], &c[nSize]);
    }

    bool SetPubKey(const CPubKey &pubkey) {
        const unsigned char* pbegin = pubkey.begin();
        return o2i_ECPublicKey(&pkey, &pbegin, pubkey.size());
    }

    bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig)
	{
		const BIGNUM * priv = EC_KEY_get0_private_key(pkey);
		BIGNUM * d = BN_bin2bn (hash.begin (), 32, nullptr);
		ECDSA_SIG *sig = ECDSA_SIG_new ();
		i2p::crypto::GetGOSTR3410Curve (i2p::crypto::eGOSTR3410CryptoProA)->Sign (priv, d, sig->r, sig->s);
		// encode signature is in DER format
		auto nSize = ECDSA_size (pkey); // max size
		vchSig.resize(nSize);
		auto p = &vchSig[0];
		nSize = i2d_ECDSA_SIG (sig, &p);
		vchSig.resize(nSize); // acutal size
		BN_free (d);
		ECDSA_SIG_free(sig);
        return true;
    }

    bool Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig)
	{
		// decode from DER
		ECDSA_SIG *sig = nullptr;
		auto p = &vchSig[0];
		d2i_ECDSA_SIG (&sig, &p, vchSig.size());
		const EC_POINT * pub = EC_KEY_get0_public_key(pkey);
		BIGNUM * d = BN_bin2bn (hash.begin (), 32, nullptr);
		bool ret = i2p::crypto::GetGOSTR3410Curve (i2p::crypto::eGOSTR3410CryptoProA)->Verify (pub, d, sig->r, sig->s);
		BN_free (d);
		ECDSA_SIG_free(sig);
		return ret;
    }

    bool SignCompact(const uint256 &hash, unsigned char *p64, int &rec)
	{
        bool fOk = false;
        ECDSA_SIG *sig = ECDSA_SIG_new ();
		const BIGNUM * priv = EC_KEY_get0_private_key(pkey);
		BIGNUM * d = BN_bin2bn (hash.begin (), 32, nullptr);
		i2p::crypto::GetGOSTR3410Curve (i2p::crypto::eGOSTR3410CryptoProA)->Sign (priv, d, sig->r, sig->s);
		BN_free (d);
        if (sig==NULL)
            return false;
        memset(p64, 0, 64);
        int nBitsR = BN_num_bits(sig->r);
        int nBitsS = BN_num_bits(sig->s);
        if (nBitsR <= 256 && nBitsS <= 256) {
            CPubKey pubkey;
            GetPubKey(pubkey, true);
            for (int i=0; i<2; i++) {
                CECKey keyRec;
                if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) {
                    CPubKey pubkeyRec;
                    keyRec.GetPubKey(pubkeyRec, true);
                    if (pubkeyRec == pubkey) {
                        rec = i;
                        fOk = true;
                        break;
                    }
                }
            }
            assert(fOk);
            BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]);
            BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]);
        }
        ECDSA_SIG_free(sig);
        return fOk;
    }

    // reconstruct public key from a compact signature
    // This is only slightly more CPU intensive than just verifying it.
    // If this function succeeds, the recovered public key is guaranteed to be valid
    // (the signature is a valid signature of the given data for that key)
    bool Recover(const uint256 &hash, const unsigned char *p64, int rec)
    {
        if (rec<0 || rec>=3)
            return false;
        ECDSA_SIG *sig = ECDSA_SIG_new();
        BN_bin2bn(&p64[0],  32, sig->r);
        BN_bin2bn(&p64[32], 32, sig->s);
        bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
        ECDSA_SIG_free(sig);
        return ret;
    }
};

}; // end of anonymous namespace

bool CKey::Check(const unsigned char *vch) {
    // Do not convert to OpenSSL's data structures for range-checking keys,
    // it's easy enough to do directly.
    static const unsigned char vchMax[32] = {
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
        0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
        0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
        0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
    };
    bool fIsZero = true;
    for (int i=0; i<32 && fIsZero; i++)
        if (vch[i] != 0)
            fIsZero = false;
    if (fIsZero)
        return false;
    for (int i=0; i<32; i++) {
        if (vch[i] < vchMax[i])
            return true;
        if (vch[i] > vchMax[i])
            return false;
    }
    return true;
}

void CKey::MakeNewKey(bool fCompressedIn) {
    do {
        RAND_bytes(vch, sizeof(vch));
    } while (!Check(vch));
    fValid = true;
    fCompressed = fCompressedIn;
}

bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
    CECKey key;
    if (!key.SetPrivKey(privkey))
        return false;
    key.GetSecretBytes(vch);
    fCompressed = fCompressedIn;
    fValid = true;
    return true;
}

CPrivKey CKey::GetPrivKey() const {
    assert(fValid);
    CECKey key;
    key.SetSecretBytes(vch);
    CPrivKey privkey;
    key.GetPrivKey(privkey, fCompressed);
    return privkey;
}

CPubKey CKey::GetPubKey() const {
    assert(fValid);
    CECKey key;
    key.SetSecretBytes(vch);
    CPubKey pubkey;
    key.GetPubKey(pubkey, fCompressed);
    return pubkey;
}

bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
    if (!fValid)
        return false;
    CECKey key;
    key.SetSecretBytes(vch);
    return key.Sign(hash, vchSig);
}

bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
    if (!fValid)
        return false;
    CECKey key;
    key.SetSecretBytes(vch);
    vchSig.resize(65);
    int rec = -1;
    if (!key.SignCompact(hash, &vchSig[1], rec))
        return false;
    assert(rec != -1);
    vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
    return true;
}

bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
    if (!IsValid())
        return false;
    CECKey key;
    if (!key.SetPubKey(*this))
        return false;
    if (!key.Verify(hash, vchSig))
        return false;
    return true;
}

bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
    if (vchSig.size() != 65)
        return false;
    CECKey key;
    if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
        return false;
    key.GetPubKey(*this, (vchSig[0] - 27) & 4);
    return true;
}

bool CPubKey::VerifyCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
    if (!IsValid())
        return false;
    if (vchSig.size() != 65)
        return false;
    CECKey key;
    if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
        return false;
    CPubKey pubkeyRec;
    key.GetPubKey(pubkeyRec, IsCompressed());
    if (*this != pubkeyRec)
        return false;
    return true;
}

bool CPubKey::IsFullyValid() const {
    if (!IsValid())
        return false;
    CECKey key;
    if (!key.SetPubKey(*this))
        return false;
    return true;
}

bool CPubKey::Decompress() {
    if (!IsValid())
        return false;
    CECKey key;
    if (!key.SetPubKey(*this))
        return false;
    key.GetPubKey(*this, false);
    return true;
}
<|endoftext|>


<commit_before># include "ProdConsum.h"
# include <chrono>
# include <thread>
# include <iomanip>

template <typename ElementType>
struct	FakeHandleElementPolicy
{
	using _ElementType = ElementType;

	static bool	HandleElement(ElementType * element)
	{
		bool returnValue(element != 0x0);
		THREAD_SAFE_STDCOUT("[-] : Consumer : " << std::setw(4) << std::this_thread::get_id() << " : [0x" << element << "] => [" << *element << "]");
		delete element;
		std::this_thread::sleep_for(std::chrono::milliseconds(300));
		return returnValue;
	}
};

template <typename QueueType, typename ConsumerType, size_t Qty>
struct	ConsumerPool
{
	explicit ConsumerPool(QueueType & queue)
	{
		for (size_t i = 0; i < Qty; ++i)
			this->_content.push_back(new ConsumerType(queue));
	}
	ConsumerPool(const ConsumerPool &) = delete;
	ConsumerPool(const ConsumerPool &&) = delete;
	ConsumerPool & operator=(const ConsumerPool &) = delete;
	~ConsumerPool()
	{
		for (auto & consumerPtr : _content)
			delete consumerPtr;
	}

	void	Apply(std::function<void(ConsumerType&)> & func)
	{
		for (auto & consumerPtr : _content)
			func(*consumerPtr);
	}
	void	LauchASync(void)
	{
		for (auto & consumerPtr : _content)
		{
			this->_asyncFutures.push_back(
			{
				std::async(std::launch::async, [&](ConsumerType * consumer) mutable	// Osef, je copie le pointer, c'est cheap
				{
					consumer->Work();
				}, consumerPtr)
			});
		}
	}
	void	GetSync(void)
	{
		for (auto & future : _asyncFutures)
			future.get();
	}

protected:
	std::vector<ConsumerType*>		_content;
	std::vector<std::future<void> >	_asyncFutures;
};

template <typename ElementType>
struct FakeUniqueRscCreationPolicy
{
	using _ElementType = ElementType;

	static ElementType * GetNewInstance(void)
	{
		return new ElementType();
	}
};

int	main(int ac, char* av[])
{
	using ElementType = int;
	using QueueType = GCL::Queue < ElementType > ;
	using HandleElementPolicy = FakeHandleElementPolicy < ElementType > ;
	using ConsumerType = GCL::Consumer < QueueType, HandleElementPolicy > ;

	// [Producer]
	/*QueueType	queue;
	auto		producingAsync = std::async(std::launch::async, [&queue](QueueType & queue) mutable
	{
		ElementType * element;
		for (size_t i = 0; i < 100; ++i)
		{
			element = new ElementType(i);
			THREAD_SAFE_STDCOUT("[+] : Producer : " << std::setw(4) << std::this_thread::get_id() << " : [0x" << element << "] => [" << *element << "]");
			queue.Push(element);
			std::this_thread::sleep_for(std::chrono::milliseconds(100));
		}
	}, std::ref(queue));
*/
	// [1 consumer]
	//GCL::Consumer<QueueType, HandleElementPolicy> consumer(queue);
	//auto		consumerAsync = std::async(std::launch::async, [&consumer](GCL::Consumer<QueueType, HandleElementPolicy> & consumer) mutable
	//{
	//	consumer.Work();
	//}, std::ref(consumer));
	//producingAsync.get();
	//consumer.RequiereStopIfLazy();
	//consumerAsync.get();

	// [n(2) consumers]
	//ConsumerPool<QueueType, ConsumerType, 2> consumers(queue);
	//consumers.LauchASync();
	//producingAsync.get();
	//consumers.Apply(std::function<void(ConsumerType &)>([&](ConsumerType & consumer) mutable -> void
	//{
	//	consumer.RequiereStopIfLazy();
	//}));
	//queue.StopAllPendingWait();
	//consumers.GetSync();

	// [Unique Rcs] (very trash test !)
	GCL::Thread::UniqueRsc<ElementType, FakeUniqueRscCreationPolicy<ElementType> >	uniqueRsc;
	std::vector<std::future<void>>	_vec;
	for (size_t i = 0; i < 10; ++i)
		_vec.emplace_back(std::async(std::launch::async, [&uniqueRsc](void) -> void
		{
			for (size_t i = 0; i < 5; ++i)
			{
				THREAD_SAFE_STDCOUT('[' << std::setw(8) << std::this_thread::get_id() << "] -> rcs=[0x" << &(uniqueRsc.Get()) << ']');
				std::this_thread::sleep_for(std::chrono::seconds(1));
			}
		}));
	for (auto & elem : _vec)
		elem.get();

	system("pause");
	return 0;
}<commit_msg>Fixing repo user name + global 2<commit_after># include "ProdConsum.h"
# include <chrono>
# include <thread>
# include <iomanip>

template <typename ElementType>
struct	FakeHandleElementPolicy
{
	using _ElementType = ElementType;

	static bool	HandleElement(ElementType * element)
	{
		bool returnValue(element != 0x0);
		THREAD_SAFE_STDCOUT("[-] : Consumer : " << std::setw(4) << std::this_thread::get_id() << " : [0x" << element << "] => [" << *element << "]");
		delete element;
		std::this_thread::sleep_for(std::chrono::milliseconds(300));
		return returnValue;
	}
};

template <typename QueueType, typename ConsumerType, size_t Qty>
struct	ConsumerPool
{
	explicit ConsumerPool(QueueType & queue)
	{
		for (size_t i = 0; i < Qty; ++i)
			this->_content.push_back(new ConsumerType(queue));
	}
	ConsumerPool(const ConsumerPool &) = delete;
	ConsumerPool(const ConsumerPool &&) = delete;
	ConsumerPool & operator=(const ConsumerPool &) = delete;
	~ConsumerPool()
	{
		for (auto & consumerPtr : _content)
			delete consumerPtr;
	}

	void	Apply(std::function<void(ConsumerType&)> & func)
	{
		for (auto & consumerPtr : _content)
			func(*consumerPtr);
	}
	void	LauchASync(void)
	{
		for (auto & consumerPtr : _content)
		{
			this->_asyncFutures.push_back(
			{
				std::async(std::launch::async, [&](ConsumerType * consumer) mutable	// Osef, je copie le pointer, c'est cheap
				{
					consumer->Work();
				}, consumerPtr)
			});
		}
	}
	void	GetSync(void)
	{
		for (auto & future : _asyncFutures)
			future.get();
	}

protected:
	std::vector<ConsumerType*>		_content;
	std::vector<std::future<void> >	_asyncFutures;
};

template <typename ElementType>
struct FakeUniqueRscCreationPolicy
{
	using _ElementType = ElementType;

	static ElementType * GetNewInstance(void)
	{
		return new ElementType();
	}
};

int	main(int ac, char* av[])
{
	using ElementType = int;
	using QueueType = GCL::Queue < ElementType > ;
	using HandleElementPolicy = FakeHandleElementPolicy < ElementType > ;
	using ConsumerType = GCL::Consumer < QueueType, HandleElementPolicy > ;

	// [Producer]
	/*QueueType	queue;
	auto		producingAsync = std::async(std::launch::async, [&queue](QueueType & queue) mutable
	{
		ElementType * element;
		for (size_t i = 0; i < 100; ++i)
		{
			element = new ElementType(i);
			THREAD_SAFE_STDCOUT("[+] : Producer : " << std::setw(4) << std::this_thread::get_id() << " : [0x" << element << "] => [" << *element << "]");
			queue.Push(element);
			std::this_thread::sleep_for(std::chrono::milliseconds(100));
		}
	}, std::ref(queue));
*/
	// [1 consumer]
	//GCL::Consumer<QueueType, HandleElementPolicy> consumer(queue);
	//auto		consumerAsync = std::async(std::launch::async, [&consumer](GCL::Consumer<QueueType, HandleElementPolicy> & consumer) mutable
	//{
	//	consumer.Work();
	//}, std::ref(consumer));
	//producingAsync.get();
	//consumer.RequiereStopIfLazy();
	//consumerAsync.get();

	// [n(2) consumers]
	//ConsumerPool<QueueType, ConsumerType, 2> consumers(queue);
	//consumers.LauchASync();
	//producingAsync.get();
	//consumers.Apply(std::function<void(ConsumerType &)>([&](ConsumerType & consumer) mutable -> void
	//{
	//	consumer.RequiereStopIfLazy();
	//}));
	//queue.StopAllPendingWait();
	//consumers.GetSync();

	// [Unique Rcs] (very trash test)
	GCL::Thread::UniqueRsc<ElementType, FakeUniqueRscCreationPolicy<ElementType> >	uniqueRsc;
	std::vector<std::future<void>>	_vec;
	for (size_t i = 0; i < 10; ++i)
		_vec.emplace_back(std::async(std::launch::async, [&uniqueRsc](void) -> void
		{
			for (size_t i = 0; i < 5; ++i)
			{
				THREAD_SAFE_STDCOUT('[' << std::setw(8) << std::this_thread::get_id() << "] -> rcs=[0x" << &(uniqueRsc.Get()) << ']');
				std::this_thread::sleep_for(std::chrono::seconds(1));
			}
		}));
	for (auto & elem : _vec)
		elem.get();

	system("pause");
	return 0;
}<|endoftext|>


<commit_before>#include "Workspace.h"

#include <memory>
#include "utils.h"
#include "git.h"
#include "estd.h"
#include "graph.h"

using namespace aBuild;

static void checkingMissingPackages(Workspace& ws) {
	// Checking missing packages
	auto missingPackages = ws.getAllMissingPackages();
	while (not missingPackages.empty()) {
		for (auto const& p : missingPackages) {
			PackageURL url(p);

			git::clone(url.getURL(), url.getBranch(), url.getPath());
		}
		missingPackages = ws.getAllMissingPackages();
	}
}
static void checkingNotNeededPackages(Workspace& ws) {
	// Checking not needed packages
	auto notRequiredPackages = ws.getAllNotRequiredPackages();
	while (not notRequiredPackages.empty()) {
		for (auto const& s : notRequiredPackages) {
			std::cout<<"Not Required "<<s<<std::endl;
			utils::rm(std::string("packages/")+s, true, true);
		}
		notRequiredPackages = ws.getAllNotRequiredPackages();
	}
}
static void checkingInvalidPackages(Workspace& ws) {
	// checking invalid packages
	auto invalidPackages = ws.getAllInvalidPackages();
	for (auto const& p : invalidPackages) {
		std::cout<<"Package is ill formed: "<<p<<std::endl;
	}
}

static void checkingRequiredPackages(Workspace& ws) {
	// check branches (if the correct ones are checked out
	auto requiredPackages = ws.getAllRequiredPackages();
	for (auto const& _url : requiredPackages) {
		PackageURL url {_url};
		utils::Cwd cwd(url.getPath());
		if (not git::isDirty()) {
			if (url.getBranch() != git::getBranch()) {
				std::cout<<"Changing branch of "<<url.getName()<<std::endl;
				git::checkout(url.getBranch());
			}
		}
	}
}

using Action = std::function<void()>;

int main(int argc, char** argv) {
	try {
		if (argc == 1) {
			Workspace ws(".");

			checkingMissingPackages(ws);
			checkingNotNeededPackages(ws);
			checkingInvalidPackages(ws);
			checkingRequiredPackages(ws);

			Graph graph;

			std::function<void(Project*)> linkingLibFunc = [&graph](Project* project) {
				utils::mkdir(".aBuild/lib/");
				std::string call = "ar rcs .aBuild/lib/"+project->getName()+".a";
				// Get file dependencies
				{
					auto ingoing = graph.getIngoing<std::string, Project>(project, false);
					for (auto const& f : ingoing) {
						call += " .aBuild/obj/"+ *f + ".o";
					}
				}
				utils::runProcess(call);
//				std::cout<<call<<std::endl;
			};
			std::function<void(Project*)> linkingExecFunc = [&graph](Project* project) {
				utils::mkdir("bin");
				utils::mkdir("bin/tests");
				std::string outFile = std::string("bin/")+project->getName();
				if (utils::isStartingWith(project->getName(), "test")) {
					outFile = std::string("bin/tests/")+project->getName();
				}
				std::string call = "ccache clang++ -o "+outFile;

				// Set all depLibraries libraries
				for (auto const& l : project->getDepLibraries()) {
					call += " -l"+l;
				}
				// Get file dependencies
				{
					auto ingoing = graph.getIngoing<std::string, Project>(project, false);
					for (auto const& f : ingoing) {
						call += " .aBuild/obj/"+ *f + ".o";
					}
				}
				// Get project dependencies
				{
					auto outgoing = graph.getIngoing<Project, Project>(project, true);
					for (auto const& f : outgoing) {
						call += " .aBuild/lib/"+f->getName()+".a";

						// Set all depLibraries libraries
						for (auto const& l : f->getDepLibraries()) {
							call += " -l"+l;
						}

					}
				}
//				std::cout<<call<<std::endl;
				utils::runProcess(call);

			};

			std::function<void(std::string*)> compileFileFunc = [&graph](std::string* f) {

				auto l = utils::explode(*f, "/");

				utils::mkdir(".aBuild/obj/" + utils::dirname(*f));
				std::string call = "ccache clang++ -Qunused-arguments -ggdb -O0 --std=c++11 "
				                   "-c " + *f + " "
				                   "-o .aBuild/obj/" + *f + ".o";

				// Get include dependencies
				{
					Project* project = *graph.getOutgoing<Project, std::string>(f, false).begin();
					for (auto const& i : project->getLegacy().includes) {
						call += " -I "+project->getPackagePath()+"/"+i;
					}
					call += " -I "+project->getPackagePath()+"/src/"+project->getPath();
					call += " -I "+project->getPackagePath()+"/src/";

					auto ingoing = graph.getIngoing<Project, Project>(project, true);
					for (auto const& f : ingoing) {
						call += " -isystem "+f->getPackagePath()+"/src";
						for (auto const& i : f->getLegacy().includes) {
							call += " -isystem "+f->getPackagePath()+"/"+i;
						}
					}
				}
				utils::runProcess(call);
//				std::cout<<call<<std::endl;
			};

			// Create dependency tree
			auto projects = ws.getAllRequiredProjects();
			for (auto& e  : projects) {
				auto& project = e.second;
				// Adding linking
				if (project.getType() == "library") {
					graph.addNode(&project, linkingLibFunc);
				} else if (project.getType() == "executable") {
					graph.addNode(&project,  linkingExecFunc);
				} else {
					std::cout<<"invalid type: "<<project.getType()<<std::endl;
				}

				// Adding compile files
				for (auto& f : project.getAllCppFiles()) {
					graph.addNode(&f, compileFileFunc);
					graph.addEdge(&f, &project);
				}
				for (auto const& dep : project.getDependencies()) {
					auto l = utils::explode(dep, "/");
					graph.addEdge(&projects.at(l[1]), &project);
				}
			}

			graph.visitAllNodes();

		} else if (argc == 2 && std::string(argv[1]) == "pull") {
			auto allPackages = utils::listDirs("./packages", true);
			//!TODO This should be done in parallel
			for (auto const& s : allPackages) {
				auto file = std::string("./packages/") + s;
				utils::Cwd cwd(file);
				if (git::isDirty()) {
					std::cout<<"ignore " << file << ": Dirty repository"<<std::endl;
				} else {
					git::pull();
				}
			}
		} else if (argc == 2 && std::string(argv[1]) == "push") {
			auto allPackages = utils::listDirs("./packages", true);
			//!TODO This should be done in parallel
			for (auto const& s : allPackages) {
				auto file = std::string("./packages/") + s;
				utils::Cwd cwd(file);
				git::push();
			}
		} else if (argc == 2 && std::string(argv[1]) == "test") {
			auto allTests = utils::listFiles("./bin/tests/");
			std::cout<<"===Start testing==="<<std::endl;
			for (auto const& t : allTests) {
				auto p = std::string("./bin/tests/")+t;
				system(p.c_str());
				std::cout<<" • running "<<p<<std::endl;
			}
			std::cout<<"ran "<<allTests.size()<<" test(s)"<<std::endl;
			std::cout<<"===Ended testing==="<<std::endl;
		}

	} catch(std::exception const& e) {
		std::cerr<<"exception: "<<e.what()<<std::endl;
	}
	return 0;
}
<commit_msg>adding a very simple install command<commit_after>#include "Workspace.h"

#include <memory>
#include <stdio.h>

#include "utils.h"
#include "git.h"
#include "estd.h"
#include "graph.h"

using namespace aBuild;

static void checkingMissingPackages(Workspace& ws) {
	// Checking missing packages
	auto missingPackages = ws.getAllMissingPackages();
	while (not missingPackages.empty()) {
		for (auto const& p : missingPackages) {
			PackageURL url(p);

			git::clone(url.getURL(), url.getBranch(), url.getPath());
		}
		missingPackages = ws.getAllMissingPackages();
	}
}
static void checkingNotNeededPackages(Workspace& ws) {
	// Checking not needed packages
	auto notRequiredPackages = ws.getAllNotRequiredPackages();
	while (not notRequiredPackages.empty()) {
		for (auto const& s : notRequiredPackages) {
			std::cout<<"Not Required "<<s<<std::endl;
			utils::rm(std::string("packages/")+s, true, true);
		}
		notRequiredPackages = ws.getAllNotRequiredPackages();
	}
}
static void checkingInvalidPackages(Workspace& ws) {
	// checking invalid packages
	auto invalidPackages = ws.getAllInvalidPackages();
	for (auto const& p : invalidPackages) {
		std::cout<<"Package is ill formed: "<<p<<std::endl;
	}
}

static void checkingRequiredPackages(Workspace& ws) {
	// check branches (if the correct ones are checked out
	auto requiredPackages = ws.getAllRequiredPackages();
	for (auto const& _url : requiredPackages) {
		PackageURL url {_url};
		utils::Cwd cwd(url.getPath());
		if (not git::isDirty()) {
			if (url.getBranch() != git::getBranch()) {
				std::cout<<"Changing branch of "<<url.getName()<<std::endl;
				git::checkout(url.getBranch());
			}
		}
	}
}

using Action = std::function<void()>;

int main(int argc, char** argv) {
	try {
		if (argc == 1) {
			Workspace ws(".");

			checkingMissingPackages(ws);
			checkingNotNeededPackages(ws);
			checkingInvalidPackages(ws);
			checkingRequiredPackages(ws);

			Graph graph;

			std::function<void(Project*)> linkingLibFunc = [&graph](Project* project) {
				utils::mkdir(".aBuild/lib/");
				std::string call = "ar rcs .aBuild/lib/"+project->getName()+".a";
				// Get file dependencies
				{
					auto ingoing = graph.getIngoing<std::string, Project>(project, false);
					for (auto const& f : ingoing) {
						call += " .aBuild/obj/"+ *f + ".o";
					}
				}
				utils::runProcess(call);
//				std::cout<<call<<std::endl;
			};
			std::function<void(Project*)> linkingExecFunc = [&graph](Project* project) {
				utils::mkdir("bin");
				utils::mkdir("bin/tests");
				std::string outFile = std::string("bin/")+project->getName();
				if (utils::isStartingWith(project->getName(), "test")) {
					outFile = std::string("bin/tests/")+project->getName();
				}
				std::string call = "ccache clang++ -o "+outFile;

				// Set all depLibraries libraries
				for (auto const& l : project->getDepLibraries()) {
					call += " -l"+l;
				}
				// Get file dependencies
				{
					auto ingoing = graph.getIngoing<std::string, Project>(project, false);
					for (auto const& f : ingoing) {
						call += " .aBuild/obj/"+ *f + ".o";
					}
				}
				// Get project dependencies
				{
					auto outgoing = graph.getIngoing<Project, Project>(project, true);
					for (auto const& f : outgoing) {
						call += " .aBuild/lib/"+f->getName()+".a";

						// Set all depLibraries libraries
						for (auto const& l : f->getDepLibraries()) {
							call += " -l"+l;
						}

					}
				}
//				std::cout<<call<<std::endl;
				utils::runProcess(call);

			};

			std::function<void(std::string*)> compileFileFunc = [&graph](std::string* f) {

				auto l = utils::explode(*f, "/");

				utils::mkdir(".aBuild/obj/" + utils::dirname(*f));
				std::string call = "ccache clang++ -Qunused-arguments -ggdb -O0 --std=c++11 "
				                   "-c " + *f + " "
				                   "-o .aBuild/obj/" + *f + ".o";

				// Get include dependencies
				{
					Project* project = *graph.getOutgoing<Project, std::string>(f, false).begin();
					for (auto const& i : project->getLegacy().includes) {
						call += " -I "+project->getPackagePath()+"/"+i;
					}
					call += " -I "+project->getPackagePath()+"/src/"+project->getPath();
					call += " -I "+project->getPackagePath()+"/src/";

					auto ingoing = graph.getIngoing<Project, Project>(project, true);
					for (auto const& f : ingoing) {
						call += " -isystem "+f->getPackagePath()+"/src";
						for (auto const& i : f->getLegacy().includes) {
							call += " -isystem "+f->getPackagePath()+"/"+i;
						}
					}
				}
				utils::runProcess(call);
//				std::cout<<call<<std::endl;
			};

			// Create dependency tree
			auto projects = ws.getAllRequiredProjects();
			for (auto& e  : projects) {
				auto& project = e.second;
				// Adding linking
				if (project.getType() == "library") {
					graph.addNode(&project, linkingLibFunc);
				} else if (project.getType() == "executable") {
					graph.addNode(&project,  linkingExecFunc);
				} else {
					std::cout<<"invalid type: "<<project.getType()<<std::endl;
				}

				// Adding compile files
				for (auto& f : project.getAllCppFiles()) {
					graph.addNode(&f, compileFileFunc);
					graph.addEdge(&f, &project);
				}
				for (auto const& dep : project.getDependencies()) {
					auto l = utils::explode(dep, "/");
					graph.addEdge(&projects.at(l[1]), &project);
				}
			}

			graph.visitAllNodes();

		} else if (argc == 2 && std::string(argv[1]) == "pull") {
			auto allPackages = utils::listDirs("./packages", true);
			//!TODO This should be done in parallel
			for (auto const& s : allPackages) {
				auto file = std::string("./packages/") + s;
				utils::Cwd cwd(file);
				if (git::isDirty()) {
					std::cout<<"ignore " << file << ": Dirty repository"<<std::endl;
				} else {
					git::pull();
				}
			}
		} else if (argc == 2 && std::string(argv[1]) == "push") {
			auto allPackages = utils::listDirs("./packages", true);
			//!TODO This should be done in parallel
			for (auto const& s : allPackages) {
				auto file = std::string("./packages/") + s;
				utils::Cwd cwd(file);
				git::push();
			}
		} else if (argc == 2 && std::string(argv[1]) == "test") {
			auto allTests = utils::listFiles("./bin/tests/");
			std::cout<<"===Start testing==="<<std::endl;
			for (auto const& t : allTests) {
				auto p = std::string("./bin/tests/")+t;
				system(p.c_str());
				std::cout<<" • running "<<p<<std::endl;
			}
			std::cout<<"ran "<<allTests.size()<<" test(s)"<<std::endl;
			std::cout<<"===Ended testing==="<<std::endl;
		} else if (argc == 2 && std::string(argv[1]) == "install") {
			auto allFiles = utils::listFiles("./bin/");
			for (auto const& f : allFiles) {
				std::cout<<"installing "<<f<<"; Error Code: ";
				auto oldFile = std::string("./bin/")+f;
				auto newFile = std::string("/usr/bin/")+f;
				auto cpFile  = std::string("cp ")+newFile+" "+oldFile;
				auto error = rename(oldFile.c_str(), newFile.c_str());
				std::cout<<error<<std::endl;
				system(cpFile.c_str());

			}
		}

	} catch(std::exception const& e) {
		std::cerr<<"exception: "<<e.what()<<std::endl;
	}
	return 0;
}
<|endoftext|>


<commit_before>#include <sqlite3.h>
#include <glib.h>
#include <errno.h>
#include <stdio.h>
#include <algorithm>

#include <QDateTime>

#include "account-mgr.h"
#include "configurator.h"
#include "seafile-applet.h"
#include "utils/utils.h"

AccountManager::AccountManager()
{
    db = NULL;
}

AccountManager::~AccountManager()
{
    if (db)
        sqlite3_close(db);
}

int AccountManager::start()
{
    const char *errmsg;
    const char *sql;

    QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("accounts.db");
    if (sqlite3_open (toCStr(db_path), &db)) {
        errmsg = sqlite3_errmsg (db);
        qDebug("failed to open account database %s: %s",
               toCStr(db_path), errmsg ? errmsg : "no error given");

        seafApplet->errorAndExit(tr("failed to open account database"));
        return -1;
    }

    sql = "CREATE TABLE IF NOT EXISTS Accounts (url VARCHAR(24), "
        "username VARCHAR(15), token VARCHAR(40), lastVisited INTEGER, "
        "PRIMARY KEY(url, username))";
    sqlite_query_exec (db, sql);

    loadAccounts();
    return 0;
}

bool AccountManager::loadAccountsCB(sqlite3_stmt *stmt, void *data)
{
    AccountManager *mgr = (AccountManager *)data;
    const char *url = (const char *)sqlite3_column_text (stmt, 0);
    const char *username = (const char *)sqlite3_column_text (stmt, 1);
    const char *token = (const char *)sqlite3_column_text (stmt, 2);
    qint64 atime = (qint64)sqlite3_column_int64 (stmt, 3);

    Account account = Account(QUrl(QString(url)), QString(username), QString(token), atime);
    mgr->accounts_.push_back(account);
    return true;
}

const std::vector<Account>& AccountManager::loadAccounts()
{
    const char *sql = "SELECT url, username, token, lastVisited FROM Accounts "
        "ORDER BY lastVisited DESC";
    accounts_.clear();
    sqlite_foreach_selected_row (db, sql, loadAccountsCB, this);
    return accounts_;
}

int AccountManager::saveAccount(const Account& account)
{
    int i = 0;
    for (i = 0; i < accounts_.size(); i++) {
        if (accounts_[i].serverUrl == account.serverUrl
            && accounts_[i].username == account.username) {
            accounts_.erase(accounts_.begin() + i);
            break;
        }
    }

    accounts_.insert(accounts_.begin(), account);

    QString url = account.serverUrl.toEncoded().data();
    qint64 timestamp = QDateTime::currentMSecsSinceEpoch();

    QString sql = "REPLACE INTO Accounts VALUES ('%1', '%2', '%3', %4) ";
    sql = sql.arg(url).arg(account.username).arg(account.token).arg(QString::number(timestamp));
    sqlite_query_exec (db, toCStr(sql));

    emit accountsChanged();

    return 0;
}

int AccountManager::removeAccount(const Account& account)
{
    QString url = account.serverUrl.toEncoded().data();

    QString sql = "DELETE FROM Accounts WHERE url = '%1' AND username = '%2'";
    sql = sql.arg(url).arg(account.username);
    sqlite_query_exec (db, toCStr(sql));

    accounts_.erase(std::remove(accounts_.begin(), accounts_.end(), account),
                    accounts_.end());

    emit accountsChanged();

    return 0;
}

void AccountManager::updateAccountLastVisited(const Account& account)
{
    const char *url = account.serverUrl.toEncoded().data();

    QString sql = "UPDATE Accounts SET lastVisited = %1 "
        "WHERE username = '%2' AND url = '%3'";

    qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
    sql = sql.arg(QString::number(timestamp)).arg(account.username).arg(url);
    sqlite_query_exec (db, toCStr(sql));
}

bool AccountManager::accountExists(const QUrl& url, const QString& username)
{
    int i, n = accounts_.size();
    for (i = 0; i < n; i++) {
        if (accounts_[i].serverUrl == url && accounts_[i].username == username) {
            return true;
        }
    }

    return false;
}

bool AccountManager::setCurrentAccount(const Account& account)
{
    if (account == currentAccount()) {
        return false;
    }

    // Would emit "accountsChanged" signal
    saveAccount(account);

    return true;
}

int AccountManager::replaceAccount(const Account& old_account, const Account& new_account)
{
    int i = 0;
    for (i = 0; i < accounts_.size(); i++) {
        if (accounts_[i].serverUrl == old_account.serverUrl
            && accounts_[i].username == old_account.username) {
            accounts_.erase(accounts_.begin() + i);
            break;
        }
    }

    accounts_.insert(accounts_.begin(), new_account);

    QString old_url = old_account.serverUrl.toEncoded().data();
    QString new_url = new_account.serverUrl.toEncoded().data();

    qint64 timestamp = QDateTime::currentMSecsSinceEpoch();

    QString sql =
        "UPDATE Accounts "
        "SET url = %1, "
        "    username = %2, "
        "    token = %3, "
        "    lastVisited = %4 "
        "WHERE url = %5 "
        "  AND username = %2";

    sql = sql.arg(new_url).arg(new_account.username). \
        arg(new_account.token).arg(QString::number(timestamp)) \
        .arg(old_url);

    sqlite_query_exec (db, toCStr(sql));

    emit accountsChanged();

    return 0;
}
<commit_msg>fixed edit account sql<commit_after>#include <sqlite3.h>
#include <glib.h>
#include <errno.h>
#include <stdio.h>
#include <algorithm>

#include <QDateTime>

#include "account-mgr.h"
#include "configurator.h"
#include "seafile-applet.h"
#include "utils/utils.h"

AccountManager::AccountManager()
{
    db = NULL;
}

AccountManager::~AccountManager()
{
    if (db)
        sqlite3_close(db);
}

int AccountManager::start()
{
    const char *errmsg;
    const char *sql;

    QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("accounts.db");
    if (sqlite3_open (toCStr(db_path), &db)) {
        errmsg = sqlite3_errmsg (db);
        qDebug("failed to open account database %s: %s",
               toCStr(db_path), errmsg ? errmsg : "no error given");

        seafApplet->errorAndExit(tr("failed to open account database"));
        return -1;
    }

    sql = "CREATE TABLE IF NOT EXISTS Accounts (url VARCHAR(24), "
        "username VARCHAR(15), token VARCHAR(40), lastVisited INTEGER, "
        "PRIMARY KEY(url, username))";
    sqlite_query_exec (db, sql);

    loadAccounts();
    return 0;
}

bool AccountManager::loadAccountsCB(sqlite3_stmt *stmt, void *data)
{
    AccountManager *mgr = (AccountManager *)data;
    const char *url = (const char *)sqlite3_column_text (stmt, 0);
    const char *username = (const char *)sqlite3_column_text (stmt, 1);
    const char *token = (const char *)sqlite3_column_text (stmt, 2);
    qint64 atime = (qint64)sqlite3_column_int64 (stmt, 3);

    Account account = Account(QUrl(QString(url)), QString(username), QString(token), atime);
    mgr->accounts_.push_back(account);
    return true;
}

const std::vector<Account>& AccountManager::loadAccounts()
{
    const char *sql = "SELECT url, username, token, lastVisited FROM Accounts "
        "ORDER BY lastVisited DESC";
    accounts_.clear();
    sqlite_foreach_selected_row (db, sql, loadAccountsCB, this);
    return accounts_;
}

int AccountManager::saveAccount(const Account& account)
{
    int i = 0;
    for (i = 0; i < accounts_.size(); i++) {
        if (accounts_[i].serverUrl == account.serverUrl
            && accounts_[i].username == account.username) {
            accounts_.erase(accounts_.begin() + i);
            break;
        }
    }

    accounts_.insert(accounts_.begin(), account);

    QString url = account.serverUrl.toEncoded().data();
    qint64 timestamp = QDateTime::currentMSecsSinceEpoch();

    QString sql = "REPLACE INTO Accounts VALUES ('%1', '%2', '%3', %4) ";
    sql = sql.arg(url).arg(account.username).arg(account.token).arg(QString::number(timestamp));
    sqlite_query_exec (db, toCStr(sql));

    emit accountsChanged();

    return 0;
}

int AccountManager::removeAccount(const Account& account)
{
    QString url = account.serverUrl.toEncoded().data();

    QString sql = "DELETE FROM Accounts WHERE url = '%1' AND username = '%2'";
    sql = sql.arg(url).arg(account.username);
    sqlite_query_exec (db, toCStr(sql));

    accounts_.erase(std::remove(accounts_.begin(), accounts_.end(), account),
                    accounts_.end());

    emit accountsChanged();

    return 0;
}

void AccountManager::updateAccountLastVisited(const Account& account)
{
    const char *url = account.serverUrl.toEncoded().data();

    QString sql = "UPDATE Accounts SET lastVisited = %1 "
        "WHERE username = '%2' AND url = '%3'";

    qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
    sql = sql.arg(QString::number(timestamp)).arg(account.username).arg(url);
    sqlite_query_exec (db, toCStr(sql));
}

bool AccountManager::accountExists(const QUrl& url, const QString& username)
{
    int i, n = accounts_.size();
    for (i = 0; i < n; i++) {
        if (accounts_[i].serverUrl == url && accounts_[i].username == username) {
            return true;
        }
    }

    return false;
}

bool AccountManager::setCurrentAccount(const Account& account)
{
    if (account == currentAccount()) {
        return false;
    }

    // Would emit "accountsChanged" signal
    saveAccount(account);

    return true;
}

int AccountManager::replaceAccount(const Account& old_account, const Account& new_account)
{
    int i = 0;
    for (i = 0; i < accounts_.size(); i++) {
        if (accounts_[i].serverUrl == old_account.serverUrl
            && accounts_[i].username == old_account.username) {
            accounts_.erase(accounts_.begin() + i);
            break;
        }
    }

    accounts_.insert(accounts_.begin(), new_account);

    QString old_url = old_account.serverUrl.toEncoded().data();
    QString new_url = new_account.serverUrl.toEncoded().data();

    qint64 timestamp = QDateTime::currentMSecsSinceEpoch();

    QString sql =
        "UPDATE Accounts "
        "SET url = '%1', "
        "    username = '%2', "
        "    token = '%3', "
        "    lastVisited = '%4' "
        "WHERE url = '%5' "
        "  AND username = '%2'";

    sql = sql.arg(new_url).arg(new_account.username). \
        arg(new_account.token).arg(QString::number(timestamp)) \
        .arg(old_url);

    sqlite_query_exec (db, toCStr(sql));

    emit accountsChanged();

    return 0;
}
<|endoftext|>