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

#include "clientversion.h"
#include "rpcserver.h"
#include "init.h"
#include "main.h"
#include "noui.h"
#include "ui_interface.h"
#include "util.h"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Bitcoin (http://www.bitcoin.org/),
 * which enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

static bool fDaemon;

void DetectShutdownThread(boost::thread_group* threadGroup)
{
    bool fShutdown = ShutdownRequested();
    // Tell the main threads to shutdown.
    while (!fShutdown)
    {
        MilliSleep(200);
        fShutdown = ShutdownRequested();
    }
    if (threadGroup)
    {
        threadGroup->interrupt_all();
        threadGroup->join_all();
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
bool AppInit(int argc, char* argv[])
{
    boost::thread_group threadGroup;
    boost::thread* detectShutdownThread = NULL;

    bool fRet = false;

    //
    // Parameters
    //
    // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
    ParseParameters(argc, argv);

    // Process help and version before taking care about datadir
    if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version"))
    {
        std::string strUsage = _("Bitcoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n";

        if (mapArgs.count("-version"))
        {
            strUsage += LicenseInfo();
        }
        else
        {
            strUsage += "\n" + _("Usage:") + "\n" +
                  "  bitcoind [options]                     " + _("Start Bitcoin Core Daemon") + "\n";

            strUsage += "\n" + HelpMessage(HMM_BITCOIND);
        }

        fprintf(stdout, "%s", strUsage.c_str());
        return false;
    }

    try
    {
        if (!boost::filesystem::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
            return false;
        }
        try
        {
            ReadConfigFile(mapArgs, mapMultiArgs);
        } catch (const std::exception& e) {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            return false;
        }
        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
        if (!SelectParamsFromCommandLine()) {
            fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
            return false;
        }

        // Command-line RPC
        bool fCommandLine = false;
        for (int i = 1; i < argc; i++)
            if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "bitcoin:"))
                fCommandLine = true;

        if (fCommandLine)
        {
            fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n");
            exit(1);
        }
#ifndef WIN32
        fDaemon = GetBoolArg("-daemon", false);
        if (fDaemon)
        {
            fprintf(stdout, "Bitcoin server starting\n");

            // Daemonize
            pid_t pid = fork();
            if (pid < 0)
            {
                fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
                return false;
            }
            if (pid > 0) // Parent process, pid is child process id
            {
                return true;
            }
            // Child process falls through to rest of initialization

            pid_t sid = setsid();
            if (sid < 0)
                fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
        }
#endif
        SoftSetBoolArg("-server", true);

        detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup));
        fRet = AppInit2(threadGroup);
    }
    catch (const std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInit()");
    }

    if (!fRet)
    {
        if (detectShutdownThread)
            detectShutdownThread->interrupt();

        threadGroup.interrupt_all();
        // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
        // the startup-failure cases to make sure they don't result in a hang due to some
        // thread-blocking-waiting-for-another-thread-during-startup case
    }

    if (detectShutdownThread)
    {
        detectShutdownThread->join();
        delete detectShutdownThread;
        detectShutdownThread = NULL;
    }
    Shutdown();

    return fRet;
}

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

    // Connect bitcoind signal handlers
    noui_connect();

    return (AppInit(argc, argv) ? 0 : 1);
}
<commit_msg>Get rid of DetectShutdownThread<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2013 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "clientversion.h"
#include "rpcserver.h"
#include "init.h"
#include "main.h"
#include "noui.h"
#include "ui_interface.h"
#include "util.h"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Bitcoin (http://www.bitcoin.org/),
 * which enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

static bool fDaemon;

void WaitForShutdown(boost::thread_group* threadGroup)
{
    bool fShutdown = ShutdownRequested();
    // Tell the main threads to shutdown.
    while (!fShutdown)
    {
        MilliSleep(200);
        fShutdown = ShutdownRequested();
    }
    if (threadGroup)
    {
        threadGroup->interrupt_all();
        threadGroup->join_all();
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
bool AppInit(int argc, char* argv[])
{
    boost::thread_group threadGroup;

    bool fRet = false;

    //
    // Parameters
    //
    // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
    ParseParameters(argc, argv);

    // Process help and version before taking care about datadir
    if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version"))
    {
        std::string strUsage = _("Bitcoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n";

        if (mapArgs.count("-version"))
        {
            strUsage += LicenseInfo();
        }
        else
        {
            strUsage += "\n" + _("Usage:") + "\n" +
                  "  bitcoind [options]                     " + _("Start Bitcoin Core Daemon") + "\n";

            strUsage += "\n" + HelpMessage(HMM_BITCOIND);
        }

        fprintf(stdout, "%s", strUsage.c_str());
        return false;
    }

    try
    {
        if (!boost::filesystem::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
            return false;
        }
        try
        {
            ReadConfigFile(mapArgs, mapMultiArgs);
        } catch (const std::exception& e) {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            return false;
        }
        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
        if (!SelectParamsFromCommandLine()) {
            fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
            return false;
        }

        // Command-line RPC
        bool fCommandLine = false;
        for (int i = 1; i < argc; i++)
            if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "bitcoin:"))
                fCommandLine = true;

        if (fCommandLine)
        {
            fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n");
            exit(1);
        }
#ifndef WIN32
        fDaemon = GetBoolArg("-daemon", false);
        if (fDaemon)
        {
            fprintf(stdout, "Bitcoin server starting\n");

            // Daemonize
            pid_t pid = fork();
            if (pid < 0)
            {
                fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
                return false;
            }
            if (pid > 0) // Parent process, pid is child process id
            {
                return true;
            }
            // Child process falls through to rest of initialization

            pid_t sid = setsid();
            if (sid < 0)
                fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
        }
#endif
        SoftSetBoolArg("-server", true);

        fRet = AppInit2(threadGroup);
    }
    catch (const std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInit()");
    }

    if (!fRet)
    {
        threadGroup.interrupt_all();
        // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
        // the startup-failure cases to make sure they don't result in a hang due to some
        // thread-blocking-waiting-for-another-thread-during-startup case
    } else {
        WaitForShutdown(&threadGroup);
    }
    Shutdown();

    return fRet;
}

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

    // Connect bitcoind signal handlers
    noui_connect();

    return (AppInit(argc, argv) ? 0 : 1);
}
<|endoftext|>


<commit_before>#include "command.hh"
#include "hash.hh"
#include "legacy.hh"
#include "shared.hh"

using namespace nix;

struct CmdHash : Command
{
    enum Mode { mFile, mPath };
    Mode mode;
    bool base32 = false;
    bool truncate = false;
    HashType ht = htSHA512;
    Strings paths;

    CmdHash(Mode mode) : mode(mode)
    {
        mkFlag(0, "base32", "print hash in base-32", &base32);
        mkFlag(0, "base16", "print hash in base-16", &base32, false);
        mkHashTypeFlag("type", &ht);
        expectArgs("paths", &paths);
    }

    std::string name() override
    {
        return mode == mFile ? "hash-file" : "hash-path";
    }

    std::string description() override
    {
        return mode == mFile
            ? "print cryptographic hash of a regular file"
            : "print cryptographic hash of the NAR serialisation of a path";
    }

    void run() override
    {
        for (auto path : paths) {
            Hash h = mode == mFile ? hashFile(ht, path) : hashPath(ht, path).first;
            if (truncate && h.hashSize > 20) h = compressHash(h, 20);
            std::cout << format("%1%\n") %
                (base32 ? printHash32(h) : printHash(h));
        }
    }
};

static RegisterCommand r1(make_ref<Command, CmdHash>(CmdHash::mFile));
static RegisterCommand r2(make_ref<Command, CmdHash>(CmdHash::mPath));

struct CmdToBase : Command
{
    bool toBase32;
    HashType ht = htSHA512;
    Strings args;

    CmdToBase(bool toBase32) : toBase32(toBase32)
    {
        mkHashTypeFlag("type", &ht);
        expectArgs("strings", &args);
    }

    std::string name() override
    {
        return toBase32 ? "to-base32" : "to-base16";
    }

    std::string description() override
    {
        return toBase32
            ? "convert a hash to base-32 representation"
            : "convert a hash to base-32 representation";
    }

    void run() override
    {
        for (auto s : args) {
            Hash h = parseHash16or32(ht, s);
            std::cout << format("%1%\n") %
                (toBase32 ? printHash32(h) : printHash(h));
        }
    }
};

static RegisterCommand r3(make_ref<Command, CmdToBase>(false));
static RegisterCommand r4(make_ref<Command, CmdToBase>(true));

/* Legacy nix-hash command. */
static int compatNixHash(int argc, char * * argv)
{
    HashType ht = htMD5;
    bool flat = false;
    bool base32 = false;
    bool truncate = false;
    enum { opHash, opTo32, opTo16 } op = opHash;
    Strings ss;

    parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
        if (*arg == "--help")
            showManPage("nix-hash");
        else if (*arg == "--version")
            printVersion("nix-hash");
        else if (*arg == "--flat") flat = true;
        else if (*arg == "--base32") base32 = true;
        else if (*arg == "--truncate") truncate = true;
        else if (*arg == "--type") {
            string s = getArg(*arg, arg, end);
            ht = parseHashType(s);
            if (ht == htUnknown)
                throw UsageError(format("unknown hash type ‘%1%’") % s);
        }
        else if (*arg == "--to-base16") op = opTo16;
        else if (*arg == "--to-base32") op = opTo32;
        else if (*arg != "" && arg->at(0) == '-')
            return false;
        else
            ss.push_back(*arg);
        return true;
    });

    if (op == opHash) {
        CmdHash cmd(flat ? CmdHash::mFile : CmdHash::mPath);
        cmd.ht = ht;
        cmd.base32 = base32;
        cmd.truncate = truncate;
        cmd.paths = ss;
        cmd.run();
    }

    else {
        CmdToBase cmd(op == opTo32);
        cmd.args = ss;
        cmd.ht = ht;
        cmd.run();
    }

    return 0;
}

static RegisterLegacyCommand s1("nix-hash", compatNixHash);
<commit_msg>Fix to-base16 description<commit_after>#include "command.hh"
#include "hash.hh"
#include "legacy.hh"
#include "shared.hh"

using namespace nix;

struct CmdHash : Command
{
    enum Mode { mFile, mPath };
    Mode mode;
    bool base32 = false;
    bool truncate = false;
    HashType ht = htSHA512;
    Strings paths;

    CmdHash(Mode mode) : mode(mode)
    {
        mkFlag(0, "base32", "print hash in base-32", &base32);
        mkFlag(0, "base16", "print hash in base-16", &base32, false);
        mkHashTypeFlag("type", &ht);
        expectArgs("paths", &paths);
    }

    std::string name() override
    {
        return mode == mFile ? "hash-file" : "hash-path";
    }

    std::string description() override
    {
        return mode == mFile
            ? "print cryptographic hash of a regular file"
            : "print cryptographic hash of the NAR serialisation of a path";
    }

    void run() override
    {
        for (auto path : paths) {
            Hash h = mode == mFile ? hashFile(ht, path) : hashPath(ht, path).first;
            if (truncate && h.hashSize > 20) h = compressHash(h, 20);
            std::cout << format("%1%\n") %
                (base32 ? printHash32(h) : printHash(h));
        }
    }
};

