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

#include "wallet/init.h"

#include "guiinterfaceutil.h"
#include "net.h"
#include "util/system.h"
#include "utilmoneystr.h"
#include "validation.h"
#include "wallet/wallet.h"

std::string GetWalletHelpString(bool showDebug)
{
    std::string strUsage = HelpMessageGroup(_("Wallet options:"));
    strUsage += HelpMessageOpt("-backuppath=<dir|file>", _("Specify custom backup path to add a copy of any wallet backup. If set as dir, every backup generates a timestamped file. If set as file, will rewrite to that file every backup."));
    strUsage += HelpMessageOpt("-createwalletbackups=<n>", strprintf(_("Number of automatic wallet backups (default: %d)"), DEFAULT_CREATEWALLETBACKUPS));
    strUsage += HelpMessageOpt("-custombackupthreshold=<n>", strprintf(_("Number of custom location backups to retain (default: %d)"), DEFAULT_CUSTOMBACKUPTHRESHOLD));
    strUsage += HelpMessageOpt("-disablewallet", strprintf(_("Do not load the wallet and disable wallet RPC calls (default: %u)"), DEFAULT_DISABLE_WALLET));
    strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
    strUsage += HelpMessageOpt("-legacywallet", _("On first run, create a legacy wallet instead of a HD wallet"));
    strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s)"), FormatMoney(maxTxFee)));
    strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"), CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK())));
    strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
    strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup"));
    strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet file") + " " + _("on startup"));
    strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
    strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), 1));
    strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup"));
    strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
    strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
    strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
        " " + _("(1 = keep tx meta data e.g. payment request information, 2 = drop tx meta data)"));
    strUsage += HelpMessageGroup(_("Mining/Staking options:"));
    strUsage += HelpMessageOpt("-coldstaking=<n>", strprintf(_("Enable cold staking functionality (0-1, default: %u). Disabled if staking=0"), DEFAULT_COLDSTAKING));
    strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), DEFAULT_GENERATE));
    strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_PROCLIMIT));
    strUsage += HelpMessageOpt("-minstakesplit=<amt>", strprintf(_("Minimum positive amount (in PIV) allowed by GUI and RPC for the stake split threshold (default: %s)"), FormatMoney(DEFAULT_MIN_STAKE_SPLIT_THRESHOLD)));
    strUsage += HelpMessageOpt("-staking=<n>", strprintf(_("Enable staking functionality (0-1, default: %u)"), DEFAULT_STAKING));
    if (showDebug) {
        strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
        strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf(_("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)"), DEFAULT_WALLET_DBLOGSIZE));
        strUsage += HelpMessageOpt("-flushwallet", strprintf(_("Run a thread to flush wallet periodically (default: %u)"), DEFAULT_FLUSHWALLET));
        strUsage += HelpMessageOpt("-printcoinstake", _("Display verbose coin stake messages in the debug.log file."));
        strUsage += HelpMessageOpt("-privdb", strprintf(_("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)"), DEFAULT_WALLET_PRIVDB));
    }

    return strUsage;
}

bool WalletParameterInteraction()
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        return true;
    }

    if (gArgs.GetBoolArg("-sysperms", false)) {
        return UIError(strprintf(_("%s is not allowed in combination with enabled wallet functionality"), "-sysperms"));
    }

    gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);
    const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;

    if (gArgs.GetBoolArg("-salvagewallet", false)) {
        if (is_multiwallet) {
            return UIError(strprintf(_("%s is only allowed with a single wallet file"), "-salvagewallet"));
        }
        // Rewrite just private keys: rescan to find transactions
        if (gArgs.SoftSetBoolArg("-rescan", true)) {
            LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
        }
    }

    bool zapwallettxes = gArgs.GetBoolArg("-zapwallettxes", false);
    // -zapwallettxes implies dropping the mempool on startup
    if (zapwallettxes && gArgs.SoftSetBoolArg("-persistmempool", false)) {
        LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
    }

    // -zapwallettxes implies a rescan
    if (zapwallettxes) {
        if (is_multiwallet) {
            return UIError(strprintf(_("%s is only allowed with a single wallet file"), "-zapwallettxes"));
        }
        if (gArgs.SoftSetBoolArg("-rescan", true)) {
            LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
        }
    }

    if (is_multiwallet) {
        if (gArgs.GetBoolArg("-upgradewallet", false)) {
            return UIError(strprintf(_("%s is only allowed with a single wallet file"), "-upgradewallet"));
        }
    }

    if (gArgs.IsArgSet("-mintxfee")) {
        CAmount n = 0;
        if (ParseMoney(gArgs.GetArg("-mintxfee", ""), n) && n > 0)
            CWallet::minTxFee = CFeeRate(n);
        else
            return UIError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")));
    }
    if (gArgs.IsArgSet("-paytxfee")) {
        CAmount nFeePerK = 0;
        if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK))
            return UIError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")));
        if (nFeePerK > nHighTransactionFeeWarning)
            UIWarning(strprintf(_("Warning: %s is set very high! This is the transaction fee you will pay if you send a transaction."), "-paytxfee"));
        payTxFee = CFeeRate(nFeePerK, 1000);
        if (payTxFee < ::minRelayTxFee) {
            return UIError(strprintf(_("Invalid amount for %s: '%s' (must be at least %s)"), "-paytxfee",
                                       gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
        }
    }
    if (gArgs.IsArgSet("-maxtxfee")) {
        CAmount nMaxFee = 0;
        if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
            return UIError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
        if (nMaxFee > nHighTransactionMaxFeeWarning)
            UIWarning(strprintf(_("Warning: %s is set very high! Fees this large could be paid on a single transaction."), "-maxtxfee"));
        maxTxFee = nMaxFee;
        if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) {
            return UIError(strprintf(_("Invalid amount for %s: '%s' (must be at least the minimum relay fee of %s to prevent stuck transactions)"),
                                       "-maxtxfee", gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
        }
    }
    if (gArgs.IsArgSet("-minstakesplit")) {
        CAmount n = 0;
        if (ParseMoney(gArgs.GetArg("-minstakesplit", ""), n) && n > 0)
            CWallet::minStakeSplitThreshold = n;
        else
            return UIError(AmountErrMsg("minstakesplit", gArgs.GetArg("-minstakesplit", "")));
    }
    nTxConfirmTarget = gArgs.GetArg("-txconfirmtarget", 1);
    bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
    bdisableSystemnotifications = gArgs.GetBoolArg("-disablesystemnotifications", false);

    return true;
}

bool WalletVerify()
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        return true;
    }

    uiInterface.InitMessage(_("Verifying wallet(s)..."));

    // Keep track of each wallet absolute path to detect duplicates.
    std::set<fs::path> wallet_paths;

    for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
        if (fs::path(walletFile).filename() != walletFile) {
            return UIError(strprintf(_("Error loading wallet %s. %s parameter must only specify a filename (not a path)."), walletFile, "-wallet"));
        }
        if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) {
            return UIError(strprintf(_("Error loading wallet %s. Invalid characters in %s filename."), walletFile, "-wallet"));
        }

        fs::path wallet_path = fs::absolute(walletFile, GetDataDir());

        if (fs::exists(wallet_path) && (!fs::is_regular_file(wallet_path) || fs::is_symlink(wallet_path))) {
            return UIError(strprintf(_("Error loading wallet %s. %s filename must be a regular file."), walletFile, "-wallet"));
        }

        if (!wallet_paths.insert(wallet_path).second) {
            return UIError(strprintf(_("Error loading wallet %s. Duplicate %s filename specified."), walletFile, "-wallet"));
        }

        std::string strError;
        if (!CWalletDB::VerifyEnvironment(walletFile, GetDataDir().string(), strError)) {
            return UIError(strError);
        }

        if (gArgs.GetBoolArg("-salvagewallet", false)) {
            // Recover readable keypairs:
            CWallet dummyWallet;
            std::string backup_filename;
            // Even if we don't use this lock in this function, we want to preserve
            // lock order in LoadToWallet if query of chain state is needed to know
            // tx status. If lock can't be taken, tx confirmation status may be not
            // reliable.
            LOCK(cs_main);
            if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter, backup_filename)) {
                return false;
            }
        }

        std::string strWarning;
        bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetDataDir().string(), strWarning, strError);
        if (!strWarning.empty()) {
            UIWarning(strWarning);
        }
        if (!dbV) {
            return UIError(strError);
        }
    }

    return true;
}

bool InitLoadWallet()
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        LogPrintf("Wallet disabled!\n");
        return true;
    }

    for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
        // automatic backups
        std::string strWarning, strError;
        if(!AutoBackupWallet(walletFile, strWarning, strError)) {
            if (!strWarning.empty()) {
                UIWarning(strprintf("%s: %s", walletFile, strWarning));
            }
            if (!strError.empty()) {
                return UIError(strprintf("%s: %s", walletFile, strError));
            }
        }

        bool fFirstRun;
        CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile, fFirstRun);
        if (!pwallet) {
            return false;
        }
        vpwallets.emplace_back(pwallet);

        if (fFirstRun) {
            // Initial backup
            if (!AutoBackupWallet(walletFile, strWarning, strError)) {
                LogPrintf("Initial auto-backup failed for wallet %s, error: %s, warning: %s\n",
                          pwallet->GetName(), (strError.empty() ? "no error" : strError),
                          (strWarning.empty() ? "no warning" : strWarning));
            }
        }
    }

    return true;
}
<commit_msg>wallet: remove not longer available "-printcoinstake" init flag.<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2017 The Bitcoin Core developers
// Copyright (c) 2021 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "wallet/init.h"

#include "guiinterfaceutil.h"
#include "net.h"
#include "util/system.h"
#include "utilmoneystr.h"
#include "validation.h"
#include "wallet/wallet.h"

std::string GetWalletHelpString(bool showDebug)
{
    std::string strUsage = HelpMessageGroup(_("Wallet options:"));
    strUsage += HelpMessageOpt("-backuppath=<dir|file>", _("Specify custom backup path to add a copy of any wallet backup. If set as dir, every backup generates a timestamped file. If set as file, will rewrite to that file every backup."));
    strUsage += HelpMessageOpt("-createwalletbackups=<n>", strprintf(_("Number of automatic wallet backups (default: %d)"), DEFAULT_CREATEWALLETBACKUPS));
    strUsage += HelpMessageOpt("-custombackupthreshold=<n>", strprintf(_("Number of custom location backups to retain (default: %d)"), DEFAULT_CUSTOMBACKUPTHRESHOLD));
    strUsage += HelpMessageOpt("-disablewallet", strprintf(_("Do not load the wallet and disable wallet RPC calls (default: %u)"), DEFAULT_DISABLE_WALLET));
    strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
    strUsage += HelpMessageOpt("-legacywallet", _("On first run, create a legacy wallet instead of a HD wallet"));
    strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s)"), FormatMoney(maxTxFee)));
    strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"), CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK())));
    strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
    strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup"));
    strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet file") + " " + _("on startup"));
    strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
    strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), 1));
    strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup"));
    strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
    strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
    strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
        " " + _("(1 = keep tx meta data e.g. payment request information, 2 = drop tx meta data)"));
    strUsage += HelpMessageGroup(_("Mining/Staking options:"));
    strUsage += HelpMessageOpt("-coldstaking=<n>", strprintf(_("Enable cold staking functionality (0-1, default: %u). Disabled if staking=0"), DEFAULT_COLDSTAKING));
    strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), DEFAULT_GENERATE));
    strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_PROCLIMIT));
    strUsage += HelpMessageOpt("-minstakesplit=<amt>", strprintf(_("Minimum positive amount (in PIV) allowed by GUI and RPC for the stake split threshold (default: %s)"), FormatMoney(DEFAULT_MIN_STAKE_SPLIT_THRESHOLD)));
    strUsage += HelpMessageOpt("-staking=<n>", strprintf(_("Enable staking functionality (0-1, default: %u)"), DEFAULT_STAKING));
    if (showDebug) {
        strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
        strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf(_("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)"), DEFAULT_WALLET_DBLOGSIZE));
        strUsage += HelpMessageOpt("-flushwallet", strprintf(_("Run a thread to flush wallet periodically (default: %u)"), DEFAULT_FLUSHWALLET));
        strUsage += HelpMessageOpt("-privdb", strprintf(_("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)"), DEFAULT_WALLET_PRIVDB));
    }

    return strUsage;
}