static RegisterCommand r1(make_ref<Command, CmdHash>(CmdHash::mFile));
static RegisterCommand r2(make_ref<Command, CmdHash>(CmdHash::mPath));

struct CmdToBase : Command
{
    bool toBase32;
    HashType ht = htSHA512;
    Strings args;

    CmdToBase(bool toBase32) : toBase32(toBase32)
    {
        mkHashTypeFlag("type", &ht);
        expectArgs("strings", &args);
    }

    std::string name() override
    {
        return toBase32 ? "to-base32" : "to-base16";
    }

    std::string description() override
    {
        return toBase32
            ? "convert a hash to base-32 representation"
            : "convert a hash to base-16 representation";
    }

    void run() override
    {
        for (auto s : args) {
            Hash h = parseHash16or32(ht, s);
            std::cout << format("%1%\n") %
                (toBase32 ? printHash32(h) : printHash(h));
        }
    }
};

static RegisterCommand r3(make_ref<Command, CmdToBase>(false));
static RegisterCommand r4(make_ref<Command, CmdToBase>(true));

/* Legacy nix-hash command. */
static int compatNixHash(int argc, char * * argv)
{
    HashType ht = htMD5;
    bool flat = false;
    bool base32 = false;
    bool truncate = false;
    enum { opHash, opTo32, opTo16 } op = opHash;
    Strings ss;

    parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
        if (*arg == "--help")
            showManPage("nix-hash");
        else if (*arg == "--version")
            printVersion("nix-hash");
        else if (*arg == "--flat") flat = true;
        else if (*arg == "--base32") base32 = true;
        else if (*arg == "--truncate") truncate = true;
        else if (*arg == "--type") {
            string s = getArg(*arg, arg, end);
            ht = parseHashType(s);
            if (ht == htUnknown)
                throw UsageError(format("unknown hash type ‘%1%’") % s);
        }
        else if (*arg == "--to-base16") op = opTo16;
        else if (*arg == "--to-base32") op = opTo32;
        else if (*arg != "" && arg->at(0) == '-')
            return false;
        else
            ss.push_back(*arg);
        return true;
    });

    if (op == opHash) {
        CmdHash cmd(flat ? CmdHash::mFile : CmdHash::mPath);
        cmd.ht = ht;
        cmd.base32 = base32;
        cmd.truncate = truncate;
        cmd.paths = ss;
        cmd.run();
    }

    else {
        CmdToBase cmd(op == opTo32);
        cmd.args = ss;
        cmd.ht = ht;
        cmd.run();
    }

    return 0;
}

static RegisterLegacyCommand s1("nix-hash", compatNixHash);
<|endoftext|>


<commit_before>#include <algorithm>

#include "command.hh"
#include "common-args.hh"
#include "eval.hh"
#include "globals.hh"
#include "legacy.hh"
#include "shared.hh"
#include "store-api.hh"
#include "filetransfer.hh"
#include "finally.hh"
#include "loggers.hh"
#include "markdown.hh"

#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <netinet/in.h>

#include <nlohmann/json.hpp>

extern std::string chrootHelperName;

void chrootHelper(int argc, char * * argv);

namespace nix {

/* Check if we have a non-loopback/link-local network interface. */
static bool haveInternet()
{
    struct ifaddrs * addrs;

    if (getifaddrs(&addrs))
        return true;

    Finally free([&]() { freeifaddrs(addrs); });

    for (auto i = addrs; i; i = i->ifa_next) {
        if (!i->ifa_addr) continue;
        if (i->ifa_addr->sa_family == AF_INET) {
            if (ntohl(((sockaddr_in *) i->ifa_addr)->sin_addr.s_addr) != INADDR_LOOPBACK) {
                return true;
            }
        } else if (i->ifa_addr->sa_family == AF_INET6) {
            if (!IN6_IS_ADDR_LOOPBACK(&((sockaddr_in6 *) i->ifa_addr)->sin6_addr) &&
                !IN6_IS_ADDR_LINKLOCAL(&((sockaddr_in6 *) i->ifa_addr)->sin6_addr))
                return true;
        }
    }

    return false;
}

std::string programPath;
char * * savedArgv;

struct HelpRequested { };

struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
{
    bool printBuildLogs = false;
    bool useNet = true;
    bool refresh = false;
    bool showVersion = false;

    NixArgs() : MultiCommand(RegisterCommand::getCommandsFor({})), MixCommonArgs("nix")
    {
        categories.clear();
        categories[Command::catDefault] = "Main commands";
        categories[catSecondary] = "Infrequently used commands";
        categories[catUtility] = "Utility/scripting commands";
        categories[catNixInstallation] = "Commands for upgrading or troubleshooting your Nix installation";

        addFlag({
            .longName = "help",
            .description = "Show usage information.",
            .handler = {[&]() { throw HelpRequested(); }},
        });

        addFlag({
            .longName = "print-build-logs",
            .shortName = 'L',
            .description = "Print full build logs on standard error.",
            .category = loggingCategory,
            .handler = {[&]() {setLogFormat(LogFormat::barWithLogs); }},
        });

        addFlag({
            .longName = "version",
            .description = "Show version information.",
            .handler = {[&]() { showVersion = true; }},
        });

        addFlag({
            .longName = "offline",
            .aliases = {"no-net"}, // FIXME: remove
            .description = "Disable substituters and consider all previously downloaded files up-to-date.",
            .handler = {[&]() { useNet = false; }},
        });

        addFlag({
            .longName = "refresh",
            .description = "Consider all previously downloaded files out-of-date.",
            .handler = {[&]() { refresh = true; }},
        });
    }

    std::map<std::string, std::vector<std::string>> aliases = {
        {"add-to-store", {"store", "add-path"}},
        {"cat-nar", {"nar", "cat"}},
        {"cat-store", {"store", "cat"}},
        {"copy-sigs", {"store", "copy-sigs"}},
        {"dev-shell", {"develop"}},
        {"diff-closures", {"store", "diff-closures"}},
        {"dump-path", {"store", "dump-path"}},
        {"hash-file", {"hash", "file"}},
        {"hash-path", {"hash", "path"}},
        {"ls-nar", {"nar", "ls"}},
        {"ls-store", {"store", "ls"}},
        {"make-content-addressable", {"store", "make-content-addressable"}},
        {"optimise-store", {"store", "optimise"}},
        {"ping-store", {"store", "ping"}},
        {"sign-paths", {"store", "sign"}},
        {"to-base16", {"hash", "to-base16"}},
        {"to-base32", {"hash", "to-base32"}},
        {"to-base64", {"hash", "to-base64"}},
        {"verify", {"store", "verify"}},
    };

    bool aliasUsed = false;

    Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos) override
    {
        if (aliasUsed || command || pos == args.end()) return pos;
        auto arg = *pos;
        auto i = aliases.find(arg);
        if (i == aliases.end()) return pos;
        warn("'%s' is a deprecated alias for '%s'",
            arg, concatStringsSep(" ", i->second));
        pos = args.erase(pos);
        for (auto j = i->second.rbegin(); j != i->second.rend(); ++j)
            pos = args.insert(pos, *j);
        aliasUsed = true;
        return pos;
    }

    std::string description() override
    {
        return "a tool for reproducible and declarative configuration management";
    }

    std::string doc() override
    {
        return
          #include "nix.md"
          ;
    }

    // Plugins may add new subcommands.
    void pluginsInited() override
    {
        commands = RegisterCommand::getCommandsFor({});
    }
};

/* Render the help for the specified subcommand to stdout using
   lowdown. */
static void showHelp(std::vector<std::string> subcommand, MultiCommand & toplevel)
{
    auto mdName = subcommand.empty() ? "nix" : fmt("nix3-%s", concatStringsSep("-", subcommand));

    evalSettings.restrictEval = false;
    evalSettings.pureEval = false;
    EvalState state({}, openStore("dummy://"));

    auto vGenerateManpage = state.allocValue();
    state.eval(state.parseExprFromString(
        #include "generate-manpage.nix.gen.hh"
        , "/"), *vGenerateManpage);

    auto vUtils = state.allocValue();
    state.cacheFile(
        "/utils.nix", "/utils.nix",
        state.parseExprFromString(
            #include "utils.nix.gen.hh"
            , "/"),
        *vUtils);

    auto attrs = state.buildBindings(16);
    attrs.alloc("command").mkString(toplevel.toJSON().dump());

    auto vRes = state.allocValue();
    state.callFunction(*vGenerateManpage, state.allocValue()->mkAttrs(attrs), *vRes, noPos);

    auto attr = vRes->attrs->get(state.symbols.create(mdName + ".md"));
    if (!attr)
        throw UsageError("Nix has no subcommand '%s'", concatStringsSep("", subcommand));

    auto markdown = state.forceString(*attr->value);

    RunPager pager;
    std::cout << renderMarkdownToTerminal(markdown) << "\n";
}

struct CmdHelp : Command
{
    std::vector<std::string> subcommand;

    CmdHelp()
    {
        expectArgs({
            .label = "subcommand",
            .handler = {&subcommand},
        });
    }

    std::string description() override
    {
        return "show help about `nix` or a particular subcommand";
    }

    std::string doc() override
    {
        return
          #include "help.md"
          ;
    }

    void run() override
    {
        assert(parent);
        MultiCommand * toplevel = parent;
        while (toplevel->parent) toplevel = toplevel->parent;
        showHelp(subcommand, *toplevel);
    }
};

static auto rCmdHelp = registerCommand<CmdHelp>("help");