bool WalletParameterInteraction()
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        return true;
    }

    if (gArgs.GetBoolArg("-sysperms", false)) {
        return UIError(strprintf(_("%s is not allowed in combination with enabled wallet functionality"), "-sysperms"));
    }

    gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);
    const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;

    if (gArgs.GetBoolArg("-salvagewallet", false)) {
        if (is_multiwallet) {
            return UIError(strprintf(_("%s is only allowed with a single wallet file"), "-salvagewallet"));
        }
        // Rewrite just private keys: rescan to find transactions
        if (gArgs.SoftSetBoolArg("-rescan", true)) {
            LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
        }
    }

    bool zapwallettxes = gArgs.GetBoolArg("-zapwallettxes", false);
    // -zapwallettxes implies dropping the mempool on startup
    if (zapwallettxes && gArgs.SoftSetBoolArg("-persistmempool", false)) {
        LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
    }

    // -zapwallettxes implies a rescan
    if (zapwallettxes) {
        if (is_multiwallet) {
            return UIError(strprintf(_("%s is only allowed with a single wallet file"), "-zapwallettxes"));
        }
        if (gArgs.SoftSetBoolArg("-rescan", true)) {
            LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
        }
    }

    if (is_multiwallet) {
        if (gArgs.GetBoolArg("-upgradewallet", false)) {
            return UIError(strprintf(_("%s is only allowed with a single wallet file"), "-upgradewallet"));
        }
    }

    if (gArgs.IsArgSet("-mintxfee")) {
        CAmount n = 0;
        if (ParseMoney(gArgs.GetArg("-mintxfee", ""), n) && n > 0)
            CWallet::minTxFee = CFeeRate(n);
        else
            return UIError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")));
    }
    if (gArgs.IsArgSet("-paytxfee")) {
        CAmount nFeePerK = 0;
        if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK))
            return UIError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")));
        if (nFeePerK > nHighTransactionFeeWarning)
            UIWarning(strprintf(_("Warning: %s is set very high! This is the transaction fee you will pay if you send a transaction."), "-paytxfee"));
        payTxFee = CFeeRate(nFeePerK, 1000);
        if (payTxFee < ::minRelayTxFee) {
            return UIError(strprintf(_("Invalid amount for %s: '%s' (must be at least %s)"), "-paytxfee",
                                       gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
        }
    }
    if (gArgs.IsArgSet("-maxtxfee")) {
        CAmount nMaxFee = 0;
        if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
            return UIError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
        if (nMaxFee > nHighTransactionMaxFeeWarning)
            UIWarning(strprintf(_("Warning: %s is set very high! Fees this large could be paid on a single transaction."), "-maxtxfee"));
        maxTxFee = nMaxFee;
        if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee) {
            return UIError(strprintf(_("Invalid amount for %s: '%s' (must be at least the minimum relay fee of %s to prevent stuck transactions)"),
                                       "-maxtxfee", gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
        }
    }
    if (gArgs.IsArgSet("-minstakesplit")) {
        CAmount n = 0;
        if (ParseMoney(gArgs.GetArg("-minstakesplit", ""), n) && n > 0)
            CWallet::minStakeSplitThreshold = n;
        else
            return UIError(AmountErrMsg("minstakesplit", gArgs.GetArg("-minstakesplit", "")));
    }
    nTxConfirmTarget = gArgs.GetArg("-txconfirmtarget", 1);
    bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
    bdisableSystemnotifications = gArgs.GetBoolArg("-disablesystemnotifications", false);

    return true;
}

bool WalletVerify()
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        return true;
    }

    uiInterface.InitMessage(_("Verifying wallet(s)..."));

    // Keep track of each wallet absolute path to detect duplicates.
    std::set<fs::path> wallet_paths;

    for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
        if (fs::path(walletFile).filename() != walletFile) {
            return UIError(strprintf(_("Error loading wallet %s. %s parameter must only specify a filename (not a path)."), walletFile, "-wallet"));
        }
        if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) {
            return UIError(strprintf(_("Error loading wallet %s. Invalid characters in %s filename."), walletFile, "-wallet"));
        }

        fs::path wallet_path = fs::absolute(walletFile, GetDataDir());

        if (fs::exists(wallet_path) && (!fs::is_regular_file(wallet_path) || fs::is_symlink(wallet_path))) {
            return UIError(strprintf(_("Error loading wallet %s. %s filename must be a regular file."), walletFile, "-wallet"));
        }

        if (!wallet_paths.insert(wallet_path).second) {
            return UIError(strprintf(_("Error loading wallet %s. Duplicate %s filename specified."), walletFile, "-wallet"));
        }

        std::string strError;
        if (!CWalletDB::VerifyEnvironment(walletFile, GetDataDir().string(), strError)) {
            return UIError(strError);
        }

        if (gArgs.GetBoolArg("-salvagewallet", false)) {
            // Recover readable keypairs:
            CWallet dummyWallet;
            std::string backup_filename;
            // Even if we don't use this lock in this function, we want to preserve
            // lock order in LoadToWallet if query of chain state is needed to know
            // tx status. If lock can't be taken, tx confirmation status may be not
            // reliable.
            LOCK(cs_main);
            if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter, backup_filename)) {
                return false;
            }
        }

        std::string strWarning;
        bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetDataDir().string(), strWarning, strError);
        if (!strWarning.empty()) {
            UIWarning(strWarning);
        }
        if (!dbV) {
            return UIError(strError);
        }
    }

    return true;
}

bool InitLoadWallet()
{
    if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
        LogPrintf("Wallet disabled!\n");
        return true;
    }

    for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
        // automatic backups
        std::string strWarning, strError;
        if(!AutoBackupWallet(walletFile, strWarning, strError)) {
            if (!strWarning.empty()) {
                UIWarning(strprintf("%s: %s", walletFile, strWarning));
            }
            if (!strError.empty()) {
                return UIError(strprintf("%s: %s", walletFile, strError));
            }
        }

        bool fFirstRun;
        CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile, fFirstRun);
        if (!pwallet) {
            return false;
        }
        vpwallets.emplace_back(pwallet);

        if (fFirstRun) {
            // Initial backup
            if (!AutoBackupWallet(walletFile, strWarning, strError)) {
                LogPrintf("Initial auto-backup failed for wallet %s, error: %s, warning: %s\n",
                          pwallet->GetName(), (strError.empty() ? "no error" : strError),
                          (strWarning.empty() ? "no warning" : strWarning));
            }
        }
    }

    return true;
}
<|endoftext|>


<commit_before><commit_msg>416 - LED Test<commit_after><|endoftext|>


<commit_before>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2013-2014 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef UNITTEST__UNIT_TEST_HPP__INCLUDED
#define UNITTEST__UNIT_TEST_HPP__INCLUDED

// C++ include.
#include <string>
#include <map>
#include <list>
#include <memory>
#include <stdexcept>
#include <sstream>
#include <exception>
#include <iostream>

//
// Test
//

//! Test.
class Test {
public:
	explicit Test( const std::string & name );

	virtual ~Test();

	//! \return name of the test.
	const std::string & name() const;

	//! Run test.
	void runTest();

	//! Test body.
	virtual void testBody() = 0;

private:
	//! Name of the test.
	std::string m_name;
}; // class Test

//
// TestInfo
//

//! Test info.
class TestInfo final {
public:
	TestInfo( const std::string & testCaseName,
		const std::shared_ptr< Test > & test );
}; // class TestInfo

//
// TestCase
//

//! Test case.
class TestCase final {
public:
	explicit TestCase( const std::string & name );

	~TestCase();

	//! \return Name of the test case.
	const std::string & name() const;

	//! Add new test.
	void addTest( const std::shared_ptr< Test > & test );

	//! Run all tests.
	void runAllTests();

private:
	TestCase( const TestCase & );

	TestCase & operator= ( const TestCase & );

private:
	//! Tests.
	std::list< std::shared_ptr< Test > > m_tests;
	//! Test case name.
	std::string m_name;
}; // class TestCase

//
// UnitTest
//

//! Unit test.
class UnitTest final {
private:
	UnitTest();

	~UnitTest();

	UnitTest( const UnitTest & );

	UnitTest & operator= ( const UnitTest & );

public:
	//! \return Instance of the singleton of this class.
	static UnitTest & instance();

	//! \return Test case for the given \arg name.
	TestCase * createTestCaseIfNotExists( const std::string & name );

	//! Run all tests.
	void runAllTests();

private:
	//! Test cases.
	std::map< std::string, std::shared_ptr< TestCase > > m_testCases;
}; // class UnitTest

//
// TEST
//

#define TEST( TestCaseName, TestName ) \
class TestName##Class final \
	:	public Test \
{ \
public: \
	TestName##Class() \
		:	Test( #TestName ) \
	{ \
	} \
 \
	~TestName##Class() \
	{ \
	} \
 \
	void testBody(); \
 \
	static TestInfo testInfo; \
}; \
 \
TestInfo TestName##Class::testInfo = \
	TestInfo( #TestCaseName, std::shared_ptr< Test > ( \
		new TestName##Class() ) ); \
void TestName##Class::testBody()

//
// RUN_ALL_TESTS
//

#define RUN_ALL_TESTS() \
	UnitTest::instance().runAllTests();

//
// CHECK_CONDITION
//

#define CHECK_CONDITION( Condition ) \
	if( !(Condition) ) \
	{ \
		std::ostringstream stream; \
		stream << "     file: \"" << __FILE__ \
			<< "\" line: " << __LINE__ << "\n" \
			<< "     ( " << #Condition << " ) [FAILED]"; \
 \
		throw std::runtime_error( stream.str() ); \
	}

//
// Test
//

inline
Test::Test( const std::string & name )
	:	m_name( name )
{
}

inline
Test::~Test()
{
}

inline const std::string &
Test::name() const
{
	return m_name;
}

inline void
Test::runTest()
{
	try {
		testBody();
	}
	catch( const std::exception & x )
	{
		std::cout << "[FAILED]" << std::endl;
		std::cout << x.what();

		exit( 1 );
	}
	catch( ... )
	{
		std::cout << "[FAILED]" << std::endl;
		std::cout << "  Unexpected exception.";

		exit( 1 );
	}
}

//
// TestInfo
//

inline
TestInfo::TestInfo( const std::string & testCaseName,
	const std::shared_ptr< Test > & test )
{
	UnitTest::instance().createTestCaseIfNotExists( testCaseName )->
		addTest( test );
}

//
// TestCase
//

inline
TestCase::TestCase( const std::string & name )
	:	m_name( name )
{
}

inline
TestCase::~TestCase()
{
}

inline const std::string &
TestCase::name() const
{
	return m_name;
}

inline void
TestCase::addTest( const std::shared_ptr< Test > & test )
{
	m_tests.push_back( test );
}

inline void
TestCase::runAllTests()
{
	std::cout << "Test case \"" << name() << "\" started..." << std::endl;

	size_t i = 1;

	for( auto & t : m_tests )
	{
		std::cout << " ";

		std::cout.width( 2 );
		std::cout.fill( '0' );

		std::cout << i << ". \""
			<< t->name() << "\"... ";

		t->runTest();

		std::cout << "[OK]" << std::endl;

		++i;
	}

	std::cout << "Test case \"" << name() << "\" finished..." << std::endl;
}

//
// UnitTest
//

inline
UnitTest::UnitTest()
{
}

inline
UnitTest::~UnitTest()
{
}

inline UnitTest &
UnitTest::instance()
{
	static UnitTest unit;

	return unit;
}

inline TestCase *
UnitTest::createTestCaseIfNotExists( const std::string & name )
{
	auto it = m_testCases.find( name );

	if( it == m_testCases.end() )
	{
		auto p = m_testCases.insert(
			std::pair< std::string, std::shared_ptr< TestCase > >( name,
				std::shared_ptr< TestCase > ( new TestCase( name ) ) ) );

		it = p.first;
	}

	return it->second.get();
}

inline void
UnitTest::runAllTests()
{
	for( auto & p : m_testCases )
		p.second->runAllTests();
}

#endif // UNITTEST__UNIT_TEST_HPP__INCLUDED
<commit_msg>Small modifications in UnitTest library.<commit_after>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2013-2014 Igor Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef UNITTEST__UNIT_TEST_HPP__INCLUDED
#define UNITTEST__UNIT_TEST_HPP__INCLUDED

// C++ include.
#include <string>
#include <map>
#include <list>
#include <memory>
#include <stdexcept>
#include <sstream>
#include <exception>
#include <iostream>

//
// Test
//

//! Test.
class Test {
public:
	explicit Test( const std::string & name );

	virtual ~Test();

	//! \return name of the test.
	const std::string & name() const;

	//! Run test.
	void runTest();

	//! Test body.
	virtual void testBody() = 0;

private:
	//! Name of the test.
	std::string m_name;
}; // class Test

//
// TestInfo
//

//! Test info.
class TestInfo final {
public:
	TestInfo( const std::string & testCaseName,
		std::shared_ptr< Test > test );
}; // class TestInfo

//
// TestCase
//

//! Test case.
class TestCase final {
public:
	explicit TestCase( const std::string & name );

	~TestCase();

	//! \return Name of the test case.
	const std::string & name() const;

	//! Add new test.
	void addTest( std::shared_ptr< Test > test );

	//! Run all tests.
	void runAllTests();

private:
	TestCase( const TestCase & );

	TestCase & operator= ( const TestCase & );

private:
	//! Tests.
	std::list< std::shared_ptr< Test > > m_tests;
	//! Test case name.
	std::string m_name;
}; // class TestCase

//
// UnitTest
//

//! Unit test.
class UnitTest final {
private:
	UnitTest();

	~UnitTest();

	UnitTest( const UnitTest & );

	UnitTest & operator= ( const UnitTest & );

public:
	//! \return Instance of the singleton of this class.
	static UnitTest & instance();

	//! \return Test case for the given \arg name.
	TestCase * createTestCaseIfNotExists( const std::string & name );

	//! Run all tests.
	void runAllTests();

private:
	//! Test cases.
	std::map< std::string, std::shared_ptr< TestCase > > m_testCases;
}; // class UnitTest

//
// TEST
//

#define TEST( TestCaseName, TestName ) \
class TestName##Class final \
	:	public Test \
{ \
public: \
	TestName##Class() \
		:	Test( #TestName ) \
	{ \
	} \
 \
	~TestName##Class() \
	{ \
	} \
 \
	void testBody(); \
 \
	static TestInfo testInfo; \
}; \
 \
TestInfo TestName##Class::testInfo = \
	TestInfo( #TestCaseName, std::make_shared< TestName##Class > () ); \
void TestName##Class::testBody()

//
// RUN_ALL_TESTS
//

#define RUN_ALL_TESTS() \
	UnitTest::instance().runAllTests();

//
// CHECK_CONDITION
//

#define CHECK_CONDITION( Condition ) \
	if( !(Condition) ) \
	{ \
		std::ostringstream stream; \
		stream << "     file: \"" << __FILE__ \
			<< "\" line: " << __LINE__ << "\n" \
			<< "     ( " << #Condition << " ) [FAILED]"; \
 \
		throw std::runtime_error( stream.str() ); \
	}

//
// Test
//

inline
Test::Test( const std::string & name )
	:	m_name( name )
{
}

inline
Test::~Test()
{
}

inline const std::string &
Test::name() const
{
	return m_name;
}

inline void
Test::runTest()
{
	try {
		testBody();
	}
	catch( const std::exception & x )
	{
		std::cout << "[FAILED]" << std::endl;
		std::cout << x.what();

		exit( 1 );
	}
	catch( ... )
	{
		std::cout << "[FAILED]" << std::endl;
		std::cout << "  Unexpected exception.";

		exit( 1 );
	}
}

//
// TestInfo
//

inline
TestInfo::TestInfo( const std::string & testCaseName,
	std::shared_ptr< Test > test )
{
	UnitTest::instance().createTestCaseIfNotExists( testCaseName )->
		addTest( test );
}

//
// TestCase
//

inline
TestCase::TestCase( const std::string & name )
	:	m_name( name )
{
}

inline
TestCase::~TestCase()
{
}

inline const std::string &
TestCase::name() const
{
	return m_name;
}

inline void
TestCase::addTest( std::shared_ptr< Test > test )
{
	m_tests.push_back( test );
}

inline void
TestCase::runAllTests()
{
	std::cout << "Test case \"" << name() << "\" started..." << std::endl;

	size_t i = 1;

	for( auto & t : m_tests )
	{
		std::cout << " ";

		std::cout.width( 2 );
		std::cout.fill( '0' );

		std::cout << i << ". \""
			<< t->name() << "\"... ";

		t->runTest();

		std::cout << "[OK]" << std::endl;

		++i;
	}

	std::cout << "Test case \"" << name() << "\" finished..." << std::endl;
}

//
// UnitTest
//

inline
UnitTest::UnitTest()
{
}

inline
UnitTest::~UnitTest()
{
}

inline UnitTest &
UnitTest::instance()
{
	static UnitTest unit;

	return unit;
}

inline TestCase *
UnitTest::createTestCaseIfNotExists( const std::string & name )
{
	auto it = m_testCases.find( name );

	if( it == m_testCases.end() )
	{
		auto p = m_testCases.insert(
			std::pair< std::string, std::shared_ptr< TestCase > >( name,
				std::make_shared< TestCase > ( name ) ) );

		it = p.first;
	}

	return it->second.get();
}

inline void
UnitTest::runAllTests()
{
	for( auto & p : m_testCases )
		p.second->runAllTests();
}

#endif // UNITTEST__UNIT_TEST_HPP__INCLUDED
<|endoftext|>


<commit_before>/******************************************************************************
 **	Filename:    mf.c
 **	Purpose:     Micro-feature interface to flexible feature extractor.
 **	Author:      Dan Johnson
 **	History:     Thu May 24 09:08:38 1990, DSJ, Created.
 **
 **	(c) Copyright Hewlett-Packard Company, 1988.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 ******************************************************************************/
/*----------------------------------------------------------------------------
          Include Files and Type Defines
----------------------------------------------------------------------------*/
#include "mf.h"

#include "featdefs.h"
#include "mfdefs.h"
#include "mfx.h"

#include <math.h>

/*----------------------------------------------------------------------------
        Global Data Definitions and Declarations
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
              Private Code
----------------------------------------------------------------------------*/
/**
 * Call the old micro-feature extractor and then copy
 * the features into the new format.  Then deallocate the
 * old micro-features.
 * @param Blob	blob to extract micro-features from
 * @param bl_denorm currently unused
 * @param cn_denorm  control parameter to feature extractor.
 * @param fx_info currently unused
 * @return Micro-features for Blob.
 * @note Exceptions: none
 * @note History: Wed May 23 18:06:38 1990, DSJ, Created.
 */
FEATURE_SET ExtractMicros(TBLOB *Blob, const DENORM& bl_denorm,
                          const DENORM& cn_denorm,
                          const INT_FX_RESULT_STRUCT& fx_info) {
  int NumFeatures;
  MICROFEATURES Features, OldFeatures;
  FEATURE_SET FeatureSet;
  FEATURE Feature;
  MICROFEATURE OldFeature;

  OldFeatures = BlobMicroFeatures(Blob, cn_denorm);
  if (OldFeatures == NULL)
    return NULL;
  NumFeatures = count (OldFeatures);
  FeatureSet = NewFeatureSet (NumFeatures);

  Features = OldFeatures;
  iterate(Features) {
    OldFeature = (MICROFEATURE) first_node (Features);
    Feature = NewFeature (&MicroFeatureDesc);
    Feature->Params[MFDirection] = OldFeature[ORIENTATION];
    Feature->Params[MFXPosition] = OldFeature[XPOSITION];
    Feature->Params[MFYPosition] = OldFeature[YPOSITION];
    Feature->Params[MFLength] = OldFeature[MFLENGTH];

    // Bulge features are deprecated and should not be used.  Set to 0.
    Feature->Params[MFBulge1] = 0.0f;
    Feature->Params[MFBulge2] = 0.0f;

#ifndef _WIN32
    // Assert that feature parameters are well defined.
    int i;
    for (i = 0; i < Feature->Type->NumParams; i++) {
      ASSERT_HOST(!isnan(Feature->Params[i]));
    }
#endif

    AddFeature(FeatureSet, Feature);
  }
  FreeMicroFeatures(OldFeatures);
  return FeatureSet;
}                                /* ExtractMicros */
<commit_msg>What the...? Git's merge failed hard.<commit_after>/******************************************************************************
 **	Filename:    mf.c
 **	Purpose:     Micro-feature interface to flexible feature extractor.
 **	Author:      Dan Johnson
 **	History:     Thu May 24 09:08:38 1990, DSJ, Created.
 **
 **	(c) Copyright Hewlett-Packard Company, 1988.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 ******************************************************************************/
/*----------------------------------------------------------------------------
          Include Files and Type Defines
----------------------------------------------------------------------------*/
#include "mf.h"

#include "featdefs.h"
#include "mfdefs.h"
#include "mfx.h"

#include <math.h>

/*----------------------------------------------------------------------------
        Global Data Definitions and Declarations
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
              Private Code
----------------------------------------------------------------------------*/
/**
 * Call the old micro-feature extractor and then copy
 * the features into the new format.  Then deallocate the
 * old micro-features.
 * @param Blob	blob to extract micro-features from
 * @param cn_denorm  control parameter to feature extractor.
 * @return Micro-features for Blob.
 * @note Exceptions: none
 * @note History: Wed May 23 18:06:38 1990, DSJ, Created.
 */
FEATURE_SET ExtractMicros(TBLOB* Blob, const DENORM& cn_denorm) {
  int NumFeatures;
  MICROFEATURES Features, OldFeatures;
  FEATURE_SET FeatureSet;
  FEATURE Feature;
  MICROFEATURE OldFeature;

  OldFeatures = BlobMicroFeatures(Blob, cn_denorm);
  if (OldFeatures == NULL)
    return NULL;
  NumFeatures = count (OldFeatures);
  FeatureSet = NewFeatureSet (NumFeatures);

  Features = OldFeatures;
  iterate(Features) {
    OldFeature = (MICROFEATURE) first_node (Features);
    Feature = NewFeature (&MicroFeatureDesc);
    Feature->Params[MFDirection] = OldFeature[ORIENTATION];
    Feature->Params[MFXPosition] = OldFeature[XPOSITION];
    Feature->Params[MFYPosition] = OldFeature[YPOSITION];
    Feature->Params[MFLength] = OldFeature[MFLENGTH];

    // Bulge features are deprecated and should not be used.  Set to 0.
    Feature->Params[MFBulge1] = 0.0f;
    Feature->Params[MFBulge2] = 0.0f;

#ifndef _WIN32
    // Assert that feature parameters are well defined.
    int i;
    for (i = 0; i < Feature->Type->NumParams; i++) {
      ASSERT_HOST(!isnan(Feature->Params[i]));
    }
#endif

    AddFeature(FeatureSet, Feature);
  }
  FreeMicroFeatures(OldFeatures);
  return FeatureSet;
}                                /* ExtractMicros */
<|endoftext|>


<commit_before>#include "game.hpp"
#include "component_drawable.hpp"
#include "component_position.hpp"
#include "component_player.hpp"
#include "component_light.hpp"
#include "component_moveable.hpp"
#include "strapon/resource_manager/resource_manager.hpp"

#include "entityx/entityx.h"
#include <glm/vec2.hpp>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

class DrawSystem : public entityx::System<DrawSystem>, public entityx::Receiver<DrawSystem>
{
public:
    DrawSystem(Game *game) : m_game(game) {
        int w, h;
        SDL_RenderGetLogicalSize(game->get_renderer(), &w, &h);
        m_camera = SDL_Rect{0, 0, w, h};
        m_drawtex = SDL_CreateTexture(game->get_renderer(), SDL_PIXELTYPE_UNKNOWN, SDL_TEXTUREACCESS_TARGET, game->get_worldsize().w, game->get_worldsize().h);
        m_lighttex = SDL_CreateTexture(game->get_renderer(), SDL_PIXELTYPE_UNKNOWN, SDL_TEXTUREACCESS_TARGET, game->get_worldsize().w, game->get_worldsize().h);
    }

    void configure(entityx::EventManager &event_manager)
    {
		event_manager.subscribe<PlayerInstructionLight>(*this);
	}

    ~DrawSystem() {
        SDL_DestroyTexture(m_drawtex);
        SDL_DestroyTexture(m_lighttex);
    }

    void update(entityx::EntityManager &es, entityx::EventManager &events, entityx::TimeDelta dt) override {
        // Change to render into rendertexture for now
        SDL_SetRenderTarget(m_game->get_renderer(), m_drawtex);
        SDL_SetRenderDrawColor(m_game->get_renderer(), 0, 100, 200, 255);
        SDL_RenderClear(m_game->get_renderer());

        entityx::ComponentHandle<Drawable> drawable;
        entityx::ComponentHandle<Position> position;
        entityx::ComponentHandle<Player> player;

        for (entityx::Entity entity : es.entities_with_components(drawable, position))
        {

            (void)entity;

            SDL_Rect dest;
            float direction_offset = -28;
            SDL_RendererFlip flip = SDL_FLIP_NONE;
            entityx::ComponentHandle<Moveable> moveable = entity.component<Moveable>();
            entityx::ComponentHandle<Light> light = entity.component<Light>();

            dest.x = position->get_position()[0];
            dest.y = position->get_position()[1];
            dest.w = drawable->get_width();
            dest.h = drawable->get_height();
            // std::cout << position->get_position()[0] << std::endl;
            // std::cout << position->get_position()[1] << std::endl;
            // std::cout << drawable->get_width() << std::endl;
            // std::cout << drawable->get_height() << std::endl;

            if(light)
            {
                if(moveable->get_velocity().x < 0)
                {
                    flip = SDL_FLIP_NONE;
                }
                if(moveable->get_velocity().x > 0)
                {
                    flip = SDL_FLIP_HORIZONTAL;
                    direction_offset *= -1;
                }

                m_light_rect.w = light->get_radius();
                m_light_rect.h = m_light_rect.w;

                m_light_rect.x = position->get_position().x + direction_offset + drawable->get_width()/2 - light->get_radius()/2;
                m_light_rect.y = position->get_position().y + -4 + drawable->get_height()/2 - light->get_radius()/2;

                light->set_radius(light->get_radius() * 0.95);
                if(light->get_radius() < 10)
                {
                    light->set_radius(50);
                }
                if(light->get_radius() > 400)
                {
                    light->set_radius(400);
                }

                if(moveable->get_velocity().x < 0)
                {
                    flip = SDL_FLIP_NONE;
                }
                else
                {
                    flip = SDL_FLIP_HORIZONTAL;
                }
                m_camera.x = position->get_position()[0] - m_camera.w/2;
                m_camera.y = position->get_position()[1] - m_camera.h/2;

                if (m_camera.x < 0)
                    m_camera.x = 0;
                else if (m_camera.x > m_game->get_worldsize().w - m_camera.w)
                    m_camera.x = m_game->get_worldsize().w - m_camera.w;

                if (m_camera.y < 0)
                    m_camera.y = 0;
                else if (m_camera.y > m_game->get_worldsize().h - m_camera.h)
                    m_camera.y = m_game->get_worldsize().h - m_camera.h;
            }

            SDL_RenderCopyEx(m_game->get_renderer(),
                               m_game->get_res_manager().get_texture(drawable->get_texture_key()),
                               NULL,
                               &dest,0,NULL,flip);
        }
        SDL_SetRenderTarget(m_game->get_renderer(), m_lighttex);
        SDL_SetRenderDrawColor(m_game->get_renderer(), 50, 50, 50, 255);
        SDL_RenderClear(m_game->get_renderer());
        SDL_SetTextureBlendMode(m_game->get_res_manager().get_texture("gradient"), SDL_BLENDMODE_ADD);

        SDL_RenderCopy(m_game->get_renderer(), m_game->get_res_manager().get_texture("gradient"),
                       nullptr, &m_light_rect);
        SDL_SetTextureBlendMode(m_lighttex, SDL_BLENDMODE_MOD);
        SDL_SetRenderTarget(m_game->get_renderer(), m_drawtex);
        SDL_RenderCopy(m_game->get_renderer(), m_lighttex, nullptr, nullptr);

        // Render to final window
        SDL_SetRenderTarget(m_game->get_renderer(), nullptr);
        SDL_RenderCopy(m_game->get_renderer(), m_drawtex, &m_camera, nullptr);

        auto score = std::to_string(m_game->get_score());
	    SDL_Color color{200, 100, 0, 200};
	    SDL_Rect font_rect{50,50,200,50};
	    SDL_Surface *font_surf = TTF_RenderText_Blended(m_game->get_res_manager().get_font("font20"), score.c_str(), color);
	    SDL_Texture *font_tex = SDL_CreateTextureFromSurface(m_game->get_renderer(), font_surf);
	    SDL_RenderCopy(m_game->get_renderer(), font_tex, nullptr, &font_rect);
	    SDL_FreeSurface(font_surf);
	    SDL_DestroyTexture(font_tex);

        SDL_RenderPresent(m_game->get_renderer());
    }
    void receive(const PlayerInstructionLight &player_instruction_light)
    {
		auto copy = player_instruction_light;
		entityx::ComponentHandle<Light> light = copy.m_entity.component<Light>();
		light->set_radius((light->get_radius()) * 1.1);
	}

private:
    Game *m_game;
    SDL_Rect m_camera;
    SDL_Texture *m_drawtex;
    SDL_Texture *m_lighttex;
    SDL_Rect m_light_rect{0,0,0,0};
};
<commit_msg>Override fix<commit_after>#include "game.hpp"
#include "component_drawable.hpp"
#include "component_position.hpp"
#include "component_player.hpp"
#include "component_light.hpp"
#include "component_moveable.hpp"
#include "strapon/resource_manager/resource_manager.hpp"

#include "entityx/entityx.h"
#include <glm/vec2.hpp>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

class DrawSystem : public entityx::System<DrawSystem>, public entityx::Receiver<DrawSystem>
{
public:
    DrawSystem(Game *game) : m_game(game) {
        int w, h;
        SDL_RenderGetLogicalSize(game->get_renderer(), &w, &h);
        m_camera = SDL_Rect{0, 0, w, h};
        m_drawtex = SDL_CreateTexture(game->get_renderer(), SDL_PIXELTYPE_UNKNOWN, SDL_TEXTUREACCESS_TARGET, game->get_worldsize().w, game->get_worldsize().h);
        m_lighttex = SDL_CreateTexture(game->get_renderer(), SDL_PIXELTYPE_UNKNOWN, SDL_TEXTUREACCESS_TARGET, game->get_worldsize().w, game->get_worldsize().h);
    }

    void configure(entityx::EventManager &event_manager) override
    {
		event_manager.subscribe<PlayerInstructionLight>(*this);
	}

    ~DrawSystem() {
        SDL_DestroyTexture(m_drawtex);
        SDL_DestroyTexture(m_lighttex);
    }

    void update(entityx::EntityManager &es, entityx::EventManager &events, entityx::TimeDelta dt) override {
        // Change to render into rendertexture for now
        SDL_SetRenderTarget(m_game->get_renderer(), m_drawtex);
        SDL_SetRenderDrawColor(m_game->get_renderer(), 0, 100, 200, 255);
        SDL_RenderClear(m_game->get_renderer());

        entityx::ComponentHandle<Drawable> drawable;
        entityx::ComponentHandle<Position> position;
        entityx::ComponentHandle<Player> player;

        for (entityx::Entity entity : es.entities_with_components(drawable, position))
        {

            (void)entity;

            SDL_Rect dest;
            float direction_offset = -28;
            SDL_RendererFlip flip = SDL_FLIP_NONE;
            entityx::ComponentHandle<Moveable> moveable = entity.component<Moveable>();
            entityx::ComponentHandle<Light> light = entity.component<Light>();

            dest.x = position->get_position()[0];
            dest.y = position->get_position()[1];
            dest.w = drawable->get_width();
            dest.h = drawable->get_height();
            // std::cout << position->get_position()[0] << std::endl;
            // std::cout << position->get_position()[1] << std::endl;
            // std::cout << drawable->get_width() << std::endl;
            // std::cout << drawable->get_height() << std::endl;

            if(light)
            {
                if(moveable->get_velocity().x < 0)
                {
                    flip = SDL_FLIP_NONE;
                }
                if(moveable->get_velocity().x > 0)
                {
                    flip = SDL_FLIP_HORIZONTAL;
                    direction_offset *= -1;
                }

                m_light_rect.w = light->get_radius();
                m_light_rect.h = m_light_rect.w;

                m_light_rect.x = position->get_position().x + direction_offset + drawable->get_width()/2 - light->get_radius()/2;
                m_light_rect.y = position->get_position().y + -4 + drawable->get_height()/2 - light->get_radius()/2;

                light->set_radius(light->get_radius() * 0.95);
                if(light->get_radius() < 10)
                {
                    light->set_radius(50);
                }
                if(light->get_radius() > 400)
                {
                    light->set_radius(400);
                }

                if(moveable->get_velocity().x < 0)
                {
                    flip = SDL_FLIP_NONE;
                }
                else
                {
                    flip = SDL_FLIP_HORIZONTAL;
                }
                m_camera.x = position->get_position()[0] - m_camera.w/2;
                m_camera.y = position->get_position()[1] - m_camera.h/2;

                if (m_camera.x < 0)
                    m_camera.x = 0;
                else if (m_camera.x > m_game->get_worldsize().w - m_camera.w)
                    m_camera.x = m_game->get_worldsize().w - m_camera.w;

                if (m_camera.y < 0)
                    m_camera.y = 0;
                else if (m_camera.y > m_game->get_worldsize().h - m_camera.h)
                    m_camera.y = m_game->get_worldsize().h - m_camera.h;
            }

            SDL_RenderCopyEx(m_game->get_renderer(),
                               m_game->get_res_manager().get_texture(drawable->get_texture_key()),
                               NULL,
                               &dest,0,NULL,flip);
        }
        SDL_SetRenderTarget(m_game->get_renderer(), m_lighttex);
        SDL_SetRenderDrawColor(m_game->get_renderer(), 50, 50, 50, 255);
        SDL_RenderClear(m_game->get_renderer());
        SDL_SetTextureBlendMode(m_game->get_res_manager().get_texture("gradient"), SDL_BLENDMODE_ADD);

        SDL_RenderCopy(m_game->get_renderer(), m_game->get_res_manager().get_texture("gradient"),
                       nullptr, &m_light_rect);
        SDL_SetTextureBlendMode(m_lighttex, SDL_BLENDMODE_MOD);
        SDL_SetRenderTarget(m_game->get_renderer(), m_drawtex);
        SDL_RenderCopy(m_game->get_renderer(), m_lighttex, nullptr, nullptr);

        // Render to final window
        SDL_SetRenderTarget(m_game->get_renderer(), nullptr);
        SDL_RenderCopy(m_game->get_renderer(), m_drawtex, &m_camera, nullptr);

        auto score = std::to_string(m_game->get_score());
	    SDL_Color color{200, 100, 0, 200};
	    SDL_Rect font_rect{50,50,200,50};
	    SDL_Surface *font_surf = TTF_RenderText_Blended(m_game->get_res_manager().get_font("font20"), score.c_str(), color);
	    SDL_Texture *font_tex = SDL_CreateTextureFromSurface(m_game->get_renderer(), font_surf);
	    SDL_RenderCopy(m_game->get_renderer(), font_tex, nullptr, &font_rect);
	    SDL_FreeSurface(font_surf);
	    SDL_DestroyTexture(font_tex);

        SDL_RenderPresent(m_game->get_renderer());
    }
    void receive(const PlayerInstructionLight &player_instruction_light)
    {
		auto copy = player_instruction_light;
		entityx::ComponentHandle<Light> light = copy.m_entity.component<Light>();
		light->set_radius((light->get_radius()) * 1.1);
	}

private:
    Game *m_game;
    SDL_Rect m_camera;
    SDL_Texture *m_drawtex;
    SDL_Texture *m_lighttex;
    SDL_Rect m_light_rect{0,0,0,0};
};
<|endoftext|>


<commit_before>#include <iostream>
#include "sorting.h"
#include "printarray.h"

#include <vector>
#include <cmath>
#include <random>
#include <functional>
#include <chrono>

double profileAverage_ms(const int *const data, const int N, const int avgN, void (*sort)(int * const, const int))
{
    int *array = new int[N];

    std::vector<double> diffs(avgN);
    //double avg = 0.0;

    for (int j = 0 ; j < avgN ; j++)
    {
        memcpy(array, data+j, N*sizeof(int));

        //PrintArray(array, N);

        auto start = std::chrono::steady_clock::now();
        (*sort)(array, N);
        auto stop  = std::chrono::steady_clock::now();

        //PrintArray(array, N);

        auto diff = stop - start;
        diffs[j] = std::chrono::duration <double, std::milli> (diff).count();
    }

    double avg = 0.0;
    for (int j = 0 ; j < avgN ; j++)
    {
        avg += diffs[j] / double(avgN);
    }
    double stddev = 0.0;
    for (int j = 0 ; j < avgN ; j++)
    {
        stddev += (diffs[j] - avg)*(diffs[j] - avg) / double(avgN);
    }
    stddev = std::sqrt(stddev);

    std::cout << N << ", " << avg << " +- " << stddev << " ms" << std::endl;

    delete[] array;

    return avg;
}

void profileSort(void (*sort)(int * const, const int))
{
    const int pow2min = 0;
    const int pow2max = 16;

    const int seed = 4;

    std::uniform_int_distribution<int> distribution(0, 99);
    std::mt19937 engine(seed); // Mersenne twister MT19937
    auto generator = std::bind(distribution, engine);

    // Allocate more than required; profileAverage() will copy the data
    // with an offset.
    int *data = new int[2 << (pow2max+1)];
    for (int i = 0 ; i < 2 << (pow2max+1) ; i++)
    {
        data[i] = generator();
    }

    //PrintArray(Ns.data(), Ns.size());

    for (int j = pow2min ; j <= pow2max ; j++)
    {
        const int N = 2 << j;
        profileAverage_ms(data, N, 6, sort);
        //std::cout << j << ", " << N << ", " << profileAverage_ms(data, N, 6, sort) << " ms" << std::endl;
    }

    delete[] data;
}

int main(int argc, char *argv[])
{
    std::cout << "main()" << std::endl;

    //profileSort(&sorting::simple::InsertionSort);
    profileSort(&sorting::efficient::Quicksort);
}
<commit_msg>Move function calling to own function<commit_after>#include <iostream>
#include "sorting.h"
#include "printarray.h"

#include <vector>
#include <cmath>
#include <random>
#include <functional>
#include <chrono>

double profileAverage_ms(const int *const data, const int N, const int avgN, void (*sort)(int * const, const int))
{
    int *array = new int[N];

    std::vector<double> diffs(avgN);
    //double avg = 0.0;

    for (int j = 0 ; j < avgN ; j++)
    {
        memcpy(array, data+j, N*sizeof(int));

        //PrintArray(array, N);

        auto start = std::chrono::steady_clock::now();
        (*sort)(array, N);
        auto stop  = std::chrono::steady_clock::now();

        //PrintArray(array, N);

        auto diff = stop - start;
        diffs[j] = std::chrono::duration <double, std::milli> (diff).count();
    }

    double avg = 0.0;
    for (int j = 0 ; j < avgN ; j++)
    {
        avg += diffs[j] / double(avgN);
    }
    double stddev = 0.0;
    for (int j = 0 ; j < avgN ; j++)
    {
        stddev += (diffs[j] - avg)*(diffs[j] - avg) / double(avgN);
    }
    stddev = std::sqrt(stddev);

    std::cout << N << ", " << avg << " +- " << stddev << " ms" << std::endl;

    delete[] array;

    return avg;
}

void profileSort(void (*sort)(int * const, const int))
{
    const int pow2min = 0;
    const int pow2max = 16;

    const int seed = 4;

    std::uniform_int_distribution<int> distribution(0, 99);
    std::mt19937 engine(seed); // Mersenne twister MT19937
    auto generator = std::bind(distribution, engine);

    // Allocate more than required; profileAverage() will copy the data
    // with an offset.
    int *data = new int[2 << (pow2max+1)];
    for (int i = 0 ; i < 2 << (pow2max+1) ; i++)
    {
        data[i] = generator();
    }

    //PrintArray(Ns.data(), Ns.size());

    for (int j = pow2min ; j <= pow2max ; j++)
    {
        const int N = 2 << j;
        profileAverage_ms(data, N, 6, sort);
        //std::cout << j << ", " << N << ", " << profileAverage_ms(data, N, 6, sort) << " ms" << std::endl;
    }

    delete[] data;
}

void generate_profiling_data()
{
    //profileSort(&sorting::simple::InsertionSort);
    profileSort(&sorting::efficient::Quicksort);
}

int main(int argc, char *argv[])
{
    std::cout << "main()" << std::endl;

    generate_profiling_data();
}
<|endoftext|>


<commit_before>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2006 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "dlgpreferences.h"
#include "dlglistindexedfiles.h"
#include "simplesearchgui.h"
#include "searchtabs.h"
#include "socketclient.h"
#include <QtGui/QListWidget>
#include <QtGui/QListWidgetItem>
#include <QtGui/QLineEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QStackedWidget>
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QFileDialog>
#include <QtGui/QComboBox>
#include <QtGui/QMenu>
#include <QtGui/QMenuBar>
#include <QtGui/QAction>
#include <QtCore/QString>
#include <QtCore/QDebug>
#include <QtCore/QCoreApplication>
#include <QtCore/QProcess>
#include <string>
#include <map>
#include <vector>
using namespace std;

SimpleSearchGui::SimpleSearchGui (QWidget * parent, Qt::WFlags flags)
    : QMainWindow (parent, flags)
{
    mainview = new QStackedWidget();

    QWidget* statuswidget = new QWidget();
    QVBoxLayout *statuslayout = new QVBoxLayout;
    statusview = new QLabel();
    statusview->setAlignment(Qt::AlignTop);
    statusview->setMargin(25);
    indexing = false;
    running = false;
    starting = true;
    indexeddirs = new QListWidget();
    adddir = new QPushButton("add directory");
    removedir = new QPushButton("remove directory");
    toggleindexing = new QPushButton("start indexing");
    toggledaemon = new QPushButton("stop daemon");
    statuslayout->addWidget(statusview);
    QHBoxLayout *hlayout = new QHBoxLayout;
    hlayout->addWidget(toggledaemon);
    hlayout->addWidget(toggleindexing);
    statuslayout->addLayout(hlayout);
/*    vector<string> backends = ClientInterface::getBackEnds();
    if (backends.size() > 1) {
        backendsList = new QComboBox();
        for (uint i = 0; i< backends.size(); ++i) {
            QString backend = backends[i].c_str();
            backendsList->insertItem(i, backend);
        }
        statuslayout->addWidget(backendsList);
    } else {*/
        backendsList = 0;
//    }
    statuslayout->addWidget(indexeddirs);
    hlayout = new QHBoxLayout;
    hlayout->addWidget(adddir);
    hlayout->addWidget(removedir);
    statuslayout->addLayout(hlayout);
    statuswidget->setLayout(statuslayout);

    tabs = new SearchTabs(&strigi);
    tabs->addTab("kde", "kde");
    tabs->addTab("msg", "mimetype:message/*");
    tabs->addTab("irc", "path:*konversation*log");
    tabs->addTab("mail", "mimetype:text/x-mail");
    tabs->addTab("audio", "mimetype:audio/*");
    tabs->addTab("other",
        "-kde -mimetype:message/* -mimetype:text/x-mail -mimetype:audio/*");
    tabs->addTab("all", "");
    mainview->addWidget(tabs);
    mainview->addWidget(statuswidget);
    mainview->setCurrentIndex(1);

    queryfield = new QLineEdit();
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(mainview);
    layout->addWidget(queryfield);

    centralview = new QWidget();
    centralview->setLayout(layout);
    setCentralWidget(centralview);

    createActions();
    createMenus();

    connect(queryfield, SIGNAL(textChanged(const QString&)),
        this, SLOT(query(const QString&)));
    connect(toggleindexing, SIGNAL(clicked()),
        this, SLOT(toggleIndexing()));
    connect(toggledaemon, SIGNAL(clicked()),
        this, SLOT(toggleDaemon()));
    connect(adddir, SIGNAL(clicked()),
        this, SLOT(addDirectory()));
    connect(removedir, SIGNAL(clicked()),
        this, SLOT(removeDirectory()));
    queryfield->setFocus(Qt::ActiveWindowFocusReason);

    socketfile = getenv("HOME");
    socketfile += "/.strigi/socket";

    connect (&strigi, SIGNAL (gotDaemonStatus( const QMap< QString, QString >& )), this, SLOT (updateStatus( const QMap< QString, QString >& )));
    connect (&strigi, SIGNAL (socketError(Qt4StrigiClient::Mode)), this, SLOT (socketError(Qt4StrigiClient::Mode)));

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), &strigi, SLOT(getDaemonStatus()));
    timer->start(2000);
    QMap<QString,QString> emptyMap;
    updateStatus(emptyMap);
}
void
SimpleSearchGui::createMenus() {
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(fileExitAct);

    editMenu = menuBar()->addMenu(tr("&Edit"));
    editMenu->addAction(editPreferenceAct);
    editMenu->addAction(editListIndexedFilesAct);
}
void
SimpleSearchGui::createActions() {
    fileExitAct = new QAction(tr("&Exit"), this);
    fileExitAct->setShortcut(tr("Ctrl+Q"));
    fileExitAct->setStatusTip(tr("Quit the program"));
    connect(fileExitAct, SIGNAL(triggered()), this, SLOT(close()));

    editPreferenceAct = new QAction(tr("Edit Preferences"), this);
    editPreferenceAct->setStatusTip(tr("Edit program preferences"));
    connect(editPreferenceAct, SIGNAL(triggered()), this, SLOT(editPreferences()));

    editListIndexedFilesAct = new QAction(tr("List indexed files"), this);
    editListIndexedFilesAct->setStatusTip(tr("Show files indexed by strigi"));
    connect(editListIndexedFilesAct, SIGNAL(triggered()), this, SLOT(editListIndexedFiles()));
}
void
SimpleSearchGui::query(const QString& item) {
    if (item.length()) {
        tabs->setQuery(item);
    }
    QString query = item.trimmed();
    if (query.length() == 0) {
        mainview->setCurrentIndex(1);
    } else {
        mainview->setCurrentIndex(0);
    }
}
void
SimpleSearchGui::updateStatus(const QMap< QString, QString >& s) {
    static bool first = true;
    static bool attemptedstart = false;
    if (!first && !statusview->isVisible()) return;
    first = false;
    QMap<QString, QString> status (s);
    if (status.size() == 0) {
        running = false;
        editListIndexedFilesAct->setEnabled(false);
        /*if (!attemptedstart) {
            status["Status"] = "Starting daemon";
            startDaemon();
            attemptedstart = true;
        } else {*/
            status["Status"] = "Daemon is not running";
        //}
    } else {
        attemptedstart = true;
        starting = false;
        running = true;
        editListIndexedFilesAct->setEnabled(true);
        if (indexeddirs->count() == 0) {
            updateDirectories();
        }
    }
    toggleindexing->setEnabled(running);
    adddir->setEnabled(running);
    removedir->setEnabled(running);
    queryfield->setEnabled(running);
    toggledaemon->setText((running)?"stop daemon":"start daemon");
    if (backendsList) {
        backendsList->setEnabled(!running);
    }
    bool idxng = status["Status"] == "indexing";
    if (idxng != indexing) {
        indexing = idxng;
        toggleindexing->setText((indexing)?"stop indexing":"start indexing");
    }

    QMap<QString,QString>::const_iterator i;
    QString text;
    for (i = status.begin(); i != status.end(); ++i) {
        text += i.key();
        text += ":\t";
        text += i.value();
        text += '\n';
    }
    statusview->setText(text);
}
void
SimpleSearchGui::socketError(Qt4StrigiClient::Mode mode)
{
    switch (mode)
    {
        case Qt4StrigiClient::GetDaemonStatus:
        {
            QMap<QString, QString> emptyMap;
            updateStatus (emptyMap);
            break;
        }
        default:
            break;
    }
}
void
SimpleSearchGui::startDaemon() {
    starting = true;
    // try to start the daemon
    QFileInfo exe = QCoreApplication::applicationDirPath()
    + "/../../daemon/strigidaemon";
    QStringList args;
    if (backendsList) {
        args += backendsList->currentText();
    }
    if (exe.exists()) {
    // start not installed version
    QProcess::startDetached(exe.absoluteFilePath(), args);
    } else {
        exe = QCoreApplication::applicationDirPath()+"/strigidaemon";
        if (exe.exists()) {
            QProcess::startDetached(exe.absoluteFilePath(), args);
        } else {
        // start installed version
        QProcess::startDetached("strigidaemon");
        }
    }
}
void
SimpleSearchGui::toggleDaemon() {
    if (running) {
        SocketClient client;
        client.setSocketName(socketfile.c_str());
        client.stopDaemon();
        indexeddirs->clear();
    } else {
        startDaemon();
    }
}
void
SimpleSearchGui::toggleIndexing() {
    SocketClient client;
    client.setSocketName(socketfile.c_str());
    if (indexing) {
        client.stopIndexing();
    } else {
        client.startIndexing();
    }
}
void
SimpleSearchGui::addDirectory() {
    // open file dialog
    QString dir = QFileDialog::getExistingDirectory (this);
    if (dir.size() <= 0) return;
    for (int i=0; i<indexeddirs->count(); ++i) {
        QString text = indexeddirs->item(i)->text();
        if (dir.startsWith(text)) {
            return;
        }
        if (text.startsWith(dir)) {
            indexeddirs->takeItem(i);
            i = 0;
        }
    }
    indexeddirs->addItem(dir);
    setDirectories();
}
void
SimpleSearchGui::removeDirectory() {
    int i = indexeddirs->currentRow();
    if (i == -1) return;
    indexeddirs->takeItem(i);
    setDirectories();
}
void
SimpleSearchGui::setDirectories() {
    set<string> s;
    for (int i=0; i<indexeddirs->count(); ++i) {
        QString text = indexeddirs->item(i)->text();
        s.insert((const char*)text.toUtf8());
    }
    SocketClient client;
    client.setSocketName(socketfile.c_str());
    client.setIndexedDirectories(s);
    updateDirectories();
}
void
SimpleSearchGui::updateDirectories() {
    indexeddirs->clear();
    SocketClient client;
    client.setSocketName(socketfile.c_str());
    set<string> s = client.getIndexedDirectories();
    indexeddirs->clear();
    set<string>::const_iterator i;
    for (i = s.begin(); i != s.end(); ++i) {
        QString dir(QString::fromUtf8(i->c_str()));
        indexeddirs->addItem(dir);
    }
}
void
SimpleSearchGui::editPreferences() {
    SocketClient client;
    client.setSocketName(socketfile.c_str());
    multimap<int,string> rules = client.getFilteringRules();

    DlgPreferences* dlg = new DlgPreferences (running, &rules);
    dlg->exec();

    delete dlg;

    //update filtering rules
    client.setFilteringRules( rules);
}
void
SimpleSearchGui::editListIndexedFiles() {
    SocketClient client;
    client.setSocketName(socketfile.c_str());
    set<string> files = client.getIndexedFiles();

    DlgListIndexedFiles dlg (files);
    dlg.exec();
}

<commit_msg>Disable daemon start button after pressing it until the daemon status changed.<commit_after>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2006 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "dlgpreferences.h"
#include "dlglistindexedfiles.h"
#include "simplesearchgui.h"
#include "searchtabs.h"
#include "socketclient.h"
#include <QtGui/QListWidget>
#include <QtGui/QListWidgetItem>
#include <QtGui/QLineEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QStackedWidget>
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QFileDialog>
#include <QtGui/QComboBox>
#include <QtGui/QMenu>
#include <QtGui/QMenuBar>
#include <QtGui/QAction>
#include <QtCore/QString>
#include <QtCore/QDebug>
#include <QtCore/QCoreApplication>
#include <QtCore/QProcess>
#include <string>
#include <map>
#include <vector>
using namespace std;

SimpleSearchGui::SimpleSearchGui (QWidget * parent, Qt::WFlags flags)
    : QMainWindow (parent, flags)
{
    mainview = new QStackedWidget();

    QWidget* statuswidget = new QWidget();
    QVBoxLayout *statuslayout = new QVBoxLayout;
    statusview = new QLabel();
    statusview->setAlignment(Qt::AlignTop);
    statusview->setMargin(25);
    indexing = false;
    running = false;
    starting = true;
    indexeddirs = new QListWidget();
    adddir = new QPushButton("add directory");
    removedir = new QPushButton("remove directory");
    toggleindexing = new QPushButton("start indexing");
    toggledaemon = new QPushButton("stop daemon");
    statuslayout->addWidget(statusview);
    QHBoxLayout *hlayout = new QHBoxLayout;
    hlayout->addWidget(toggledaemon);
    hlayout->addWidget(toggleindexing);
    statuslayout->addLayout(hlayout);
/*    vector<string> backends = ClientInterface::getBackEnds();
    if (backends.size() > 1) {
        backendsList = new QComboBox();
        for (uint i = 0; i< backends.size(); ++i) {
            QString backend = backends[i].c_str();
            backendsList->insertItem(i, backend);
        }
        statuslayout->addWidget(backendsList);
    } else {*/
        backendsList = 0;
//    }
    statuslayout->addWidget(indexeddirs);
    hlayout = new QHBoxLayout;
    hlayout->addWidget(adddir);
    hlayout->addWidget(removedir);
    statuslayout->addLayout(hlayout);
    statuswidget->setLayout(statuslayout);

    tabs = new SearchTabs(&strigi);
    tabs->addTab("kde", "kde");
    tabs->addTab("msg", "mimetype:message/*");
    tabs->addTab("irc", "path:*konversation*log");
    tabs->addTab("mail", "mimetype:text/x-mail");
    tabs->addTab("audio", "mimetype:audio/*");
    tabs->addTab("other",
        "-kde -mimetype:message/* -mimetype:text/x-mail -mimetype:audio/*");
    tabs->addTab("all", "");
    mainview->addWidget(tabs);
    mainview->addWidget(statuswidget);
    mainview->setCurrentIndex(1);

    queryfield = new QLineEdit();
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(mainview);
    layout->addWidget(queryfield);

    centralview = new QWidget();
    centralview->setLayout(layout);
    setCentralWidget(centralview);

    createActions();
    createMenus();

    connect(queryfield, SIGNAL(textChanged(const QString&)),
        this, SLOT(query(const QString&)));
    connect(toggleindexing, SIGNAL(clicked()),
        this, SLOT(toggleIndexing()));
    connect(toggledaemon, SIGNAL(clicked()),
        this, SLOT(toggleDaemon()));
    connect(adddir, SIGNAL(clicked()),
        this, SLOT(addDirectory()));
    connect(removedir, SIGNAL(clicked()),
        this, SLOT(removeDirectory()));
    queryfield->setFocus(Qt::ActiveWindowFocusReason);

    socketfile = getenv("HOME");
    socketfile += "/.strigi/socket";

    connect (&strigi, SIGNAL (gotDaemonStatus( const QMap< QString, QString >& )), this, SLOT (updateStatus( const QMap< QString, QString >& )));
    connect (&strigi, SIGNAL (socketError(Qt4StrigiClient::Mode)), this, SLOT (socketError(Qt4StrigiClient::Mode)));

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), &strigi, SLOT(getDaemonStatus()));
    timer->start(2000);
    QMap<QString,QString> emptyMap;
    updateStatus(emptyMap);
}
void
SimpleSearchGui::createMenus() {
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(fileExitAct);

    editMenu = menuBar()->addMenu(tr("&Edit"));
    editMenu->addAction(editPreferenceAct);
    editMenu->addAction(editListIndexedFilesAct);
}
void
SimpleSearchGui::createActions() {
    fileExitAct = new QAction(tr("&Exit"), this);
    fileExitAct->setShortcut(tr("Ctrl+Q"));
    fileExitAct->setStatusTip(tr("Quit the program"));
    connect(fileExitAct, SIGNAL(triggered()), this, SLOT(close()));

    editPreferenceAct = new QAction(tr("Edit Preferences"), this);
    editPreferenceAct->setStatusTip(tr("Edit program preferences"));
    connect(editPreferenceAct, SIGNAL(triggered()), this, SLOT(editPreferences()));

    editListIndexedFilesAct = new QAction(tr("List indexed files"), this);
    editListIndexedFilesAct->setStatusTip(tr("Show files indexed by strigi"));
    connect(editListIndexedFilesAct, SIGNAL(triggered()), this, SLOT(editListIndexedFiles()));
}
void
SimpleSearchGui::query(const QString& item) {
    if (item.length()) {
        tabs->setQuery(item);
    }
    QString query = item.trimmed();
    if (query.length() == 0) {
        mainview->setCurrentIndex(1);
    } else {
        mainview->setCurrentIndex(0);
    }
}
void
SimpleSearchGui::updateStatus(const QMap< QString, QString >& s) {
    static bool first = true;
    static bool attemptedstart = false;
    if (!first && !statusview->isVisible()) return;
    first = false;
    QMap<QString, QString> status (s);
    if (status.size() == 0) {
        running = false;
        editListIndexedFilesAct->setEnabled(false);
        /*if (!attemptedstart) {
            status["Status"] = "Starting daemon";
            startDaemon();
            attemptedstart = true;
        } else {*/
            status["Status"] = "Daemon is not running";
        //}
    } else {
        attemptedstart = true;
        starting = false;
        running = true;
        editListIndexedFilesAct->setEnabled(true);
        if (indexeddirs->count() == 0) {
            updateDirectories();
        }
    }
    toggleindexing->setEnabled(running);
    adddir->setEnabled(running);
    removedir->setEnabled(running);
    queryfield->setEnabled(running);
    toggledaemon->setText((running)?"stop daemon":"start daemon");
    toggledaemon->setEnabled(true);
    if (backendsList) {
        backendsList->setEnabled(!running);
    }
    bool idxng = status["Status"] == "indexing";
    if (idxng != indexing) {
        indexing = idxng;
        toggleindexing->setText((indexing)?"stop indexing":"start indexing");
    }

    QMap<QString,QString>::const_iterator i;
    QString text;
    for (i = status.begin(); i != status.end(); ++i) {
        text += i.key();
        text += ":\t";
        text += i.value();
        text += '\n';
    }
    statusview->setText(text);
}
void
SimpleSearchGui::socketError(Qt4StrigiClient::Mode mode)
{
    switch (mode)
    {
        case Qt4StrigiClient::GetDaemonStatus:
        {
            QMap<QString, QString> emptyMap;
            updateStatus (emptyMap);
            break;
        }
        default:
            break;
    }
}
void
SimpleSearchGui::startDaemon() {
    toggledaemon->setEnabled(false);
    starting = true;
    // try to start the daemon
    QFileInfo exe = QCoreApplication::applicationDirPath()
    + "/../../daemon/strigidaemon";
    QStringList args;
    if (backendsList) {
        args += backendsList->currentText();
    }
    if (exe.exists()) {
        // start not installed version
        QProcess::startDetached(exe.absoluteFilePath(), args);
    } else {
        exe = QCoreApplication::applicationDirPath()+"/strigidaemon";
        if (exe.exists()) {
            QProcess::startDetached(exe.absoluteFilePath(), args);
        } else {
            // start installed version
            QProcess::startDetached("strigidaemon");
        }
    }
}
void
SimpleSearchGui::toggleDaemon() {
    if (running) {
        SocketClient client;
        client.setSocketName(socketfile.c_str());
        client.stopDaemon();
        indexeddirs->clear();
    } else {
        startDaemon();
    }
}
void
SimpleSearchGui::toggleIndexing() {
    SocketClient client;
    client.setSocketName(socketfile.c_str());
    if (indexing) {
        client.stopIndexing();
    } else {
        client.startIndexing();
    }
}
void
SimpleSearchGui::addDirectory() {
    // open file dialog
    QString dir = QFileDialog::getExistingDirectory (this);
    if (dir.size() <= 0) return;
    for (int i=0; i<indexeddirs->count(); ++i) {
        QString text = indexeddirs->item(i)->text();
        if (dir.startsWith(text)) {
            return;
        }
        if (text.startsWith(dir)) {
            indexeddirs->takeItem(i);
            i = 0;
        }
    }
    indexeddirs->addItem(dir);
    setDirectories();
}
void
SimpleSearchGui::removeDirectory() {
    int i = indexeddirs->currentRow();
    if (i == -1) return;
    indexeddirs->takeItem(i);
    setDirectories();
}
void
SimpleSearchGui::setDirectories() {
    set<string> s;
    for (int i=0; i<indexeddirs->count(); ++i) {
        QString text = indexeddirs->item(i)->text();
        s.insert((const char*)text.toUtf8());
    }
    SocketClient client;
    client.setSocketName(socketfile.c_str());
    client.setIndexedDirectories(s);
    updateDirectories();
}
void
SimpleSearchGui::updateDirectories() {
    indexeddirs->clear();
    SocketClient client;
    client.setSocketName(socketfile.c_str());
    set<string> s = client.getIndexedDirectories();
    indexeddirs->clear();
    set<string>::const_iterator i;
    for (i = s.begin(); i != s.end(); ++i) {
        QString dir(QString::fromUtf8(i->c_str()));
        indexeddirs->addItem(dir);
    }
}
void
SimpleSearchGui::editPreferences() {
    SocketClient client;
    client.setSocketName(socketfile.c_str());
    multimap<int,string> rules = client.getFilteringRules();

    DlgPreferences* dlg = new DlgPreferences (running, &rules);
    dlg->exec();

    delete dlg;

    //update filtering rules
    client.setFilteringRules( rules);
}
void
SimpleSearchGui::editListIndexedFiles() {
    SocketClient client;
    client.setSocketName(socketfile.c_str());
    set<string> files = client.getIndexedFiles();

    DlgListIndexedFiles dlg (files);
    dlg.exec();
}