void mainWrapped(int argc, char * * argv)
{
    savedArgv = argv;

    /* The chroot helper needs to be run before any threads have been
       started. */
    if (argc > 0 && argv[0] == chrootHelperName) {
        chrootHelper(argc, argv);
        return;
    }

    initNix();
    initGC();

    #if __linux__
    if (getuid() == 0) {
        try {
            saveMountNamespace();
            if (unshare(CLONE_NEWNS) == -1)
                throw SysError("setting up a private mount namespace");
        } catch (Error & e) { }
    }
    #endif

    programPath = argv[0];
    auto programName = std::string(baseNameOf(programPath));

    {
        auto legacy = (*RegisterLegacyCommand::commands)[programName];
        if (legacy) return legacy(argc, argv);
    }

    evalSettings.pureEval = true;

    setLogFormat("bar");
    settings.verboseBuild = false;
    if (isatty(STDERR_FILENO)) {
        verbosity = lvlNotice;
    } else {
        verbosity = lvlInfo;
    }

    Finally f([] { logger->stop(); });

    NixArgs args;

    if (argc == 2 && std::string(argv[1]) == "__dump-args") {
        std::cout << args.toJSON().dump() << "\n";
        return;
    }

    if (argc == 2 && std::string(argv[1]) == "__dump-builtins") {
        evalSettings.pureEval = false;
        EvalState state({}, openStore("dummy://"));
        auto res = nlohmann::json::object();
        auto builtins = state.baseEnv.values[0]->attrs;
        for (auto & builtin : *builtins) {
            auto b = nlohmann::json::object();
            if (!builtin.value->isPrimOp()) continue;
            auto primOp = builtin.value->primOp;
            if (!primOp->doc) continue;
            b["arity"] = primOp->arity;
            b["args"] = primOp->args;
            b["doc"] = trim(stripIndentation(primOp->doc));
            res[(std::string) builtin.name] = std::move(b);
        }
        std::cout << res.dump() << "\n";
        return;
    }

    Finally printCompletions([&]()
    {
        if (completions) {
            switch (completionType) {
            case ctNormal:
                std::cout << "normal\n"; break;
            case ctFilenames:
                std::cout << "filenames\n"; break;
            case ctAttrs:
                std::cout << "attrs\n"; break;
            }
            for (auto & s : *completions)
                std::cout << s.completion << "\t" << s.description << "\n";
        }
    });

    try {
        args.parseCmdline(argvToStrings(argc, argv));
    } catch (HelpRequested &) {
        std::vector<std::string> subcommand;
        MultiCommand * command = &args;
        while (command) {
            if (command && command->command) {
                subcommand.push_back(command->command->first);
                command = dynamic_cast<MultiCommand *>(&*command->command->second);
            } else
                break;
        }
        showHelp(subcommand, args);
        return;
    } catch (UsageError &) {
        if (!completions) throw;
    }

    if (completions) return;

    if (args.showVersion) {
        printVersion(programName);
        return;
    }

    if (!args.command)
        throw UsageError("no subcommand specified");

    if (args.command->first != "repl"
        && args.command->first != "doctor"
        && args.command->first != "upgrade-nix")
        settings.requireExperimentalFeature(Xp::NixCommand);

    if (args.useNet && !haveInternet()) {
        warn("you don't have Internet access; disabling some network-dependent features");
        args.useNet = false;
    }

    if (!args.useNet) {
        // FIXME: should check for command line overrides only.
        if (!settings.useSubstitutes.overridden)
            settings.useSubstitutes = false;
        if (!settings.tarballTtl.overridden)
            settings.tarballTtl = std::numeric_limits<unsigned int>::max();
        if (!fileTransferSettings.tries.overridden)
            fileTransferSettings.tries = 0;
        if (!fileTransferSettings.connectTimeout.overridden)
            fileTransferSettings.connectTimeout = 1;
    }

    if (args.refresh) {
        settings.tarballTtl = 0;
        settings.ttlNegativeNarInfoCache = 0;
        settings.ttlPositiveNarInfoCache = 0;
    }

    args.command->second->prepare();
    args.command->second->run();
}

}

int main(int argc, char * * argv)
{
    // Increase the default stack size for the evaluator and for
    // libstdc++'s std::regex.
    nix::setStackSize(64 * 1024 * 1024);

    return nix::handleExceptions(argv[0], [&]() {
        nix::mainWrapped(argc, argv);
    });
}
<commit_msg>Remove dead field in NixArgs<commit_after>#include <algorithm>

#include "command.hh"
#include "common-args.hh"
#include "eval.hh"
#include "globals.hh"
#include "legacy.hh"
#include "shared.hh"
#include "store-api.hh"
#include "filetransfer.hh"
#include "finally.hh"
#include "loggers.hh"
#include "markdown.hh"

#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <netinet/in.h>

#include <nlohmann/json.hpp>

extern std::string chrootHelperName;

void chrootHelper(int argc, char * * argv);

namespace nix {

/* Check if we have a non-loopback/link-local network interface. */
static bool haveInternet()
{
    struct ifaddrs * addrs;

    if (getifaddrs(&addrs))
        return true;

    Finally free([&]() { freeifaddrs(addrs); });

    for (auto i = addrs; i; i = i->ifa_next) {
        if (!i->ifa_addr) continue;
        if (i->ifa_addr->sa_family == AF_INET) {
            if (ntohl(((sockaddr_in *) i->ifa_addr)->sin_addr.s_addr) != INADDR_LOOPBACK) {
                return true;
            }
        } else if (i->ifa_addr->sa_family == AF_INET6) {
            if (!IN6_IS_ADDR_LOOPBACK(&((sockaddr_in6 *) i->ifa_addr)->sin6_addr) &&
                !IN6_IS_ADDR_LINKLOCAL(&((sockaddr_in6 *) i->ifa_addr)->sin6_addr))
                return true;
        }
    }

    return false;
}

std::string programPath;
char * * savedArgv;

struct HelpRequested { };

struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
{
    bool useNet = true;
    bool refresh = false;
    bool showVersion = false;

    NixArgs() : MultiCommand(RegisterCommand::getCommandsFor({})), MixCommonArgs("nix")
    {
        categories.clear();
        categories[Command::catDefault] = "Main commands";
        categories[catSecondary] = "Infrequently used commands";
        categories[catUtility] = "Utility/scripting commands";
        categories[catNixInstallation] = "Commands for upgrading or troubleshooting your Nix installation";

        addFlag({
            .longName = "help",
            .description = "Show usage information.",
            .handler = {[&]() { throw HelpRequested(); }},
        });

        addFlag({
            .longName = "print-build-logs",
            .shortName = 'L',
            .description = "Print full build logs on standard error.",
            .category = loggingCategory,
            .handler = {[&]() {setLogFormat(LogFormat::barWithLogs); }},
        });

        addFlag({
            .longName = "version",
            .description = "Show version information.",
            .handler = {[&]() { showVersion = true; }},
        });

        addFlag({
            .longName = "offline",
            .aliases = {"no-net"}, // FIXME: remove
            .description = "Disable substituters and consider all previously downloaded files up-to-date.",
            .handler = {[&]() { useNet = false; }},
        });

        addFlag({
            .longName = "refresh",
            .description = "Consider all previously downloaded files out-of-date.",
            .handler = {[&]() { refresh = true; }},
        });
    }

    std::map<std::string, std::vector<std::string>> aliases = {
        {"add-to-store", {"store", "add-path"}},
        {"cat-nar", {"nar", "cat"}},
        {"cat-store", {"store", "cat"}},
        {"copy-sigs", {"store", "copy-sigs"}},
        {"dev-shell", {"develop"}},
        {"diff-closures", {"store", "diff-closures"}},
        {"dump-path", {"store", "dump-path"}},
        {"hash-file", {"hash", "file"}},
        {"hash-path", {"hash", "path"}},
        {"ls-nar", {"nar", "ls"}},
        {"ls-store", {"store", "ls"}},
        {"make-content-addressable", {"store", "make-content-addressable"}},
        {"optimise-store", {"store", "optimise"}},
        {"ping-store", {"store", "ping"}},
        {"sign-paths", {"store", "sign"}},
        {"to-base16", {"hash", "to-base16"}},
        {"to-base32", {"hash", "to-base32"}},
        {"to-base64", {"hash", "to-base64"}},
        {"verify", {"store", "verify"}},
    };

    bool aliasUsed = false;

    Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos) override
    {
        if (aliasUsed || command || pos == args.end()) return pos;
        auto arg = *pos;
        auto i = aliases.find(arg);
        if (i == aliases.end()) return pos;
        warn("'%s' is a deprecated alias for '%s'",
            arg, concatStringsSep(" ", i->second));
        pos = args.erase(pos);
        for (auto j = i->second.rbegin(); j != i->second.rend(); ++j)
            pos = args.insert(pos, *j);
        aliasUsed = true;
        return pos;
    }

    std::string description() override
    {
        return "a tool for reproducible and declarative configuration management";
    }

    std::string doc() override
    {
        return
          #include "nix.md"
          ;
    }

    // Plugins may add new subcommands.
    void pluginsInited() override
    {
        commands = RegisterCommand::getCommandsFor({});
    }
};

/* Render the help for the specified subcommand to stdout using
   lowdown. */
static void showHelp(std::vector<std::string> subcommand, MultiCommand & toplevel)
{
    auto mdName = subcommand.empty() ? "nix" : fmt("nix3-%s", concatStringsSep("-", subcommand));

    evalSettings.restrictEval = false;
    evalSettings.pureEval = false;
    EvalState state({}, openStore("dummy://"));

    auto vGenerateManpage = state.allocValue();
    state.eval(state.parseExprFromString(
        #include "generate-manpage.nix.gen.hh"
        , "/"), *vGenerateManpage);

    auto vUtils = state.allocValue();
    state.cacheFile(
        "/utils.nix", "/utils.nix",
        state.parseExprFromString(
            #include "utils.nix.gen.hh"
            , "/"),
        *vUtils);

    auto attrs = state.buildBindings(16);
    attrs.alloc("command").mkString(toplevel.toJSON().dump());

    auto vRes = state.allocValue();
    state.callFunction(*vGenerateManpage, state.allocValue()->mkAttrs(attrs), *vRes, noPos);

    auto attr = vRes->attrs->get(state.symbols.create(mdName + ".md"));
    if (!attr)
        throw UsageError("Nix has no subcommand '%s'", concatStringsSep("", subcommand));

    auto markdown = state.forceString(*attr->value);

    RunPager pager;
    std::cout << renderMarkdownToTerminal(markdown) << "\n";
}

struct CmdHelp : Command
{
    std::vector<std::string> subcommand;

    CmdHelp()
    {
        expectArgs({
            .label = "subcommand",
            .handler = {&subcommand},
        });
    }

    std::string description() override
    {
        return "show help about `nix` or a particular subcommand";
    }

    std::string doc() override
    {
        return
          #include "help.md"
          ;
    }

    void run() override
    {
        assert(parent);
        MultiCommand * toplevel = parent;
        while (toplevel->parent) toplevel = toplevel->parent;
        showHelp(subcommand, *toplevel);
    }
};

static auto rCmdHelp = registerCommand<CmdHelp>("help");