<|endoftext|>


<commit_before>/* <x0/response.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 Chrisitan Parpart <trapni@gentoo.org>
 */

#include <x0/response.hpp>
#include <x0/server.hpp>
#include <x0/io/file.hpp>
#include <x0/io/file_source.hpp>
#include <x0/io/buffer_source.hpp>
#include <x0/io/chunked_filter.hpp>
#include <x0/strutils.hpp>
#include <x0/types.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <strings.h>						// strcasecmp
#include <string>
#include <algorithm>

namespace x0 {

using boost::algorithm::iequals;

char response::status_codes[512][4];

response::~response()
{
	//DEBUG("~response(%p, conn=%p)", this, connection_);
}

template<typename T>
inline std::string make_str(T value)
{
	return boost::lexical_cast<std::string>(value);
}

source_ptr response::make_default_content()
{
	if (content_forbidden()) // || !equals(request_->method, "GET"))
		return source_ptr();

	std::string filename(connection_->server().config()["ErrorDocuments"][make_str(status)].as<std::string>());
	fileinfo_ptr fi(connection_->server().fileinfo(filename));
	if (fi->exists())
	{
		file_ptr f(new file(fi));

		headers.set("Content-Type", fi->mimetype());
		headers.set("Content-Length", boost::lexical_cast<std::string>(fi->size()));

		return std::make_shared<file_source>(f);
	}
	else
	{
		const char *codeStr = status_cstr(status);
		char buf[1024];

		int nwritten = snprintf(buf, sizeof(buf),
			""
			"<title>%s</title>"
			"
%d %s
"
			"\r\n",
			codeStr, status(), codeStr
		);

		headers.set("Content-Type", "text/html");
		headers.set("Content-Length", boost::lexical_cast<std::string>(nwritten));

		return std::make_shared<buffer_source>(buffer::from_copy(buf, nwritten));
	}
}

source_ptr response::serialize()
{
	buffer buffers;

	if (!status)
	{
		status = response::ok;
	}

	if (!headers.contains("Content-Type"))
	{
		headers.push_back("Content-Type", "text/plain"); //!< \todo pass "default" content-type instead!
	}

	if (!headers.contains("Content-Length") && !content_forbidden())
	{
		headers.set("Connection", "closed");
	}
	else if (!headers.contains("Connection"))
	{
		if (iequals(request_->header("Connection"), "keep-alive"))
			headers.push_back("Connection", "keep-alive");
		else
			headers.push_back("Connection", "closed");
	}

	// post-response hook
	connection_->server().post_process(const_cast<x0::request *>(request_), this);

	// enable chunked transfer encoding if required and possible
	if (!headers.contains("Content-Length"))
	{
		if (request_->supports_protocol(1, 1)
			&& !headers.contains("Transfer-Encoding")
			&& !content_forbidden())
		{
			headers.push_back("Transfer-Encoding", "chunked");
			filter_chain.push_back(std::make_shared<chunked_filter>());
		}
		else
		{
			headers.set("Connection", "closed");
		}
	}

	if (request_->supports_protocol(1, 1))
		buffers.push_back("HTTP/1.1 ");
	else if (request_->supports_protocol(1, 0))
		buffers.push_back("HTTP/1.0 ");
	else
		buffers.push_back("HTTP/0.9 ");

	buffers.push_back(status_codes[status]);
	buffers.push_back(' ');
	buffers.push_back(status_cstr(status));
	buffers.push_back("\r\n");

	for (auto i = headers.begin(), e = headers.end(); i != e; ++i)
	{
		const response_header& h = *i;
		buffers.push_back(h.name.data(), h.name.size());
		buffers.push_back(": ");
		buffers.push_back(h.value.data(), h.value.size());
		buffers.push_back("\r\n");
	};

	buffers.push_back("\r\n");

	return std::make_shared<buffer_source>(std::move(buffers));
}

response::response(connection *connection, x0::request *request, int _status) :
	connection_(connection),
	request_(request),
	headers_sent_(false),
	status(_status),
	headers()
{
	connection_->response_ = this;

	//DEBUG("response(%p, conn=%p)", this, connection_);

	headers.push_back("Date", connection_->server().now().http_str().str());
	headers.push_back("Server", connection_->server().tag());
}

const char *response::status_cstr(int value)
{
	switch (value)
	{
		// information
		case 100: return "Continue";
		case 101: return "Switching Protocols";
		case 102: return "Processing";

		// success
		case 200: return "Ok";
		case 201: return "Created";
		case 202: return "Accepted";
		case 204: return "No Content";
		case 206: return "Partial Content";

		// redirect
		case 300: return "Multiple Choices";
		case 301: return "Moved Permanently";
		case 302: return "Moved Temporarily";
		case 304: return "Not Modified";

		// client errors
		case 400: return "Bad Request";
		case 401: return "Unauthorized";
		case 403: return "Forbidden";
		case 404: return "Not Found";
		case 406: return "Not Acceptable";
		case 407: return "Proxy Authentication Required";
		case 408: return "Request Timeout";
		case 409: return "Conflict";
		case 410: return "Gone";
		case 411: return "Length Required";
		case 412: return "Precondition Failed";
		case 413: return "Request Entity Too Large";
		case 414: return "Request URI Too Long";
		case 415: return "Unsupported Media Type";
		case 416: return "Requested Range Not Satisfiable";
		case 417: return "Expectaction Failed";
		case 421: return "There Are Too Many Connections From Your Internet Address";
		case 422: return "Unprocessable Entity";
		case 423: return "Locked";
		case 424: return "Failed Dependency";
		case 425: return "Unordered Collection";
		case 426: return "Upgrade Required";

		// server errors
		case 500: return "Internal Server Error";
		case 501: return "Not_Implemented";
		case 502: return "Bad Gateway";
		case 503: return "Service Unavailable";
		case 504: return "Gateway Timed Out";
		case 505: return "HTTP Version Not Supported";
		case 507: return "Insufficient Storage";
		case 509: return "Bandwidth Limit Exceeded";
		case 510: return "Not Extended";

		// unknown
		default: return "";
	}
}

std::string response::status_str(int value)
{
	return std::string(status_cstr(value));
}

void response::finished0(int ec)
{
	//DEBUG("response(%p).finished(%d)", this, ec);

	if (filter_chain.empty())
		finished1(ec);
	else
		connection_->async_write(std::make_shared<filter_source>(filter_chain),
			std::bind(&response::finished1, this, std::placeholders::_1));
}

/** handler, being invoked when this response has been fully flushed and is considered done.
 */
void response::finished1(int ec)
{
	//DEBUG("response(%p).finished_next(%d)", this, ec);

	{
		server& srv = request_->connection.server();

		// log request/response
		srv.request_done(const_cast<x0::request *>(request_), this);
	}

	if (strcasecmp(headers["Connection"].c_str(), "keep-alive") == 0)
		connection_->resume();
	else
		delete connection_;
}

void response::initialize()
{
	// pre-compute string representations of status codes for use in response serialization
	for (std::size_t i = 0; i < sizeof(status_codes) / sizeof(*status_codes); ++i)
		snprintf(status_codes[i], sizeof(*status_codes), "%03ld", i);
}

} // namespace x0
<commit_msg>core: fixes a few typos wrt "Connection: close" response header.<commit_after>/* <x0/response.cpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 Chrisitan Parpart <trapni@gentoo.org>
 */

#include <x0/response.hpp>
#include <x0/server.hpp>
#include <x0/io/file.hpp>
#include <x0/io/file_source.hpp>
#include <x0/io/buffer_source.hpp>
#include <x0/io/chunked_filter.hpp>
#include <x0/strutils.hpp>
#include <x0/types.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <strings.h>						// strcasecmp
#include <string>
#include <algorithm>

namespace x0 {

using boost::algorithm::iequals;

char response::status_codes[512][4];

response::~response()
{
	//DEBUG("~response(%p, conn=%p)", this, connection_);
}

template<typename T>
inline std::string make_str(T value)
{
	return boost::lexical_cast<std::string>(value);
}

source_ptr response::make_default_content()
{
	if (content_forbidden()) // || !equals(request_->method, "GET"))
		return source_ptr();

	std::string filename(connection_->server().config()["ErrorDocuments"][make_str(status)].as<std::string>());
	fileinfo_ptr fi(connection_->server().fileinfo(filename));
	if (fi->exists())
	{
		file_ptr f(new file(fi));

		headers.set("Content-Type", fi->mimetype());
		headers.set("Content-Length", boost::lexical_cast<std::string>(fi->size()));

		return std::make_shared<file_source>(f);
	}
	else
	{
		const char *codeStr = status_cstr(status);
		char buf[1024];

		int nwritten = snprintf(buf, sizeof(buf),
			""
			"<title>%s</title>"
			"
%d %s
"
			"\r\n",
			codeStr, status(), codeStr
		);

		headers.set("Content-Type", "text/html");
		headers.set("Content-Length", boost::lexical_cast<std::string>(nwritten));

		return std::make_shared<buffer_source>(buffer::from_copy(buf, nwritten));
	}
}

source_ptr response::serialize()
{
	buffer buffers;

	if (!status)
	{
		status = response::ok;
	}

	if (!headers.contains("Content-Type"))
	{
		headers.push_back("Content-Type", "text/plain"); //!< \todo pass "default" content-type instead!
	}

	if (!headers.contains("Content-Length") && !content_forbidden())
	{
		headers.set("Connection", "close");
	}
	else if (!headers.contains("Connection"))
	{
		if (iequals(request_->header("Connection"), "keep-alive"))
			headers.push_back("Connection", "keep-alive");
		else
			headers.push_back("Connection", "close");
	}

	// post-response hook
	connection_->server().post_process(const_cast<x0::request *>(request_), this);

	// enable chunked transfer encoding if required and possible
	if (!headers.contains("Content-Length"))
	{
		if (request_->supports_protocol(1, 1)
			&& !headers.contains("Transfer-Encoding")
			&& !content_forbidden())
		{
			headers.push_back("Transfer-Encoding", "chunked");
			filter_chain.push_back(std::make_shared<chunked_filter>());
		}
		else
		{
			headers.set("Connection", "close");
		}
	}

	if (request_->supports_protocol(1, 1))
		buffers.push_back("HTTP/1.1 ");
	else if (request_->supports_protocol(1, 0))
		buffers.push_back("HTTP/1.0 ");
	else
		buffers.push_back("HTTP/0.9 ");

	buffers.push_back(status_codes[status]);
	buffers.push_back(' ');
	buffers.push_back(status_cstr(status));
	buffers.push_back("\r\n");

	for (auto i = headers.begin(), e = headers.end(); i != e; ++i)
	{
		const response_header& h = *i;
		buffers.push_back(h.name.data(), h.name.size());
		buffers.push_back(": ");
		buffers.push_back(h.value.data(), h.value.size());
		buffers.push_back("\r\n");
	};

	buffers.push_back("\r\n");

	return std::make_shared<buffer_source>(std::move(buffers));
}

response::response(connection *connection, x0::request *request, int _status) :
	connection_(connection),
	request_(request),
	headers_sent_(false),
	status(_status),
	headers()
{
	connection_->response_ = this;

	//DEBUG("response(%p, conn=%p)", this, connection_);

	headers.push_back("Date", connection_->server().now().http_str().str());
	headers.push_back("Server", connection_->server().tag());
}

const char *response::status_cstr(int value)
{
	switch (value)
	{
		// information
		case 100: return "Continue";
		case 101: return "Switching Protocols";
		case 102: return "Processing";

		// success
		case 200: return "Ok";
		case 201: return "Created";
		case 202: return "Accepted";
		case 204: return "No Content";
		case 206: return "Partial Content";

		// redirect
		case 300: return "Multiple Choices";
		case 301: return "Moved Permanently";
		case 302: return "Moved Temporarily";
		case 304: return "Not Modified";

		// client errors
		case 400: return "Bad Request";
		case 401: return "Unauthorized";
		case 403: return "Forbidden";
		case 404: return "Not Found";
		case 406: return "Not Acceptable";
		case 407: return "Proxy Authentication Required";
		case 408: return "Request Timeout";
		case 409: return "Conflict";
		case 410: return "Gone";
		case 411: return "Length Required";
		case 412: return "Precondition Failed";
		case 413: return "Request Entity Too Large";
		case 414: return "Request URI Too Long";
		case 415: return "Unsupported Media Type";
		case 416: return "Requested Range Not Satisfiable";
		case 417: return "Expectaction Failed";
		case 421: return "There Are Too Many Connections From Your Internet Address";
		case 422: return "Unprocessable Entity";
		case 423: return "Locked";
		case 424: return "Failed Dependency";
		case 425: return "Unordered Collection";
		case 426: return "Upgrade Required";

		// server errors
		case 500: return "Internal Server Error";
		case 501: return "Not_Implemented";
		case 502: return "Bad Gateway";
		case 503: return "Service Unavailable";
		case 504: return "Gateway Timed Out";
		case 505: return "HTTP Version Not Supported";
		case 507: return "Insufficient Storage";
		case 509: return "Bandwidth Limit Exceeded";
		case 510: return "Not Extended";

		// unknown
		default: return "";
	}
}

std::string response::status_str(int value)
{
	return std::string(status_cstr(value));
}

void response::finished0(int ec)
{
	//DEBUG("response(%p).finished(%d)", this, ec);

	if (filter_chain.empty())
		finished1(ec);
	else
		connection_->async_write(std::make_shared<filter_source>(filter_chain),
			std::bind(&response::finished1, this, std::placeholders::_1));
}

/** handler, being invoked when this response has been fully flushed and is considered done.
 */
void response::finished1(int ec)
{
	//DEBUG("response(%p).finished_next(%d)", this, ec);

	{
		server& srv = request_->connection.server();

		// log request/response
		srv.request_done(const_cast<x0::request *>(request_), this);
	}

	if (strcasecmp(headers["Connection"].c_str(), "keep-alive") == 0)
		connection_->resume();
	else
		delete connection_;
}

void response::initialize()
{
	// pre-compute string representations of status codes for use in response serialization
	for (std::size_t i = 0; i < sizeof(status_codes) / sizeof(*status_codes); ++i)
		snprintf(status_codes[i], sizeof(*status_codes), "%03ld", i);
}

} // namespace x0
<|endoftext|>