void mainWrapped(int argc, char * * argv)
{
    savedArgv = argv;

    /* The chroot helper needs to be run before any threads have been
       started. */
    if (argc > 0 && argv[0] == chrootHelperName) {
        chrootHelper(argc, argv);
        return;
    }

    initNix();
    initGC();

    #if __linux__
    if (getuid() == 0) {
        try {
            saveMountNamespace();
            if (unshare(CLONE_NEWNS) == -1)
                throw SysError("setting up a private mount namespace");
        } catch (Error & e) { }
    }
    #endif

    programPath = argv[0];
    auto programName = std::string(baseNameOf(programPath));

    {
        auto legacy = (*RegisterLegacyCommand::commands)[programName];
        if (legacy) return legacy(argc, argv);
    }

    evalSettings.pureEval = true;

    setLogFormat("bar");
    settings.verboseBuild = false;
    if (isatty(STDERR_FILENO)) {
        verbosity = lvlNotice;
    } else {
        verbosity = lvlInfo;
    }

    Finally f([] { logger->stop(); });

    NixArgs args;

    if (argc == 2 && std::string(argv[1]) == "__dump-args") {
        std::cout << args.toJSON().dump() << "\n";
        return;
    }

    if (argc == 2 && std::string(argv[1]) == "__dump-builtins") {
        evalSettings.pureEval = false;
        EvalState state({}, openStore("dummy://"));
        auto res = nlohmann::json::object();
        auto builtins = state.baseEnv.values[0]->attrs;
        for (auto & builtin : *builtins) {
            auto b = nlohmann::json::object();
            if (!builtin.value->isPrimOp()) continue;
            auto primOp = builtin.value->primOp;
            if (!primOp->doc) continue;
            b["arity"] = primOp->arity;
            b["args"] = primOp->args;
            b["doc"] = trim(stripIndentation(primOp->doc));
            res[(std::string) builtin.name] = std::move(b);
        }
        std::cout << res.dump() << "\n";
        return;
    }

    Finally printCompletions([&]()
    {
        if (completions) {
            switch (completionType) {
            case ctNormal:
                std::cout << "normal\n"; break;
            case ctFilenames:
                std::cout << "filenames\n"; break;
            case ctAttrs:
                std::cout << "attrs\n"; break;
            }
            for (auto & s : *completions)
                std::cout << s.completion << "\t" << s.description << "\n";
        }
    });

    try {
        args.parseCmdline(argvToStrings(argc, argv));
    } catch (HelpRequested &) {
        std::vector<std::string> subcommand;
        MultiCommand * command = &args;
        while (command) {
            if (command && command->command) {
                subcommand.push_back(command->command->first);
                command = dynamic_cast<MultiCommand *>(&*command->command->second);
            } else
                break;
        }
        showHelp(subcommand, args);
        return;
    } catch (UsageError &) {
        if (!completions) throw;
    }

    if (completions) return;

    if (args.showVersion) {
        printVersion(programName);
        return;
    }

    if (!args.command)
        throw UsageError("no subcommand specified");

    if (args.command->first != "repl"
        && args.command->first != "doctor"
        && args.command->first != "upgrade-nix")
        settings.requireExperimentalFeature(Xp::NixCommand);

    if (args.useNet && !haveInternet()) {
        warn("you don't have Internet access; disabling some network-dependent features");
        args.useNet = false;
    }

    if (!args.useNet) {
        // FIXME: should check for command line overrides only.
        if (!settings.useSubstitutes.overridden)
            settings.useSubstitutes = false;
        if (!settings.tarballTtl.overridden)
            settings.tarballTtl = std::numeric_limits<unsigned int>::max();
        if (!fileTransferSettings.tries.overridden)
            fileTransferSettings.tries = 0;
        if (!fileTransferSettings.connectTimeout.overridden)
            fileTransferSettings.connectTimeout = 1;
    }

    if (args.refresh) {
        settings.tarballTtl = 0;
        settings.ttlNegativeNarInfoCache = 0;
        settings.ttlPositiveNarInfoCache = 0;
    }

    args.command->second->prepare();
    args.command->second->run();
}

}

int main(int argc, char * * argv)
{
    // Increase the default stack size for the evaluator and for
    // libstdc++'s std::regex.
    nix::setStackSize(64 * 1024 * 1024);

    return nix::handleExceptions(argv[0], [&]() {
        nix::mainWrapped(argc, argv);
    });
}
<|endoftext|>


<commit_before>#include "main.h"

// blabla

/// Filename of input file.
char* filename = NULL;

int yyerror(const char* msg)
{
  // display passed error message
  fprintf(stderr, "Error in '%s' in line %d:\n", filename, yylineno);
  fprintf(stderr, "  token/text last read was '%s'\n\n", yytext);

  // close input file
  fclose(yyin);

  fprintf(stderr, "-------------------------------------------------------------------------------\n");

  int firstShowedLine = ((yylineno-3)>0)?(yylineno-3):1;

  std::ifstream inputFile(filename);
  std::string errorLine;
  for (int i=0; i<firstShowedLine; i++)
    getline(inputFile, errorLine);

  // print the erroneous line (plus/minus three more)
  for (int i=firstShowedLine; i<=firstShowedLine+6; i++)
  {
    fprintf(stderr, "%d: %s\n", i, errorLine.c_str());
    getline(inputFile, errorLine);
    if (inputFile.eof())
      break;
  }

  fprintf(stderr, "-------------------------------------------------------------------------------\n");

  inputFile.close();

  exit(1);
}

int main( int argc, char *argv[])
{
  if (argc != 2)
    exit(2);

  // don't show debug messages from flex and Bison
  yydebug = 0;
  yy_flex_debug = 0;

  filename = argv[1];

  if (!(yyin = fopen(filename, "r")))
  {
    fprintf(stderr, "  File '%s' not found.\n", filename);
    exit(2);
  }

  fprintf(stderr, "Parsing '%s'...\n", filename);

  // invoke Bison parser
  int error = yyparse();

  if (!error)
    fprintf(stderr, "Parsing complete.\n");

  return error;
}
<commit_msg>+ removed stupid comment<commit_after>#include "main.h"

/// Filename of input file.
char* filename = NULL;

int yyerror(const char* msg)
{
  // display passed error message
  fprintf(stderr, "Error in '%s' in line %d:\n", filename, yylineno);
  fprintf(stderr, "  token/text last read was '%s'\n\n", yytext);

  // close input file
  fclose(yyin);

  fprintf(stderr, "-------------------------------------------------------------------------------\n");

  int firstShowedLine = ((yylineno-3)>0)?(yylineno-3):1;

  std::ifstream inputFile(filename);
  std::string errorLine;
  for (int i=0; i<firstShowedLine; i++)
    getline(inputFile, errorLine);

  // print the erroneous line (plus/minus three more)
  for (int i=firstShowedLine; i<=firstShowedLine+6; i++)
  {
    fprintf(stderr, "%d: %s\n", i, errorLine.c_str());
    getline(inputFile, errorLine);
    if (inputFile.eof())
      break;
  }

  fprintf(stderr, "-------------------------------------------------------------------------------\n");

  inputFile.close();

  exit(1);
}

int main( int argc, char *argv[])
{
  if (argc != 2)
    exit(2);

  // don't show debug messages from flex and Bison
  yydebug = 0;
  yy_flex_debug = 0;

  filename = argv[1];

  if (!(yyin = fopen(filename, "r")))
  {
    fprintf(stderr, "  File '%s' not found.\n", filename);
    exit(2);
  }

  fprintf(stderr, "Parsing '%s'...\n", filename);

  // invoke Bison parser
  int error = yyparse();

  if (!error)
    fprintf(stderr, "Parsing complete.\n");

  return error;
}
<|endoftext|>


<commit_before>#include "notebook.h"
#include "logging.h"
#include "sourcefile.h"
#include "singletons.h"
#include <fstream>
#include <regex>
#include "cmake.h"

#include <iostream> //TODO: remove
using namespace std; //TODO: remove

namespace sigc {
  SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
}

Notebook::Notebook(Directories &directories) : Gtk::Notebook(), directories(directories) {
  Gsv::init();
}

int Notebook::size() {
  return get_n_pages();
}

Source::View* Notebook::get_view(int page) {
  if(page>=size())
    return nullptr;
  return source_views.at(page);
}

Source::View* Notebook::get_current_view() {
  INFO("Getting sourceview");
  if(get_current_page()==-1)
    return nullptr;
  return get_view(get_current_page());
}

void Notebook::open(std::string path) {
  INFO("Notebook open file");
  INFO("Notebook create page");
  for(int c=0;c<size();c++) {
    if(path==get_view(c)->file_path) {
      set_current_page(c);
      get_current_view()->grab_focus();
      return;
    }
  }

  std::ifstream can_read(path);
  if(!can_read) {
    Singleton::terminal()->print("Error: could not open "+path+"\n");
    return;
  }
  can_read.close();

  auto language=Source::guess_language(path);
  if(language && (language->get_id()=="chdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) {
    std::string project_path;
    if(directories.cmake && directories.cmake->project_path!="")
      project_path=directories.cmake->project_path.string();
    else {
      auto parent_path=boost::filesystem::path(path).parent_path();
      project_path=parent_path.string();
      CMake cmake(parent_path);
      if(cmake.project_path!="") {
        project_path=cmake.project_path.string();
        Singleton::terminal()->print("Project path for "+path+" set to "+project_path+"\n");
      }
      else
        Singleton::terminal()->print("Error: could not find project path for "+path+"\n");
    }
    source_views.emplace_back(new Source::ClangView(path, project_path));
  }
  else
    source_views.emplace_back(new Source::GenericView(path, language));

  scrolled_windows.emplace_back(new Gtk::ScrolledWindow());
  hboxes.emplace_back(new Gtk::HBox());
  scrolled_windows.back()->add(*source_views.back());
  hboxes.back()->pack_start(*scrolled_windows.back(), true, true);

  boost::filesystem::path file_path(source_views.back()->file_path);
  std::string title=file_path.filename().string();
  append_page(*hboxes.back(), title);
  show_all_children();
  set_current_page(size()-1);
  set_focus_child(*source_views.back());
  get_current_view()->get_buffer()->set_modified(false);
  get_current_view()->grab_focus();
  //Add star on tab label when the page is not saved:
  auto source_view=get_current_view();
  get_current_view()->get_buffer()->signal_modified_changed().connect([this, source_view]() {
    boost::filesystem::path file_path(source_view->file_path);
    std::string title=file_path.filename().string();
    if(source_view->get_buffer()->get_modified())
      title+="*";
    int page=-1;
    for(int c=0;c<size();c++) {
      if(get_view(c)==source_view) {
        page=c;
        break;
      }
    }
    if(page!=-1)
      set_tab_label_text(*(get_nth_page(page)), title);
  });

  get_current_view()->on_update_status=[this](Source::View* view, const std::string &status) {
    if(get_current_view()==view)
      Singleton::status()->set_text(status);
  };
}

bool Notebook::save(int page) {
  if(page>=size())
    return false;
  auto view=get_view(page);
  if (view->file_path != "" && view->get_buffer()->get_modified()) {
    if(juci::filesystem::write(view->file_path, view->get_buffer())) {
      view->get_buffer()->set_modified(false);
      Singleton::terminal()->print("File saved to: " +view->file_path+"\n");

      //If CMakeLists.txt have been modified:
      if(boost::filesystem::path(view->file_path).filename().string()=="CMakeLists.txt") {
        if(directories.cmake && directories.cmake->project_path!="" && CMake::create_compile_commands(directories.cmake->project_path.string())) {
          directories.open_folder();
          for(auto source_view: source_views) {
            if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view)) {
              if(directories.cmake->project_path.string()==source_clang_view->project_path) {
                if(source_clang_view->restart_parse())
                  Singleton::terminal()->print("Reparsing "+source_clang_view->file_path+"\n");
                else
                  Singleton::terminal()->print("Already reparsing "+source_clang_view->file_path+". Please reopen the file manually.\n");
              }
            }
          }
        }
      }

      return true;
    }
    Singleton::terminal()->print("Error: could not save file " +view->file_path+"\n");
  }
  return false;
}

bool Notebook::save_current() {
  INFO("Notebook save current file");
  if(get_current_page()==-1)
    return false;
  return save(get_current_page());
}

bool Notebook::close_current_page() {
  INFO("Notebook close page");
  if (size() != 0) {
    if(get_current_view()->get_buffer()->get_modified()){
      if(!save_modified_dialog())
        return false;
    }
    int page = get_current_page();
    remove_page(page);
    if(get_current_page()==-1)
      Singleton::status()->set_text("");
    auto source_view=source_views.at(page);
    source_views.erase(source_views.begin()+ page);
    scrolled_windows.erase(scrolled_windows.begin()+page);
    hboxes.erase(hboxes.begin()+page);
    if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view))
      source_clang_view->async_delete();
    else
      delete source_view;
  }
  return true;
}

bool Notebook::save_modified_dialog() {
  INFO("Notebook::save_modified_dialog");
  Gtk::MessageDialog dialog((Gtk::Window&)(*get_toplevel()), "Save file!", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
  dialog.set_secondary_text("Do you want to save: " + get_current_view()->file_path+" ?");
  int result = dialog.run();
  if(result==Gtk::RESPONSE_YES) {
    save_current();
    return true;
  }
  else if(result==Gtk::RESPONSE_NO) {
    return true;
  }
  else {
    return false;
  }
}

<commit_msg>Minor fix.<commit_after>#include "notebook.h"
#include "logging.h"
#include "sourcefile.h"
#include "singletons.h"
#include <fstream>
#include <regex>
#include "cmake.h"

#include <iostream> //TODO: remove
using namespace std; //TODO: remove

namespace sigc {
  SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
}

Notebook::Notebook(Directories &directories) : Gtk::Notebook(), directories(directories) {
  Gsv::init();
}

int Notebook::size() {
  return get_n_pages();
}

Source::View* Notebook::get_view(int page) {
  if(page>=size())
    return nullptr;
  return source_views.at(page);
}

Source::View* Notebook::get_current_view() {
  INFO("Getting sourceview");
  if(get_current_page()==-1)
    return nullptr;
  return get_view(get_current_page());
}

void Notebook::open(std::string path) {
  INFO("Notebook open file");
  INFO("Notebook create page");
  for(int c=0;c<size();c++) {
    if(path==get_view(c)->file_path) {
      set_current_page(c);
      get_current_view()->grab_focus();
      return;
    }
  }

  std::ifstream can_read(path);
  if(!can_read) {
    Singleton::terminal()->print("Error: could not open "+path+"\n");
    return;
  }
  can_read.close();

  auto language=Source::guess_language(path);
  if(language && (language->get_id()=="chdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) {
    std::string project_path;
    if(directories.cmake && directories.cmake->project_path!="")
      project_path=directories.cmake->project_path.string();
    else {
      auto parent_path=boost::filesystem::path(path).parent_path();
      project_path=parent_path.string();
      CMake cmake(parent_path);
      if(cmake.project_path!="") {
        project_path=cmake.project_path.string();
        Singleton::terminal()->print("Project path for "+path+" set to "+project_path+"\n");
      }
      else
        Singleton::terminal()->print("Error: could not find project path for "+path+"\n");
    }
    source_views.emplace_back(new Source::ClangView(path, project_path));
  }
  else
    source_views.emplace_back(new Source::GenericView(path, language));

  scrolled_windows.emplace_back(new Gtk::ScrolledWindow());
  hboxes.emplace_back(new Gtk::HBox());
  scrolled_windows.back()->add(*source_views.back());
  hboxes.back()->pack_start(*scrolled_windows.back(), true, true);

  boost::filesystem::path file_path(source_views.back()->file_path);
  std::string title=file_path.filename().string();
  append_page(*hboxes.back(), title);
  show_all_children();
  set_current_page(size()-1);
  set_focus_child(*source_views.back());
  get_current_view()->get_buffer()->set_modified(false);
  get_current_view()->grab_focus();
  //Add star on tab label when the page is not saved:
  auto source_view=get_current_view();
  get_current_view()->get_buffer()->signal_modified_changed().connect([this, source_view]() {
    boost::filesystem::path file_path(source_view->file_path);
    std::string title=file_path.filename().string();
    if(source_view->get_buffer()->get_modified())
      title+="*";
    int page=-1;
    for(int c=0;c<size();c++) {
      if(get_view(c)==source_view) {
        page=c;
        break;
      }
    }
    if(page!=-1)
      set_tab_label_text(*(get_nth_page(page)), title);
  });

  get_current_view()->on_update_status=[this](Source::View* view, const std::string &status) {
    if(get_current_view()==view)
      Singleton::status()->set_text(status);
  };
}

bool Notebook::save(int page) {
  if(page>=size())
    return false;
  auto view=get_view(page);
  if (view->file_path != "" && view->get_buffer()->get_modified()) {
    if(juci::filesystem::write(view->file_path, view->get_buffer())) {
      view->get_buffer()->set_modified(false);
      Singleton::terminal()->print("File saved to: " +view->file_path+"\n");

      //If CMakeLists.txt have been modified:
      if(boost::filesystem::path(view->file_path).filename().string()=="CMakeLists.txt") {
        if(directories.cmake && directories.cmake->project_path!="" && boost::filesystem::path(view->file_path)>=directories.cmake->project_path && CMake::create_compile_commands(directories.cmake->project_path.string())) {
          directories.open_folder();
          for(auto source_view: source_views) {
            if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view)) {
              if(directories.cmake->project_path.string()==source_clang_view->project_path) {
                if(source_clang_view->restart_parse())
                  Singleton::terminal()->print("Reparsing "+source_clang_view->file_path+"\n");
                else
                  Singleton::terminal()->print("Already reparsing "+source_clang_view->file_path+". Please reopen the file manually.\n");
              }
            }
          }
        }
      }

      return true;
    }
    Singleton::terminal()->print("Error: could not save file " +view->file_path+"\n");
  }
  return false;
}

bool Notebook::save_current() {
  INFO("Notebook save current file");
  if(get_current_page()==-1)
    return false;
  return save(get_current_page());
}

bool Notebook::close_current_page() {
  INFO("Notebook close page");
  if (size() != 0) {
    if(get_current_view()->get_buffer()->get_modified()){
      if(!save_modified_dialog())
        return false;
    }
    int page = get_current_page();
    remove_page(page);
    if(get_current_page()==-1)
      Singleton::status()->set_text("");
    auto source_view=source_views.at(page);
    source_views.erase(source_views.begin()+ page);
    scrolled_windows.erase(scrolled_windows.begin()+page);
    hboxes.erase(hboxes.begin()+page);
    if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view))
      source_clang_view->async_delete();
    else
      delete source_view;
  }
  return true;
}

bool Notebook::save_modified_dialog() {
  INFO("Notebook::save_modified_dialog");
  Gtk::MessageDialog dialog((Gtk::Window&)(*get_toplevel()), "Save file!", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
  dialog.set_secondary_text("Do you want to save: " + get_current_view()->file_path+" ?");
  int result = dialog.run();
  if(result==Gtk::RESPONSE_YES) {
    save_current();
    return true;
  }
  else if(result==Gtk::RESPONSE_NO) {
    return true;
  }
  else {
    return false;
  }
}

<|endoftext|>


<commit_before>/*
 * Nouncer Implementation
 */

#include "nouncer.h"

/*
 * Assembles the map<word,phoneme> dictionary by reading one line at a time,
 * separating the word from the pronunciation, encoding the phoneme, and
 * putting the pair in the map
 */

std::vector<char> Nouncer::cons = {'9',':',';','<','I','J','K','T','U','V','W',
                                   'X','Y','h','i','j','k','l','m','v','w','y','z','{'};

Nouncer::Nouncer() {

  dict = new std::map<std::string, std::string>;

  std::ifstream file(DICTIONARY_FILE);

  if (file) {
    std::string line;

    while (std::getline(file,line)) {
      if (line.substr(0,3) == COMMENT_HEAD) {
        continue;
      }
      else {
        addWord(line);
      }
    }
  }
  else {
    std::cerr << "Unable to load dictionary" << std::endl;
  }
}

Nouncer::~Nouncer() {
  dict->erase(dict->begin(), dict->end());
  delete dict;
}

/*
 * Given a string, return a pointer to the associated nounce
 * or the nounce of "gravy" if the string is not found.
 */
std::string* Nouncer::lookUp(std::string word) {
  try {
    return &(dict->at(Utils::allCaps(word)));
  }
  catch (const std::out_of_range& oor) {
    return &(dict->at("GRAVY"));
  }
}

/*
 * TODO: Let's encode outside this and pass in the nounce
 *
 * Maps a phoneme dictionary entry to a
 * <std::string word, std::string nounce> pair
 * and inserts in the dictionary.
 */
void Nouncer::addWord(std::string line) {
  std::istringstream ss(line);
  std::string word;
  std::string nounce;
  std::string phoneme;

  ss >> word;

  while (ss >> phoneme) {
    char encoded_phoneme = encode(phoneme);
    nounce.push_back(encoded_phoneme);
  }

  std::reverse(nounce.begin(), nounce.end());

  std::pair<std::string, std::string> word_phonemes(word, nounce);
  dict->insert(word_phonemes);
}

/*
 * Encodes the phoneme string as a nounce
 */
char Nouncer::encode(std::string phoneme) {
  char phone = '\0';

  if      (phoneme == "AA")  phone = ' ';
  else if (phoneme == "AA0") phone = '!';
  else if (phoneme == "AA1") phone = '\"';
  else if (phoneme == "AA2") phone = '#';
  else if (phoneme == "AE")  phone = '$';
  else if (phoneme == "AE0") phone = '%';
  else if (phoneme == "AE1") phone = '&';
  else if (phoneme == "AE2") phone = '(';
  else if (phoneme == "AH")  phone = ')';
  else if (phoneme == "AH0") phone = '*';
  else if (phoneme == "AH1") phone = '+';
  else if (phoneme == "AH2") phone = ',';
  else if (phoneme == "AO")  phone = '-';
  else if (phoneme == "AO0") phone = '.';
  else if (phoneme == "AO1") phone = '/';
  else if (phoneme == "AO2") phone = '0';
  else if (phoneme == "AW")  phone = '1';
  else if (phoneme == "AW0") phone = '2';
  else if (phoneme == "AW1") phone = '3';
  else if (phoneme == "AW2") phone = '4';
  else if (phoneme == "AY")  phone = '5';
  else if (phoneme == "AY0") phone = '6';
  else if (phoneme == "AY1") phone = '7';
  else if (phoneme == "AY2") phone = '8';
  else if (phoneme == "B")   phone = '9';
  else if (phoneme == "CH")  phone = ':';
  else if (phoneme == "D")   phone = ';';
  else if (phoneme == "DH")  phone = '<';
  else if (phoneme == "EH")  phone = '=';
  else if (phoneme == "EH0") phone = '>';
  else if (phoneme == "EH1") phone = '?';
  else if (phoneme == "EH2") phone = '@';
  else if (phoneme == "ER")  phone = 'A';
  else if (phoneme == "ER0") phone = 'B';
  else if (phoneme == "ER1") phone = 'C';
  else if (phoneme == "ER2") phone = 'D';
  else if (phoneme == "EY")  phone = 'E';
  else if (phoneme == "EY0") phone = 'F';
  else if (phoneme == "EY1") phone = 'G';
  else if (phoneme == "EY2") phone = 'H';
  else if (phoneme == "F")   phone = 'I';
  else if (phoneme == "G")   phone = 'J';
  else if (phoneme == "HH")  phone = 'K';
  else if (phoneme == "IH")  phone = 'L';
  else if (phoneme == "IH0") phone = 'M';
  else if (phoneme == "IH1") phone = 'N';
  else if (phoneme == "IH2") phone = 'O';
  else if (phoneme == "IY")  phone = 'P';
  else if (phoneme == "IY0") phone = 'Q';
  else if (phoneme == "IY1") phone = 'R';
  else if (phoneme == "IY2") phone = 'S';
  else if (phoneme == "JH")  phone = 'T';
  else if (phoneme == "K")   phone = 'U';
  else if (phoneme == "L")   phone = 'V';
  else if (phoneme == "M")   phone = 'W';
  else if (phoneme == "N")   phone = 'X';
  else if (phoneme == "NG")  phone = 'Y';
  else if (phoneme == "OW")  phone = 'Z';
  else if (phoneme == "OW0") phone = 'a';
  else if (phoneme == "OW1") phone = 'b';
  else if (phoneme == "OW2") phone = 'c';
  else if (phoneme == "OY")  phone = 'd';
  else if (phoneme == "OY0") phone = 'e';
  else if (phoneme == "OY1") phone = 'f';
  else if (phoneme == "OY2") phone = 'g';
  else if (phoneme == "P")   phone = 'h';
  else if (phoneme == "R")   phone = 'i';
  else if (phoneme == "S")   phone = 'j';
  else if (phoneme == "SH")  phone = 'k';
  else if (phoneme == "T")   phone = 'l';
  else if (phoneme == "TH")  phone = 'm';
  else if (phoneme == "UH")  phone = 'n';
  else if (phoneme == "UH0") phone = 'o';
  else if (phoneme == "UH1") phone = 'p';
  else if (phoneme == "UH2") phone = 'q';
  else if (phoneme == "UW")  phone = 'r';
  else if (phoneme == "UW0") phone = 's';
  else if (phoneme == "UW1") phone = 't';
  else if (phoneme == "UW2") phone = 'u';
  else if (phoneme == "V")   phone = 'v';
  else if (phoneme == "W")   phone = 'w';
  else if (phoneme == "Y")   phone = 'y';
  else if (phoneme == "Z")   phone = 'z';
  else if (phoneme == "ZH")  phone = '{';
  else
    std::cerr << "Could not identify phoneme " << phoneme << std::endl;

  return phone;
}

bool Nouncer::isVowel(char& phone) {
  if (std::find(cons.begin(),cons.end(),phone) != cons.end() ) return false;

  else return true;
}

int Nouncer::getSylCount(std::string word) {
  int count = 0;
  std::string* nounce = lookUp(word);

  for (auto i = nounce->begin(); i != nounce->end(); ++i) {
    if ( isVowel(*i) ) count++;
  }

  return count;
}

int Nouncer::getSize() {
  return dict->size();
}

void Nouncer::print(std::string filename) {
  std::ofstream of(filename);
  for (auto it = dict->begin(); it!=dict->end(); ++it) {
    of<<(*it).first<<":"<<(*it).second<<std::endl;
  }
}
<commit_msg>clean up<commit_after>/*
 * Nouncer Implementation
 */

#include "nouncer.h"

/*
 * Assembles the map<word,phoneme> dictionary by reading one line at a time,
 * separating the word from the pronunciation, encoding the phoneme, and
 * putting the pair in the map
 */

std::vector<char> Nouncer::cons = {
  '9',':',';','<','I','J','K','T','U','V','W',
  'X','Y','h','i','j','k','l','m','v','w','y','z','{'
};

Nouncer::Nouncer() {

  dict = new std::map<std::string, std::string>;

  std::ifstream file(DICTIONARY_FILE);

  if (file) {
    std::string line;

    while (std::getline(file,line)) {
      if (line.substr(0,3) == COMMENT_HEAD) {
        continue;
      }
      else {
        addWord(line);
      }
    }
  }
  else {
    std::cerr << "Unable to load dictionary" << std::endl;
  }
}

Nouncer::~Nouncer() {
  dict->erase(dict->begin(), dict->end());
  delete dict;
}

/*
 * Given a string, return a pointer to the associated nounce
 * or the nounce of "gravy" if the string is not found.
 */
std::string* Nouncer::lookUp(std::string word) {
  try {
    return &(dict->at(Utils::allCaps(word)));
  }
  catch (const std::out_of_range& oor) {
    return &(dict->at("GRAVY"));
  }
}

/*
 * TODO: Let's encode outside this and pass in the nounce
 *
 * Maps a phoneme dictionary entry to a
 * <std::string word, std::string nounce> pair
 * and inserts in the dictionary.
 */
void Nouncer::addWord(std::string line) {
  std::istringstream ss(line);
  std::string word;
  std::string nounce;
  std::string phoneme;

  ss >> word;

  while (ss >> phoneme) {
    char encoded_phoneme = encode(phoneme);
    nounce.push_back(encoded_phoneme);
  }

  std::reverse(nounce.begin(), nounce.end());

  std::pair<std::string, std::string> word_phonemes(word, nounce);
  dict->insert(word_phonemes);
}

/*
 * Encodes the phoneme string as a nounce
 */
char Nouncer::encode(std::string phoneme) {
  char phone = '\0';

  if      (phoneme == "AA")  phone = ' ';
  else if (phoneme == "AA0") phone = '!';
  else if (phoneme == "AA1") phone = '\"';
  else if (phoneme == "AA2") phone = '#';
  else if (phoneme == "AE")  phone = '$';
  else if (phoneme == "AE0") phone = '%';
  else if (phoneme == "AE1") phone = '&';
  else if (phoneme == "AE2") phone = '(';
  else if (phoneme == "AH")  phone = ')';
  else if (phoneme == "AH0") phone = '*';
  else if (phoneme == "AH1") phone = '+';
  else if (phoneme == "AH2") phone = ',';
  else if (phoneme == "AO")  phone = '-';
  else if (phoneme == "AO0") phone = '.';
  else if (phoneme == "AO1") phone = '/';
  else if (phoneme == "AO2") phone = '0';
  else if (phoneme == "AW")  phone = '1';
  else if (phoneme == "AW0") phone = '2';
  else if (phoneme == "AW1") phone = '3';
  else if (phoneme == "AW2") phone = '4';
  else if (phoneme == "AY")  phone = '5';
  else if (phoneme == "AY0") phone = '6';
  else if (phoneme == "AY1") phone = '7';
  else if (phoneme == "AY2") phone = '8';
  else if (phoneme == "B")   phone = '9';
  else if (phoneme == "CH")  phone = ':';
  else if (phoneme == "D")   phone = ';';
  else if (phoneme == "DH")  phone = '<';
  else if (phoneme == "EH")  phone = '=';
  else if (phoneme == "EH0") phone = '>';
  else if (phoneme == "EH1") phone = '?';
  else if (phoneme == "EH2") phone = '@';
  else if (phoneme == "ER")  phone = 'A';
  else if (phoneme == "ER0") phone = 'B';
  else if (phoneme == "ER1") phone = 'C';
  else if (phoneme == "ER2") phone = 'D';
  else if (phoneme == "EY")  phone = 'E';
  else if (phoneme == "EY0") phone = 'F';
  else if (phoneme == "EY1") phone = 'G';
  else if (phoneme == "EY2") phone = 'H';
  else if (phoneme == "F")   phone = 'I';
  else if (phoneme == "G")   phone = 'J';
  else if (phoneme == "HH")  phone = 'K';
  else if (phoneme == "IH")  phone = 'L';
  else if (phoneme == "IH0") phone = 'M';
  else if (phoneme == "IH1") phone = 'N';
  else if (phoneme == "IH2") phone = 'O';
  else if (phoneme == "IY")  phone = 'P';
  else if (phoneme == "IY0") phone = 'Q';
  else if (phoneme == "IY1") phone = 'R';
  else if (phoneme == "IY2") phone = 'S';
  else if (phoneme == "JH")  phone = 'T';
  else if (phoneme == "K")   phone = 'U';
  else if (phoneme == "L")   phone = 'V';
  else if (phoneme == "M")   phone = 'W';
  else if (phoneme == "N")   phone = 'X';
  else if (phoneme == "NG")  phone = 'Y';
  else if (phoneme == "OW")  phone = 'Z';
  else if (phoneme == "OW0") phone = 'a';
  else if (phoneme == "OW1") phone = 'b';
  else if (phoneme == "OW2") phone = 'c';
  else if (phoneme == "OY")  phone = 'd';
  else if (phoneme == "OY0") phone = 'e';
  else if (phoneme == "OY1") phone = 'f';
  else if (phoneme == "OY2") phone = 'g';
  else if (phoneme == "P")   phone = 'h';
  else if (phoneme == "R")   phone = 'i';
  else if (phoneme == "S")   phone = 'j';
  else if (phoneme == "SH")  phone = 'k';
  else if (phoneme == "T")   phone = 'l';
  else if (phoneme == "TH")  phone = 'm';
  else if (phoneme == "UH")  phone = 'n';
  else if (phoneme == "UH0") phone = 'o';
  else if (phoneme == "UH1") phone = 'p';
  else if (phoneme == "UH2") phone = 'q';
  else if (phoneme == "UW")  phone = 'r';
  else if (phoneme == "UW0") phone = 's';
  else if (phoneme == "UW1") phone = 't';
  else if (phoneme == "UW2") phone = 'u';
  else if (phoneme == "V")   phone = 'v';
  else if (phoneme == "W")   phone = 'w';
  else if (phoneme == "Y")   phone = 'y';
  else if (phoneme == "Z")   phone = 'z';
  else if (phoneme == "ZH")  phone = '{';
  else
    std::cerr << "Could not identify phoneme " << phoneme << std::endl;

  return phone;
}

bool Nouncer::isVowel(char& phone) {
  return !(std::find(cons.begin(),cons.end(),phone) != cons.end())
}

int Nouncer::getSylCount(std::string word) {
  int count = 0;
  std::string* nounce = lookUp(word);

  for (auto i = nounce->begin(); i != nounce->end(); ++i) {
    if ( isVowel(*i) ) count++;
  }

  return count;
}

int Nouncer::getSize() {
  return dict->size();
}

void Nouncer::print(std::string filename) {
  std::ofstream of(filename);
  for (auto it = dict->begin(); it!=dict->end(); ++it) {
    of<<(*it).first<<":"<<(*it).second<<std::endl;
  }
}
<|endoftext|>


<commit_before>#include "commands.h"
#include "config.h"
#include "diagnostics.h"
#include "interface/usb.h"
#include "util/log.h"
#include "config.h"
#include "openxc.pb.h"
#include "pb_decode.h"
#include <payload/payload.h>
#include "signals.h"
#include <can/canutil.h>
#include <bitfield/bitfield.h>
#include <limits.h>

using openxc::interface::usb::sendControlMessage;
using openxc::util::log::debug;
using openxc::config::getConfiguration;
using openxc::payload::PayloadFormat;
using openxc::commands::UsbControlCommand;
using openxc::signals::getCanBuses;
using openxc::signals::getCanBusCount;
using openxc::signals::getSignals;
using openxc::signals::getSignalCount;
using openxc::signals::getCommands;
using openxc::signals::getCommandCount;
using openxc::can::lookupBus;
using openxc::can::lookupSignal;

namespace can = openxc::can;
namespace payload = openxc::payload;
namespace config = openxc::config;
namespace diagnostics = openxc::diagnostics;
namespace usb = openxc::interface::usb;
namespace uart = openxc::interface::uart;
namespace pipeline = openxc::pipeline;

static bool handleVersionCommand() {
    char descriptor[128];
    config::getFirmwareDescriptor(descriptor, sizeof(descriptor));

    usb::sendControlMessage(&getConfiguration()->usb, (uint8_t*)descriptor,
            strlen(descriptor));

    openxc_VehicleMessage message;
    message.has_type = true;
    message.type = openxc_VehicleMessage_Type_COMMAND_RESPONSE;
    message.has_command_response = true;
    message.command_response.has_type = true;
    message.command_response.type = openxc_ControlCommand_Type_VERSION;
    message.command_response.has_message = true;
    memset(message.command_response.message, 0,
            sizeof(message.command_response.message));
    strncpy(message.command_response.message, descriptor, sizeof(descriptor));
    pipeline::publish(&message, &getConfiguration()->pipeline);

    return true;
}

static bool handleDeviceIdCommmand() {
    // TODO move getDeviceId to openxc::platform, allow each platform to
    // define where the device ID comes from.
    uart::UartDevice* uart = &getConfiguration()->uart;
    size_t deviceIdLength = strnlen(uart->deviceId, sizeof(uart->deviceId));
    if(deviceIdLength > 0) {
        usb::sendControlMessage(&getConfiguration()->usb,
                (uint8_t*)uart->deviceId, strlen(uart->deviceId));

        openxc_VehicleMessage message;
        message.has_type = true;
        message.type = openxc_VehicleMessage_Type_COMMAND_RESPONSE;
        message.has_command_response = true;
        message.command_response.has_type = true;
        message.command_response.type = openxc_ControlCommand_Type_DEVICE_ID;
        message.command_response.has_message = true;
        memset(message.command_response.message, 0,
                sizeof(message.command_response.message));
        strncpy(message.command_response.message, uart->deviceId,
                deviceIdLength);
        pipeline::publish(&message, &getConfiguration()->pipeline);
    }
    return true;
}

static bool handleDiagnosticRequestCommand(openxc_ControlCommand* command) {
    bool status = diagnostics::handleDiagnosticCommand(
            &getConfiguration()->diagnosticsManager, command);

    openxc_VehicleMessage message;
    message.has_type = true;
    message.type = openxc_VehicleMessage_Type_COMMAND_RESPONSE;
    message.has_command_response = true;
    message.command_response.has_type = true;
    message.command_response.type = openxc_ControlCommand_Type_DIAGNOSTIC;
    message.command_response.has_status = true;
    message.command_response.status = status;
    pipeline::publish(&message, &getConfiguration()->pipeline);

    return status;
}

static bool handleComplexCommand(openxc_VehicleMessage* message) {
    bool status = true;
    if(message != NULL && message->has_control_command) {
        openxc_ControlCommand* command = &message->control_command;
        switch(command->type) {
        case openxc_ControlCommand_Type_DIAGNOSTIC:
            status = handleDiagnosticRequestCommand(command);
            break;
        case openxc_ControlCommand_Type_VERSION:
            status = handleVersionCommand();
            break;
        case openxc_ControlCommand_Type_DEVICE_ID:
            status = handleDeviceIdCommmand();
            break;
        default:
            status = false;
            break;
        }
    }
    return status;
}

static bool handleRaw(openxc_VehicleMessage* message) {
    bool status = true;
    if(message->has_raw_message) {
        openxc_RawMessage* rawMessage = &message->raw_message;
        CanBus* matchingBus = NULL;
        if(rawMessage->has_bus) {
            matchingBus = lookupBus(rawMessage->bus, getCanBuses(), getCanBusCount());
        } else if(getCanBusCount() > 0) {
            matchingBus = &getCanBuses()[0];
            debug("No bus specified for write, using the first active: %d", matchingBus->address);
        }

        if(matchingBus == NULL) {
            debug("No matching active bus for requested address: %d",
                    rawMessage->bus);
            status = false;
        } else if(matchingBus->rawWritable) {
            uint8_t size = rawMessage->data.size;
            CanMessage message = {
                id: rawMessage->message_id,
                format: rawMessage->message_id > 2047 ? CanMessageFormat::EXTENDED : CanMessageFormat::STANDARD
            };
            memcpy(message.data, rawMessage->data.bytes, size);
            message.length = size;
            can::write::enqueueMessage(matchingBus, &message);
        } else {
            debug("Raw CAN writes not allowed for bus %d", matchingBus->address);
            status = false;
        }
    }
    return status;
}

static bool handleTranslated(openxc_VehicleMessage* message) {
    bool status = true;
    if(message->has_translated_message) {
        openxc_TranslatedMessage* translatedMessage =
                &message->translated_message;
        if(translatedMessage->has_name) {
            CanSignal* signal = lookupSignal(translatedMessage->name,
                    getSignals(), getSignalCount(), true);
            if(signal != NULL) {
                if(!translatedMessage->has_value) {
                    debug("Write request for %s missing value", translatedMessage->name);
                    status = false;
                }

                can::write::encodeAndSendSignal(signal, &translatedMessage->value, false);
                // TODO support writing evented signals
            } else {
                CanCommand* command = lookupCommand(translatedMessage->name,
                        getCommands(), getCommandCount());
                if(command != NULL) {
                    // TODO this still isn't that flexible, can't accept
                    // arbitrary parameters in your command - still stuck with
                    // this 'value' and 'event' business, where the eventeds all
                    // have string values
                    // TODO could simplify it by passing the entire
                    // TranslatedMessage to the handler
                    switch(translatedMessage->type) {
                    case openxc_TranslatedMessage_Type_STRING:
                    case openxc_TranslatedMessage_Type_NUM:
                    case openxc_TranslatedMessage_Type_BOOL:
                        command->handler(translatedMessage->name,
                                &translatedMessage->value,
                                NULL,
                                getSignals(), getSignalCount());
                        break;
                    case openxc_TranslatedMessage_Type_EVENTED_STRING:
                    case openxc_TranslatedMessage_Type_EVENTED_NUM:
                    case openxc_TranslatedMessage_Type_EVENTED_BOOL:
                        command->handler(translatedMessage->name,
                                &translatedMessage->value,
                                &translatedMessage->event,
                                getSignals(), getSignalCount());
                        break;
                    }
                } else {
                    debug("Writing not allowed for signal \"%s\"",
                            translatedMessage->name);
                    status = false;
                }
            }
        }
    }
    return status;
}

bool openxc::commands::handleControlCommand(UsbControlCommand command, uint8_t payload[],
        size_t payloadLength) {
    bool recognized = true;
    switch(command) {
    case UsbControlCommand::VERSION:
        handleVersionCommand();
        break;
    case UsbControlCommand::DEVICE_ID:
        handleDeviceIdCommmand();
        break;
    case UsbControlCommand::COMPLEX_COMMAND:
        handleIncomingMessage(payload, payloadLength);
        break;
    default:
        recognized = false;
        break;
    }
    return recognized;
}

bool openxc::commands::handleIncomingMessage(uint8_t payload[], size_t length) {
    openxc_VehicleMessage message = {0};
    bool status = true;
    if(payload::deserialize(payload, length,
                getConfiguration()->payloadFormat, &message)) {
        if(validate(&message)) {
            switch(message.type) {
            case openxc_VehicleMessage_Type_RAW:
                handleRaw(&message);
                break;
            case openxc_VehicleMessage_Type_TRANSLATED:
                handleTranslated(&message);
                break;
            case openxc_VehicleMessage_Type_CONTROL_COMMAND:
                handleComplexCommand(&message);
                break;
            default:
                debug("Incoming message had unrecognized type: %d", message.type);
                status = false;
                break;
            }
        } else {
            debug("Incoming message is complete but invalid");
        }
    } else {
        status = false;
    }
    return status;
}

static bool validateRaw(openxc_VehicleMessage* message) {
    bool valid = true;
    if(message->has_type && message->type == openxc_VehicleMessage_Type_RAW &&
            message->has_raw_message) {
        openxc_RawMessage* raw = &message->raw_message;
        if(!raw->has_message_id) {
            valid = false;
            debug("Write request is malformed, missing id");
        }

        if(!raw->has_data) {
            valid = false;
            debug("Raw write request for 0x%02x missing data", raw->message_id);
        }
    } else {
        valid = false;
    }
    return valid;
}

static bool validateTranslated(openxc_VehicleMessage* message) {
    bool valid = true;
    if(message->has_type && message->type == openxc_VehicleMessage_Type_TRANSLATED &&
            message->has_translated_message) {
        openxc_TranslatedMessage* translated = &message->translated_message;
        if(!translated->has_name) {
            valid = false;
            debug("Write request is missing name");
        }

        if(!translated->has_value) {
            valid = false;
        } else if(!translated->value.has_type) {
            valid = false;
            debug("Unsupported type in value field of %s", translated->name);
        }

        if(translated->has_event) {
            if(!translated->event.has_type) {
                valid = false;
                debug("Unsupported type in event field of %s", translated->name);
            }
        }

    } else {
        valid = false;
    }
    return valid;
}

static bool validateDiagnosticRequest(openxc_VehicleMessage* message) {
    bool valid = true;
    if(message->has_control_command) {
        openxc_ControlCommand* command = &message->control_command;
        if(command->has_type && command->type == openxc_ControlCommand_Type_DIAGNOSTIC) {
            openxc_DiagnosticRequest* request = &command->diagnostic_request;

            if(!request->has_action) {
                valid = false;
                debug("Diagnostic request command missing action");
            }

            if(!request->has_message_id) {
                valid = false;
                debug("Diagnostic request missing message ID");
            }

            if(!request->has_mode) {
                valid = false;
                debug("Diagnostic request missing mode");
            }
        } else {
            valid = false;
            debug("Diagnostic request is of unexpected type");
        }
    } else {
        valid = false;
    }
    return valid;
}

static bool validateControlCommand(openxc_VehicleMessage* message) {
    bool valid = message->has_type &&
            message->type == openxc_VehicleMessage_Type_CONTROL_COMMAND &&
            message->has_control_command &&
            message->control_command.has_type;
    if(valid) {
        switch(message->control_command.type) {
        case openxc_ControlCommand_Type_DIAGNOSTIC:
            valid = validateDiagnosticRequest(message);
            break;
        case openxc_ControlCommand_Type_VERSION:
        case openxc_ControlCommand_Type_DEVICE_ID:
            valid =  true;
            break;
        default:
            valid = false;
            break;
        }
    }
    return valid;
}

bool openxc::commands::validate(openxc_VehicleMessage* message) {
    bool valid = false;
    if(message != NULL && message->has_type) {
        switch(message->type) {
        case openxc_VehicleMessage_Type_RAW:
            valid = validateRaw(message);
            break;
        case openxc_VehicleMessage_Type_TRANSLATED:
            valid = validateTranslated(message);
            break;
        case openxc_VehicleMessage_Type_CONTROL_COMMAND:
            valid = validateControlCommand(message);
            break;
        default:
            debug("Incoming message had unrecognized type: %d", message->type);
            break;
        }
    }
    return valid;
}
<commit_msg>Make sure diag command responses have no 'message'.<commit_after>#include "commands.h"
#include "config.h"
#include "diagnostics.h"
#include "interface/usb.h"
#include "util/log.h"
#include "config.h"
#include "openxc.pb.h"
#include "pb_decode.h"
#include <payload/payload.h>
#include "signals.h"
#include <can/canutil.h>
#include <bitfield/bitfield.h>
#include <limits.h>

using openxc::interface::usb::sendControlMessage;
using openxc::util::log::debug;
using openxc::config::getConfiguration;
using openxc::payload::PayloadFormat;
using openxc::commands::UsbControlCommand;
using openxc::signals::getCanBuses;
using openxc::signals::getCanBusCount;
using openxc::signals::getSignals;
using openxc::signals::getSignalCount;
using openxc::signals::getCommands;
using openxc::signals::getCommandCount;
using openxc::can::lookupBus;
using openxc::can::lookupSignal;

namespace can = openxc::can;
namespace payload = openxc::payload;
namespace config = openxc::config;
namespace diagnostics = openxc::diagnostics;
namespace usb = openxc::interface::usb;
namespace uart = openxc::interface::uart;
namespace pipeline = openxc::pipeline;

static bool handleVersionCommand() {
    char descriptor[128];
    config::getFirmwareDescriptor(descriptor, sizeof(descriptor));

    usb::sendControlMessage(&getConfiguration()->usb, (uint8_t*)descriptor,
            strlen(descriptor));

    openxc_VehicleMessage message;
    message.has_type = true;
    message.type = openxc_VehicleMessage_Type_COMMAND_RESPONSE;
    message.has_command_response = true;
    message.command_response.has_type = true;
    message.command_response.type = openxc_ControlCommand_Type_VERSION;
    message.command_response.has_message = true;
    memset(message.command_response.message, 0,
            sizeof(message.command_response.message));
    strncpy(message.command_response.message, descriptor, sizeof(descriptor));
    pipeline::publish(&message, &getConfiguration()->pipeline);

    return true;
}

static bool handleDeviceIdCommmand() {
    // TODO move getDeviceId to openxc::platform, allow each platform to
    // define where the device ID comes from.
    uart::UartDevice* uart = &getConfiguration()->uart;
    size_t deviceIdLength = strnlen(uart->deviceId, sizeof(uart->deviceId));
    if(deviceIdLength > 0) {
        usb::sendControlMessage(&getConfiguration()->usb,
                (uint8_t*)uart->deviceId, strlen(uart->deviceId));

        openxc_VehicleMessage message;
        message.has_type = true;
        message.type = openxc_VehicleMessage_Type_COMMAND_RESPONSE;
        message.has_command_response = true;
        message.command_response.has_type = true;
        message.command_response.type = openxc_ControlCommand_Type_DEVICE_ID;
        message.command_response.has_message = true;
        memset(message.command_response.message, 0,
                sizeof(message.command_response.message));
        strncpy(message.command_response.message, uart->deviceId,
                deviceIdLength);
        pipeline::publish(&message, &getConfiguration()->pipeline);
    }
    return true;
}

static bool handleDiagnosticRequestCommand(openxc_ControlCommand* command) {
    bool status = diagnostics::handleDiagnosticCommand(
            &getConfiguration()->diagnosticsManager, command);

    openxc_VehicleMessage message;
    message.has_type = true;
    message.type = openxc_VehicleMessage_Type_COMMAND_RESPONSE;
    message.has_command_response = true;
    message.command_response.has_type = true;
    message.command_response.type = openxc_ControlCommand_Type_DIAGNOSTIC;
    message.command_response.has_message = false;
    message.command_response.has_status = true;
    message.command_response.status = status;
    pipeline::publish(&message, &getConfiguration()->pipeline);

    return status;
}

static bool handleComplexCommand(openxc_VehicleMessage* message) {
    bool status = true;
    if(message != NULL && message->has_control_command) {
        openxc_ControlCommand* command = &message->control_command;
        switch(command->type) {
        case openxc_ControlCommand_Type_DIAGNOSTIC:
            status = handleDiagnosticRequestCommand(command);
            break;
        case openxc_ControlCommand_Type_VERSION:
            status = handleVersionCommand();
            break;
        case openxc_ControlCommand_Type_DEVICE_ID:
            status = handleDeviceIdCommmand();
            break;
        default:
            status = false;
            break;
        }
    }
    return status;
}

static bool handleRaw(openxc_VehicleMessage* message) {
    bool status = true;
    if(message->has_raw_message) {
        openxc_RawMessage* rawMessage = &message->raw_message;
        CanBus* matchingBus = NULL;
        if(rawMessage->has_bus) {
            matchingBus = lookupBus(rawMessage->bus, getCanBuses(), getCanBusCount());
        } else if(getCanBusCount() > 0) {
            matchingBus = &getCanBuses()[0];
            debug("No bus specified for write, using the first active: %d", matchingBus->address);
        }

        if(matchingBus == NULL) {
            debug("No matching active bus for requested address: %d",
                    rawMessage->bus);
            status = false;
        } else if(matchingBus->rawWritable) {
            uint8_t size = rawMessage->data.size;
            CanMessage message = {
                id: rawMessage->message_id,
                format: rawMessage->message_id > 2047 ? CanMessageFormat::EXTENDED : CanMessageFormat::STANDARD
            };
            memcpy(message.data, rawMessage->data.bytes, size);
            message.length = size;
            can::write::enqueueMessage(matchingBus, &message);
        } else {
            debug("Raw CAN writes not allowed for bus %d", matchingBus->address);
            status = false;
        }
    }
    return status;
}

static bool handleTranslated(openxc_VehicleMessage* message) {
    bool status = true;
    if(message->has_translated_message) {
        openxc_TranslatedMessage* translatedMessage =
                &message->translated_message;
        if(translatedMessage->has_name) {
            CanSignal* signal = lookupSignal(translatedMessage->name,
                    getSignals(), getSignalCount(), true);
            if(signal != NULL) {
                if(!translatedMessage->has_value) {
                    debug("Write request for %s missing value", translatedMessage->name);
                    status = false;
                }

                can::write::encodeAndSendSignal(signal, &translatedMessage->value, false);
                // TODO support writing evented signals
            } else {
                CanCommand* command = lookupCommand(translatedMessage->name,
                        getCommands(), getCommandCount());
                if(command != NULL) {
                    // TODO this still isn't that flexible, can't accept
                    // arbitrary parameters in your command - still stuck with
                    // this 'value' and 'event' business, where the eventeds all
                    // have string values
                    // TODO could simplify it by passing the entire
                    // TranslatedMessage to the handler
                    switch(translatedMessage->type) {
                    case openxc_TranslatedMessage_Type_STRING:
                    case openxc_TranslatedMessage_Type_NUM:
                    case openxc_TranslatedMessage_Type_BOOL:
                        command->handler(translatedMessage->name,
                                &translatedMessage->value,
                                NULL,
                                getSignals(), getSignalCount());
                        break;
                    case openxc_TranslatedMessage_Type_EVENTED_STRING:
                    case openxc_TranslatedMessage_Type_EVENTED_NUM:
                    case openxc_TranslatedMessage_Type_EVENTED_BOOL:
                        command->handler(translatedMessage->name,
                                &translatedMessage->value,
                                &translatedMessage->event,
                                getSignals(), getSignalCount());
                        break;
                    }
                } else {
                    debug("Writing not allowed for signal \"%s\"",
                            translatedMessage->name);
                    status = false;
                }
            }
        }
    }
    return status;
}

bool openxc::commands::handleControlCommand(UsbControlCommand command, uint8_t payload[],
        size_t payloadLength) {
    bool recognized = true;
    switch(command) {
    case UsbControlCommand::VERSION:
        handleVersionCommand();
        break;
    case UsbControlCommand::DEVICE_ID:
        handleDeviceIdCommmand();
        break;
    case UsbControlCommand::COMPLEX_COMMAND:
        handleIncomingMessage(payload, payloadLength);
        break;
    default:
        recognized = false;
        break;
    }
    return recognized;
}

bool openxc::commands::handleIncomingMessage(uint8_t payload[], size_t length) {
    openxc_VehicleMessage message = {0};
    bool status = true;
    if(payload::deserialize(payload, length,
                getConfiguration()->payloadFormat, &message)) {
        if(validate(&message)) {
            switch(message.type) {
            case openxc_VehicleMessage_Type_RAW:
                handleRaw(&message);
                break;
            case openxc_VehicleMessage_Type_TRANSLATED:
                handleTranslated(&message);
                break;
            case openxc_VehicleMessage_Type_CONTROL_COMMAND:
                handleComplexCommand(&message);
                break;
            default:
                debug("Incoming message had unrecognized type: %d", message.type);
                status = false;
                break;
            }
        } else {
            debug("Incoming message is complete but invalid");
        }
    } else {
        status = false;
    }
    return status;
}

static bool validateRaw(openxc_VehicleMessage* message) {
    bool valid = true;
    if(message->has_type && message->type == openxc_VehicleMessage_Type_RAW &&
            message->has_raw_message) {
        openxc_RawMessage* raw = &message->raw_message;
        if(!raw->has_message_id) {
            valid = false;
            debug("Write request is malformed, missing id");
        }

        if(!raw->has_data) {
            valid = false;
            debug("Raw write request for 0x%02x missing data", raw->message_id);
        }
    } else {
        valid = false;
    }
    return valid;
}

static bool validateTranslated(openxc_VehicleMessage* message) {
    bool valid = true;
    if(message->has_type && message->type == openxc_VehicleMessage_Type_TRANSLATED &&
            message->has_translated_message) {
        openxc_TranslatedMessage* translated = &message->translated_message;
        if(!translated->has_name) {
            valid = false;
            debug("Write request is missing name");
        }

        if(!translated->has_value) {
            valid = false;
        } else if(!translated->value.has_type) {
            valid = false;
            debug("Unsupported type in value field of %s", translated->name);
        }

        if(translated->has_event) {
            if(!translated->event.has_type) {
                valid = false;
                debug("Unsupported type in event field of %s", translated->name);
            }
        }

    } else {
        valid = false;
    }
    return valid;
}

static bool validateDiagnosticRequest(openxc_VehicleMessage* message) {
    bool valid = true;
    if(message->has_control_command) {
        openxc_ControlCommand* command = &message->control_command;
        if(command->has_type && command->type == openxc_ControlCommand_Type_DIAGNOSTIC) {
            openxc_DiagnosticRequest* request = &command->diagnostic_request;

            if(!request->has_action) {
                valid = false;
                debug("Diagnostic request command missing action");
            }

            if(!request->has_message_id) {
                valid = false;
                debug("Diagnostic request missing message ID");
            }

            if(!request->has_mode) {
                valid = false;
                debug("Diagnostic request missing mode");
            }
        } else {
            valid = false;
            debug("Diagnostic request is of unexpected type");
        }
    } else {
        valid = false;
    }
    return valid;
}

static bool validateControlCommand(openxc_VehicleMessage* message) {
    bool valid = message->has_type &&
            message->type == openxc_VehicleMessage_Type_CONTROL_COMMAND &&
            message->has_control_command &&
            message->control_command.has_type;
    if(valid) {
        switch(message->control_command.type) {
        case openxc_ControlCommand_Type_DIAGNOSTIC:
            valid = validateDiagnosticRequest(message);
            break;
        case openxc_ControlCommand_Type_VERSION:
        case openxc_ControlCommand_Type_DEVICE_ID:
            valid =  true;
            break;
        default:
            valid = false;
            break;
        }
    }
    return valid;
}

bool openxc::commands::validate(openxc_VehicleMessage* message) {
    bool valid = false;
    if(message != NULL && message->has_type) {
        switch(message->type) {
        case openxc_VehicleMessage_Type_RAW:
            valid = validateRaw(message);
            break;
        case openxc_VehicleMessage_Type_TRANSLATED:
            valid = validateTranslated(message);
            break;
        case openxc_VehicleMessage_Type_CONTROL_COMMAND:
            valid = validateControlCommand(message);
            break;
        default:
            debug("Incoming message had unrecognized type: %d", message->type);
            break;
        }
    }
    return valid;
}
<|endoftext|>