<commit_before>/*
    open source routing machine
    Copyright (C) Dennis Luxen, 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
any later version.

This program 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 General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "OSRM.h"

OSRM::OSRM(const char * server_ini_path) {
    if( !testDataFile(server_ini_path) ){
        throw OSRMException("server.ini not found");
    }

    BaseConfiguration serverConfig(server_ini_path);

    boost::system::error_code ec;

    boost::filesystem::path base_path =
                boost::filesystem::absolute(server_ini_path).parent_path();

    objects = new QueryObjectsStorage(
        boost::filesystem::canonical(
            serverConfig.GetParameter("hsgrData"),
            base_path, ec ).string(),
        boost::filesystem::canonical(
            serverConfig.GetParameter("ramIndex"),
            base_path,
            ec
        ).string(),
        boost::filesystem::canonical(
            serverConfig.GetParameter("fileIndex"),
            base_path,
            ec
        ).string(),
        boost::filesystem::canonical(
            serverConfig.GetParameter("nodesData"),
            base_path,
        ec ).string(),
        boost::filesystem::canonical(
            serverConfig.GetParameter("edgesData"),
            base_path,
            ec
        ).string(),
        boost::filesystem::canonical(
            serverConfig.GetParameter("namesData"),
            base_path,
            ec
        ).string(),
        boost::filesystem::canonical(
            serverConfig.GetParameter("timestamp"),
            base_path,
            ec
        ).string()
    );

    RegisterPlugin(new HelloWorldPlugin());
    RegisterPlugin(new LocatePlugin(objects));
    RegisterPlugin(new NearestPlugin(objects));
    RegisterPlugin(new TimestampPlugin(objects));
    RegisterPlugin(new ViaRoutePlugin(objects));
}

OSRM::~OSRM() {
    BOOST_FOREACH(PluginMap::value_type & plugin_pointer, pluginMap) {
        delete plugin_pointer.second;
    }
    delete objects;
}

void OSRM::RegisterPlugin(BasePlugin * plugin) {
    std::cout << "[plugin] " << plugin->GetDescriptor() << std::endl;
    pluginMap[plugin->GetDescriptor()] = plugin;
}

void OSRM::RunQuery(RouteParameters & route_parameters, http::Reply & reply) {
    const PluginMap::const_iterator & iter = pluginMap.find(route_parameters.service);
    if(pluginMap.end() != iter) {
        reply.status = http::Reply::ok;
        iter->second->HandleRequest(route_parameters, reply );
    } else {
        reply = http::Reply::stockReply(http::Reply::badRequest);
    }
}
<commit_msg>Fixing boost filesystem to work on old installations, too<commit_after>/*
    open source routing machine
    Copyright (C) Dennis Luxen, 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
any later version.

This program 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 General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "OSRM.h"

OSRM::OSRM(const char * server_ini_path) {
    if( !testDataFile(server_ini_path) ){
        throw OSRMException("server.ini not found");
    }

    BaseConfiguration serverConfig(server_ini_path);

    boost::filesystem::path base_path =
               boost::filesystem::absolute(server_ini_path).parent_path();

    boost::filesystem::path hsgr_path = boost::filesystem::absolute(
            serverConfig.GetParameter("hsgrData"),
            base_path
    );

    boost::filesystem::path ram_index_path = boost::filesystem::absolute(
            serverConfig.GetParameter("ramIndex"),
            base_path
    );

    boost::filesystem::path file_index_path = boost::filesystem::absolute(
            serverConfig.GetParameter("fileIndex"),
            base_path
    );

    boost::filesystem::path node_data_path = boost::filesystem::absolute(
            serverConfig.GetParameter("nodesData"),
            base_path
    );
    boost::filesystem::path edge_data_path = boost::filesystem::absolute(
            serverConfig.GetParameter("edgesData"),
            base_path
    );
    boost::filesystem::path name_data_path = boost::filesystem::absolute(
            serverConfig.GetParameter("namesData"),
            base_path
    );
    boost::filesystem::path timestamp_path = boost::filesystem::absolute(
            serverConfig.GetParameter("timestamp"),
            base_path
    );

    objects = new QueryObjectsStorage(
        hsgr_path.string(),
        ram_index_path.string(),
        file_index_path.string(),
        node_data_path.string(),
        edge_data_path.string(),
        name_data_path.string(),
        timestamp_path.string()
    );

    RegisterPlugin(new HelloWorldPlugin());
    RegisterPlugin(new LocatePlugin(objects));
    RegisterPlugin(new NearestPlugin(objects));
    RegisterPlugin(new TimestampPlugin(objects));
    RegisterPlugin(new ViaRoutePlugin(objects));
}

OSRM::~OSRM() {
    BOOST_FOREACH(PluginMap::value_type & plugin_pointer, pluginMap) {
        delete plugin_pointer.second;
    }
    delete objects;
}

void OSRM::RegisterPlugin(BasePlugin * plugin) {
    std::cout << "[plugin] " << plugin->GetDescriptor() << std::endl;
    pluginMap[plugin->GetDescriptor()] = plugin;
}

void OSRM::RunQuery(RouteParameters & route_parameters, http::Reply & reply) {
    const PluginMap::const_iterator & iter = pluginMap.find(route_parameters.service);
    if(pluginMap.end() != iter) {
        reply.status = http::Reply::ok;
        iter->second->HandleRequest(route_parameters, reply );
    } else {
        reply = http::Reply::stockReply(http::Reply::badRequest);
    }
}
<|endoftext|>


<commit_before>#include "defs.hpp"
#include "screen.hpp"
#include "area.hpp"
#include "client/keyboard/keycode.h"
#include "client/ui/event.hpp"
using namespace LD22;

static const int TRANSITION_TIME = 32 * 5;

static const unsigned char KEY_MAP[] = {
    KEY_W, InUp,
    KP_8, InUp,
    KEY_Up, InUp,

    KEY_A, InLeft,
    KP_4, InLeft,
    KEY_Left, InLeft,

    KEY_S, InDown,
    KP_5, InDown,
    KEY_Down, InDown,

    KEY_D, InRight,
    KP_6, InRight,
    KEY_Right, InRight,

    255
};

Screen::Screen()
    : m_key(KEY_MAP), m_levelno(0)
{
    m_area.reset(new Area(*this));
}

Screen::~Screen()
{ }

void Screen::handleEvent(const UI::Event &evt)
{
    switch (evt.type) {
    case UI::KeyDown:
        // if (evt.keyEvent().key == KEY_Escape)
    case UI::KeyUp:
        m_key.handleKeyEvent(evt.keyEvent());
        break;

    default:
        break;
    }
}

void Screen::init()
{
    startLevel(1);
}

static void drawFade(int t, int r, int g, int b, int a, int maxt)
{
    int aa;
    if (t < 0) aa = 0;
    else if (t >= maxt) aa = a;
    else aa = t * a / maxt;
    glEnable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glColor4ub(r, g, b, aa);
    glBegin(GL_QUADS);
    glVertex2s(0, 0);
    glVertex2s(SCREEN_WIDTH, 0);
    glVertex2s(SCREEN_WIDTH, SCREEN_HEIGHT);
    glVertex2s(0, SCREEN_HEIGHT);
    glEnd();
    glDisable(GL_BLEND);
    glColor3ub(255, 255, 255);
}

void Screen::drawExtra(int delta)
{
    m_area->draw(delta);
    switch (m_state) {
    case SPlay:
        break;

    case SLose:
        drawFade(m_timer, 200, 0, 0, 110, 15);
        break;

    case SWin:
        drawFade(m_timer, 200, 200, 200, 150, 15);
        break;
    }
}

void Screen::advance()
{
    ScreenBase::advance();
    m_area->advance();
    m_timer++;
    switch (m_state) {
    case SLose:
        if (m_timer == TRANSITION_TIME)
            startLevel(m_levelno);
        break;

    case SWin:
        if (m_timer == TRANSITION_TIME)
            startLevel(m_levelno + 1);
        break;

    default:
        break;
    }
}

void Screen::lose()
{
    if (m_state == SPlay) {
        m_state = SLose;
        m_timer = 0;
    }
}

void Screen::win()
{
    if (m_state == SPlay) {
        m_state = SWin;
        m_timer = 0;
    }
}

void Screen::startLevel(int num)
{
    printf("startLevel(%d)\n", num);
    if (m_levelno != num)
        level().load(num);
    loadLevel();
    m_area->load();
    m_state = SPlay;
    m_timer = 0;
    m_levelno = num;
}
<commit_msg>Remove debugging output<commit_after>#include "defs.hpp"
#include "screen.hpp"
#include "area.hpp"
#include "client/keyboard/keycode.h"
#include "client/ui/event.hpp"
using namespace LD22;

static const int TRANSITION_TIME = 32 * 5;

static const unsigned char KEY_MAP[] = {
    KEY_W, InUp,
    KP_8, InUp,
    KEY_Up, InUp,

    KEY_A, InLeft,
    KP_4, InLeft,
    KEY_Left, InLeft,

    KEY_S, InDown,
    KP_5, InDown,
    KEY_Down, InDown,

    KEY_D, InRight,
    KP_6, InRight,
    KEY_Right, InRight,

    255
};

Screen::Screen()
    : m_key(KEY_MAP), m_levelno(0)
{
    m_area.reset(new Area(*this));
}

Screen::~Screen()
{ }

void Screen::handleEvent(const UI::Event &evt)
{
    switch (evt.type) {
    case UI::KeyDown:
        // if (evt.keyEvent().key == KEY_Escape)
    case UI::KeyUp:
        m_key.handleKeyEvent(evt.keyEvent());
        break;

    default:
        break;
    }
}

void Screen::init()
{
    startLevel(1);
}

static void drawFade(int t, int r, int g, int b, int a, int maxt)
{
    int aa;
    if (t < 0) aa = 0;
    else if (t >= maxt) aa = a;
    else aa = t * a / maxt;
    glEnable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glColor4ub(r, g, b, aa);
    glBegin(GL_QUADS);
    glVertex2s(0, 0);
    glVertex2s(SCREEN_WIDTH, 0);
    glVertex2s(SCREEN_WIDTH, SCREEN_HEIGHT);
    glVertex2s(0, SCREEN_HEIGHT);
    glEnd();
    glDisable(GL_BLEND);
    glColor3ub(255, 255, 255);
}

void Screen::drawExtra(int delta)
{
    m_area->draw(delta);
    switch (m_state) {
    case SPlay:
        break;

    case SLose:
        drawFade(m_timer, 200, 0, 0, 110, 15);
        break;

    case SWin:
        drawFade(m_timer, 200, 200, 200, 150, 15);
        break;
    }
}

void Screen::advance()
{
    ScreenBase::advance();
    m_area->advance();
    m_timer++;
    switch (m_state) {
    case SLose:
        if (m_timer == TRANSITION_TIME)
            startLevel(m_levelno);
        break;

    case SWin:
        if (m_timer == TRANSITION_TIME)
            startLevel(m_levelno + 1);
        break;

    default:
        break;
    }
}

void Screen::lose()
{
    if (m_state == SPlay) {
        m_state = SLose;
        m_timer = 0;
    }
}

void Screen::win()
{
    if (m_state == SPlay) {
        m_state = SWin;
        m_timer = 0;
    }
}

void Screen::startLevel(int num)
{
    if (m_levelno != num)
        level().load(num);
    loadLevel();
    m_area->load();
    m_state = SPlay;
    m_timer = 0;
    m_levelno = num;
}
<|endoftext|>


<commit_before>/*
    We start from a sum of 0 and try to add powers of 2 until the sum reaches
    10^25.

    We start from 2^0 and consider powers of 2 incrementally. Note that at
    each power 2^e, we either add 0, 2^e, 2^{e + 1} to the current sum depending
    on whether 2^e is counted 0, 1, 2 times respectively.

    The trick is to notice that after considering the power 2^e, all future
    steps will only alter the bits greater than the e-th bit, meaning that
    the bits 0, ..., e are fixed after step e.

    Hence at each step e, the multiple of 2^e added to the current sum must
    satisfy the requirement that bits 0, ..., e of the resultant sum are the
    same as that of 10^25.

    The above allows us to do some dynamic programming. At each step e + 1, we
    consider the possible sums from step 0, ..., e. Since we know what bits
    0, ..., e must be after step e, we only need to consider the number of cases
    for each possible value of bit e + 1 after step e.

    After step e + 1, we save the number of cases for each possible value of
    bit e + 2 for use for the next step, and repeat until we finish up all the
    bits in 10^25.
*/

#include <iostream>
#include <gmpxx.h>
#include <vector>
#include <cstdint>
#include "number_util.h"

int main()
{
    mpz_class n = util::pow(mpz_class(10), 25);
    std::vector<uint64_t> cases = { 1, 1 };

    while ((n >>= 1) > 0)
    {
        if ((n & 1) == mpz_class(0))
            cases = { cases[0], cases[0] + cases[1] };
        else
            cases = { cases[0] + cases[1], cases[1] };
    }

    std::cout << cases[0];
}<commit_msg>Generalized to odd numbers.<commit_after>/*
    We start from a sum of 0 and try to add powers of 2 until the sum reaches
    10^25.

    We start from 2^0 and consider powers of 2 incrementally. Note that at
    each power 2^e, we either add 0, 2^e, 2^{e + 1} to the current sum depending
    on whether 2^e is counted 0, 1, 2 times respectively.

    The trick is to notice that after considering the power 2^e, all future
    steps will only alter the bits greater than the e-th bit, meaning that
    the bits 0, ..., e are fixed after step e.

    Hence at each step e, the multiple of 2^e added to the current sum must
    satisfy the requirement that bits 0, ..., e of the resultant sum are the
    same as that of 10^25.

    The above allows us to do some dynamic programming. At each step e + 1, we
    consider the possible sums from step 0, ..., e. Since we know what bits
    0, ..., e must be after step e, we only need to consider the number of cases
    for each possible value of bit e + 1 after step e.

    After step e + 1, we save the number of cases for each possible value of
    bit e + 2 for use for the next step, and repeat until we finish up all the
    bits in 10^25.
*/

#include <iostream>
#include <gmpxx.h>
#include <vector>
#include <cstdint>
#include "number_util.h"

int main()
{
    mpz_class n = util::pow(mpz_class(10), 25);
    std::vector<uint64_t> cases = { 1, (n & 1) == 0 };

    while ((n >>= 1) > 0)
    {
        if ((n & 1) == mpz_class(0))
            cases = { cases[0], cases[0] + cases[1] };
        else
            cases = { cases[0] + cases[1], cases[1] };
    }

    std::cout << cases[0];
}<|endoftext|>


<commit_before>#include "transactiondesc.h"

#include "guiutil.h"
#include "bitcoinunits.h"

#include "main.h"
#include "wallet.h"
#include "txdb.h"
#include "ui_interface.h"
#include "base58.h"

QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
    AssertLockHeld(cs_main);
    if (!IsFinalTx(wtx, nBestHeight + 1))
    {
        if (wtx.nLockTime < LOCKTIME_THRESHOLD)
            return tr("Open for %n more block(s)", "", wtx.nLockTime - nBestHeight);
        else
            return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
    }
    else
    {
        int nDepth = wtx.GetDepthInMainChain();
        if (nDepth < 0)
            return tr("conflicted");
        else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
            return tr("%1/offline").arg(nDepth);
        else if (nDepth < 10)
            return tr("%1/unconfirmed").arg(nDepth);
        else
            return tr("%1 confirmations").arg(nDepth);
    }
}

QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
{
    QString strHTML;

    LOCK2(cs_main, wallet->cs_wallet);
    strHTML.reserve(4000);
    strHTML += "";

    int64_t nTime = wtx.GetTxTime();
    int64_t nCredit = wtx.GetCredit();
    int64_t nDebit = wtx.GetDebit();
    int64_t nNet = nCredit - nDebit;

    strHTML += "" + tr("Status") + ": " + FormatTxStatus(wtx);
    int nRequests = wtx.GetRequestCount();
    if (nRequests != -1)
    {
        if (nRequests == 0)
            strHTML += tr(", has not been successfully broadcast yet");
        else if (nRequests > 0)
            strHTML += tr(", broadcast through %n node(s)", "", nRequests);
    }
    strHTML += "
";

    strHTML += "" + tr("Date") + ": " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "
";

    //
    // From
    //
    if (wtx.IsCoinBase() || wtx.IsCoinStake())
    {
        strHTML += "" + tr("Source") + ": " + tr("Generated") + "
";
    }
    else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
    {
        // Online transaction
        strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
";
    }
    else
    {
        // Offline transaction
        if (nNet > 0)
        {
            // Credit
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            {
                if (wallet->IsMine(txout))
                {
                    CTxDestination address;
                    if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
                    {
                        if (wallet->mapAddressBook.count(address))
                        {
                            strHTML += "" + tr("From") + ": " + tr("unknown") + "
";
                            strHTML += "" + tr("To") + ": ";
                            strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
                            if (!wallet->mapAddressBook[address].empty())
                                strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
                            else
                                strHTML += " (" + tr("own address") + ")";
                            strHTML += "
";
                        }
                    }
                    break;
                }
            }
        }
    }

    //
    // To
    //
    if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
    {
        // Online transaction
        std::string strAddress = wtx.mapValue["to"];
        strHTML += "" + tr("To") + ": ";
        CTxDestination dest = CBitcoinAddress(strAddress).Get();
        if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
        strHTML += GUIUtil::HtmlEscape(strAddress) + "
";
    }

    //
    // Amount
    //
    if (wtx.IsCoinBase() && nCredit == 0)
    {
        //
        // Coinbase
        //
        int64_t nUnmatured = 0;
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            nUnmatured += wallet->GetCredit(txout);
        strHTML += "" + tr("Credit") + ": ";
        if (wtx.IsInMainChain())
            strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
        else
            strHTML += "(" + tr("not accepted") + ")";
        strHTML += "
";
    }
    else if (nNet > 0)
    {
        //
        // Credit
        //
        strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "
";
    }
    else
    {
        bool fAllFromMe = true;
        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
            fAllFromMe = fAllFromMe && wallet->IsMine(txin);

        bool fAllToMe = true;
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            fAllToMe = fAllToMe && wallet->IsMine(txout);

        if (fAllFromMe)
        {
            //
            // Debit
            //
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            {
                if (wallet->IsMine(txout))
                    continue;

                if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
                {
                    // Offline transaction
                    CTxDestination address;
                    if (ExtractDestination(txout.scriptPubKey, address))
                    {
                        strHTML += "" + tr("To") + ": ";
                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
                        strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
                        strHTML += "
";
                    }
                }

                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "
";
            }

            if (fAllToMe)
            {
                // Payment to self
                int64_t nChange = wtx.GetChange();
                int64_t nValue = nCredit - nChange;
                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "
";
                strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "
";
            }

            int64_t nTxFee = nDebit - wtx.GetValueOut();
            if (nTxFee > 0)
                strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "
";
        }
        else
        {
            //
            // Mixed debit transaction
            //
            BOOST_FOREACH(const CTxIn& txin, wtx.vin)
                if (wallet->IsMine(txin))
                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                if (wallet->IsMine(txout))
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";
        }
    }

    strHTML += "" + tr("Net amount") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "
";

    //
    // Message
    //
    if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
        strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "
";
    if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
        strHTML += "
" + tr("Comment") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
";

    strHTML += "" + tr("Transaction ID") + ": " + wtx.GetHash().ToString().c_str() + "
";

    if (wtx.IsCoinBase() || wtx.IsCoinStake())
        strHTML += "
" + tr("Generated coins must mature 510 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "
";

    //
    // Debug view
    //
    if (fDebug)
    {
        strHTML += "

" + tr("Debug information") + "

";
        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
            if(wallet->IsMine(txin))
                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            if(wallet->IsMine(txout))
                strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";

        strHTML += "
" + tr("Transaction") + ":
";
        strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);

        CTxDB txdb("r"); // To fetch source txouts

        strHTML += "
" + tr("Inputs") + ":";
        strHTML += "
";

        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
        {
            COutPoint prevout = txin.prevout;

            CTransaction prev;
            if(txdb.ReadDiskTx(prevout.hash, prev))
            {
                if (prevout.n < prev.vout.size())
                {
                    strHTML += "
";
                    const CTxOut &vout = prev.vout[prevout.n];
                    CTxDestination address;
                    if (ExtractDestination(vout.scriptPubKey, address))
                    {
                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
                        strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
                    }
                    strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
                    strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "
";
                }
            }
        }

        strHTML += "
";
    }

    strHTML += "";
    return strHTML;
}
<commit_msg>Fix incorrect block count for confirmations<commit_after>#include "transactiondesc.h"

#include "guiutil.h"
#include "bitcoinunits.h"

#include "main.h"
#include "wallet.h"
#include "txdb.h"
#include "ui_interface.h"
#include "base58.h"

QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
    AssertLockHeld(cs_main);
    if (!IsFinalTx(wtx, nBestHeight + 1))
    {
        if (wtx.nLockTime < LOCKTIME_THRESHOLD)
            return tr("Open for %n more block(s)", "", wtx.nLockTime - nBestHeight);
        else
            return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
    }
    else
    {
        int nDepth = wtx.GetDepthInMainChain();
        if (nDepth < 0)
            return tr("conflicted");
        else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
            return tr("%1/offline").arg(nDepth);
        else if (nDepth < 10)
            return tr("%1/unconfirmed").arg(nDepth);
        else
            return tr("%1 confirmations").arg(nDepth);
    }
}

QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
{
    QString strHTML;

    LOCK2(cs_main, wallet->cs_wallet);
    strHTML.reserve(4000);
    strHTML += "";

    int64_t nTime = wtx.GetTxTime();
    int64_t nCredit = wtx.GetCredit();
    int64_t nDebit = wtx.GetDebit();
    int64_t nNet = nCredit - nDebit;

    strHTML += "" + tr("Status") + ": " + FormatTxStatus(wtx);
    int nRequests = wtx.GetRequestCount();
    if (nRequests != -1)
    {
        if (nRequests == 0)
            strHTML += tr(", has not been successfully broadcast yet");
        else if (nRequests > 0)
            strHTML += tr(", broadcast through %n node(s)", "", nRequests);
    }
    strHTML += "
";

    strHTML += "" + tr("Date") + ": " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "
";

    //
    // From
    //
    if (wtx.IsCoinBase() || wtx.IsCoinStake())
    {
        strHTML += "" + tr("Source") + ": " + tr("Generated") + "
";
    }
    else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
    {
        // Online transaction
        strHTML += "" + tr("From") + ": " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "
";
    }
    else
    {
        // Offline transaction
        if (nNet > 0)
        {
            // Credit
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            {
                if (wallet->IsMine(txout))
                {
                    CTxDestination address;
                    if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
                    {
                        if (wallet->mapAddressBook.count(address))
                        {
                            strHTML += "" + tr("From") + ": " + tr("unknown") + "
";
                            strHTML += "" + tr("To") + ": ";
                            strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
                            if (!wallet->mapAddressBook[address].empty())
                                strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
                            else
                                strHTML += " (" + tr("own address") + ")";
                            strHTML += "
";
                        }
                    }
                    break;
                }
            }
        }
    }

    //
    // To
    //
    if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
    {
        // Online transaction
        std::string strAddress = wtx.mapValue["to"];
        strHTML += "" + tr("To") + ": ";
        CTxDestination dest = CBitcoinAddress(strAddress).Get();
        if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
        strHTML += GUIUtil::HtmlEscape(strAddress) + "
";
    }

    //
    // Amount
    //
    if (wtx.IsCoinBase() && nCredit == 0)
    {
        //
        // Coinbase
        //
        int64_t nUnmatured = 0;
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            nUnmatured += wallet->GetCredit(txout);
        strHTML += "" + tr("Credit") + ": ";
        if (wtx.IsInMainChain())
            strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
        else
            strHTML += "(" + tr("not accepted") + ")";
        strHTML += "
";
    }
    else if (nNet > 0)
    {
        //
        // Credit
        //
        strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "
";
    }
    else
    {
        bool fAllFromMe = true;
        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
            fAllFromMe = fAllFromMe && wallet->IsMine(txin);

        bool fAllToMe = true;
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            fAllToMe = fAllToMe && wallet->IsMine(txout);

        if (fAllFromMe)
        {
            //
            // Debit
            //
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            {
                if (wallet->IsMine(txout))
                    continue;

                if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
                {
                    // Offline transaction
                    CTxDestination address;
                    if (ExtractDestination(txout.scriptPubKey, address))
                    {
                        strHTML += "" + tr("To") + ": ";
                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
                        strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
                        strHTML += "
";
                    }
                }

                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "
";
            }

            if (fAllToMe)
            {
                // Payment to self
                int64_t nChange = wtx.GetChange();
                int64_t nValue = nCredit - nChange;
                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "
";
                strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "
";
            }

            int64_t nTxFee = nDebit - wtx.GetValueOut();
            if (nTxFee > 0)
                strHTML += "" + tr("Transaction fee") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "
";
        }
        else
        {
            //
            // Mixed debit transaction
            //
            BOOST_FOREACH(const CTxIn& txin, wtx.vin)
                if (wallet->IsMine(txin))
                    strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";
            BOOST_FOREACH(const CTxOut& txout, wtx.vout)
                if (wallet->IsMine(txout))
                    strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";
        }
    }

    strHTML += "" + tr("Net amount") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "
";

    //
    // Message
    //
    if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
        strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "
";
    if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
        strHTML += "
" + tr("Comment") + ":
" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
";

    strHTML += "" + tr("Transaction ID") + ": " + wtx.GetHash().ToString().c_str() + "
";

    if (wtx.IsCoinBase() || wtx.IsCoinStake())
        strHTML += "
" + tr("Generated coins must mature 30 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "
";

    //
    // Debug view
    //
    if (fDebug)
    {
        strHTML += "

" + tr("Debug information") + "

";
        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
            if(wallet->IsMine(txin))
                strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "
";
        BOOST_FOREACH(const CTxOut& txout, wtx.vout)
            if(wallet->IsMine(txout))
                strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "
";

        strHTML += "
" + tr("Transaction") + ":
";
        strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);

        CTxDB txdb("r"); // To fetch source txouts

        strHTML += "
" + tr("Inputs") + ":";
        strHTML += "
";

        BOOST_FOREACH(const CTxIn& txin, wtx.vin)
        {
            COutPoint prevout = txin.prevout;

            CTransaction prev;
            if(txdb.ReadDiskTx(prevout.hash, prev))
            {
                if (prevout.n < prev.vout.size())
                {
                    strHTML += "
";
                    const CTxOut &vout = prev.vout[prevout.n];
                    CTxDestination address;
                    if (ExtractDestination(vout.scriptPubKey, address))
                    {
                        if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
                            strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
                        strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
                    }
                    strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue);
                    strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "
";
                }
            }
        }

        strHTML += "
";
    }

    strHTML += "";
    return strHTML;
}
<|endoftext|>


<commit_before>class Solution {
public:
    bool canWinNim(int n) {
        if(n%4==0) return false;
        return true;
    }
};
<commit_msg>Nim Game<commit_after>class Solution {
public:
    bool canWinNim(int n) {
        if(n%4==0) return false;
        return true;
    }
};

<|endoftext|>


<commit_before>#include "mini_stdint.h"

#define WEAK __attribute__((weak))

extern "C" {

extern void __android_log_vprint(int, const char *, const char *, __builtin_va_list);

extern size_t fwrite(const void *, size_t, size_t, void *);
extern void *fopen(const char *, const char *);
extern int fclose(void *);

WEAK int halide_printf(const char * fmt, ...) {
    __builtin_va_list args;
    __builtin_va_start(args,fmt);
    __android_log_vprint(7, "halide", fmt, args);
    __builtin_va_end(args);
    // Profiler assumes that return value <=0 is failure,
    // so return something else here.
    return 1;
}

static bool write_stub(const void *bytes, size_t size, void *f) {
    return fwrite(const_cast<void *>(bytes), size, 1, f) == 1;
}

WEAK int32_t halide_debug_to_file(const char *filename, uint8_t *data,
                                  int32_t s0, int32_t s1, int32_t s2, int32_t s3,
                                  int32_t type_code, int32_t bytes_per_element) {
    void *f = fopen(filename, "wb");
    if (!f) return -1;

    int result = halide_write_debug_image(filename, data, s0, s1, s2, s3,
					  type_code, bytes_per_element, write_stub, (void *)f);

    fclose(f);
    return result;
}

}
<commit_msg>Fixed __android_log_vprint signature<commit_after>#include "mini_stdint.h"

#define WEAK __attribute__((weak))

extern "C" {

extern int __android_log_vprint(int, const char *, const char *, __builtin_va_list);

extern size_t fwrite(const void *, size_t, size_t, void *);
extern void *fopen(const char *, const char *);
extern int fclose(void *);

WEAK int halide_printf(const char * fmt, ...) {
    __builtin_va_list args;
    __builtin_va_start(args,fmt);
    int result = __android_log_vprint(7, "halide", fmt, args);
    __builtin_va_end(args);
    return result;
}

static bool write_stub(const void *bytes, size_t size, void *f) {
    return fwrite(const_cast<void *>(bytes), size, 1, f) == 1;
}

WEAK int32_t halide_debug_to_file(const char *filename, uint8_t *data,
                                  int32_t s0, int32_t s1, int32_t s2, int32_t s3,
                                  int32_t type_code, int32_t bytes_per_element) {
    void *f = fopen(filename, "wb");
    if (!f) return -1;

    int result = halide_write_debug_image(filename, data, s0, s1, s2, s3,
					  type_code, bytes_per_element, write_stub, (void *)f);

    fclose(f);
    return result;
}

}
<|endoftext|>


<commit_before>/**
 ** \file scheduler/scheduler.cc
 ** \brief Implementation of scheduler::Scheduler.
 */

//#define ENABLE_DEBUG_TRACES

#include <cassert>
#include <cstdlib>

#include <libport/compiler.hh>
#include <libport/containers.hh>
#include <libport/contract.hh>
#include <libport/foreach.hh>

#include <object/urbi-exception.hh>

#include <scheduler/scheduler.hh>
#include <scheduler/job.hh>

namespace scheduler
{

  // This function is required to start a new job using the libcoroutine.
  // Its only purpose is to create the context and start the execution
  // of the new job.
  static void
  run_job(Job* job)
  {
    job->run();
  }

  void
  Scheduler::add_job(rJob job)
  {
    assert(job);
    assert(!libport::has(jobs_, job));
    assert(!libport::has(pending_, job));
    // If we are currently in a job, add it to the pending_ queue so that
    // the job is started in the course of the current round. To make sure
    // that it is not started too late even if the creator is located after
    // the job that is causing the creation (think "at job handler" for
    // example), insert it right after the current job.
    if (current_job_)
    {
      jobs_type::iterator insert_before = job_p_;
      pending_.insert(++insert_before, job);
    }
    else
    {
      jobs_.push_back(job);
      jobs_to_start_ = true;
    }
  }

  libport::utime_t
  Scheduler::work()
  {
    ++cycle_;
    ECHO("======================================================== cycle "
	  << cycle_);

    libport::utime_t deadline = execute_round();

#ifdef ENABLE_DEBUG_TRACES
    if (deadline)
      ECHO("Scheduler asking to be woken up in "
	    << (deadline - get_time_()) / 1000000L << " seconds");
    else
      ECHO("Scheduler asking to be woken up ASAP");
#endif

    return deadline;
  }

  libport::utime_t
  Scheduler::execute_round()
  {
    // Run all the jobs in the run queue once. If any job declares upon entry or
    // return that it is not side-effect free, we remember that for the next
    // cycle.
    pending_.clear();
    std::swap(pending_, jobs_);

    // By default, wake us up after one hour and consider that we have no
    // new job to start. Also, run waiting jobs only if the previous round
    // may have add a side effect and reset this indication for the current
    // job.
    libport::utime_t start_time = get_time_();
    libport::utime_t deadline = start_time +  3600000000LL;
    jobs_to_start_ = false;
    bool start_waiting = possible_side_effect_;
    possible_side_effect_ = false;
    bool at_least_one_started = false;

    ECHO(pending_.size() << " jobs in the queue for this round");

    // Do not use libport::foreach here, as the list of jobs may grow if
    // add_job() is called during the iteration.
    for (job_p_ = pending_.begin();
	 job_p_ != pending_.end();
	 ++job_p_)
    {
      rJob& job = *job_p_;
      // If the job has terminated during the previous round, remove the
      // references we have on it by just skipping it.
      if (job->terminated())
	continue;

      // Should the job be started?
      bool start = false;

      // Save the current time since we will use it several times during this job
      // analysis.
      libport::utime_t current_time = get_time_();

      ECHO("Considering " << *job << " in state " << state_name(job->state_get()));

      switch (job->state_get())
      {
      case to_start:
      {
	// New job. Start its coroutine but do not start the job as it would be queued
	// twice otherwise. It will start doing real work at the next cycle, so set
	// deadline to 0. Note that we use "continue" here to avoid having the job
	// requeued because it hasn't been started by setting "start".
	//
	// The code below takes care of destroying the rJob reference to the job, so
	// that it does not stay in the call stack as a local variable. If it did,
	// the job would never be destroyed. However, to prevent the job from being
	// prematurely destroyed, we set current_job_ (global to the scheduler) to
	// the rJob.
	ECHO("Starting job " << *job);
	current_job_ = job;
	ECHO("Job " << *job << " is starting");
	job = 0;
	coroutine_start(coro_, current_job_->coro_get(), run_job, current_job_.get());
	current_job_ = 0;
	deadline = SCHED_IMMEDIATE;
	at_least_one_started = true;
	continue;
      }
      case zombie:
	assert(false);
	break;
      case running:
	start = true;
	break;
      case sleeping:
	{
	  libport::utime_t job_deadline = job->deadline_get();

	  // If the job has been frozen, extend its deadline by the
	  // corresponding amount of time. The deadline will be adjusted
	  // later when the job is unfrozen using notice_not_frozen(),
	  // but in the meantime we do not want to cause an early wakeup.
	  if (libport::utime_t frozen_since = job->frozen_since_get())
	    job_deadline += current_time - frozen_since;

	  if (job_deadline <= current_time)
	    start = true;
	  else
	    deadline = std::min(deadline, job_deadline);
	}
	break;
      case waiting:
	// Since jobs keep their orders in the queue, start waiting jobs if
	// previous jobs in the run have had a possible side effect or if
	// the previous run may have had some. Without it, we may miss some
	// changes if the watching job is after the modifying job in the queue
	// and the watched condition gets true for only one cycle.
	start = start_waiting || possible_side_effect_;
	break;
      case joining:
	break;
      }

      // Tell the job whether it is frozen or not so that it can remember
      // since when it has been in this state.
      if (job->frozen())
	job->notice_frozen(current_time);
      else
	job->notice_not_frozen(current_time);

      // A job with an exception will start unconditionally.
      if (start || job->has_pending_exception())
      {
	at_least_one_started = true;
	ECHO("will resume job " << *job
	      << (job->side_effect_free_get() ? " (side-effect free)" : ""));
	possible_side_effect_ |= !job->side_effect_free_get();
	assert(!current_job_);
	coroutine_switch_to(coro_, job->coro_get());
	assert(current_job_);
	current_job_ = 0;
	possible_side_effect_ |= !job->side_effect_free_get();
	ECHO("back from job " << *job
	      << (job->side_effect_free_get() ? " (side-effect free)" : ""));
	switch (job->state_get())
	{
	case running:
	  deadline = SCHED_IMMEDIATE;
	  break;
	case sleeping:
	  deadline = std::min(deadline, job->deadline_get());
	  break;
	default:
	  break;
	}
      }
      else
	jobs_.push_back(job);   // Job not started, keep it in queue
    }

    /// If during this cycle a new job has been created by an existing job,
    /// start it. Also start if a possible side effect happened, it may have
    /// occurred later then the waiting jobs in the cycle.
    if (jobs_to_start_ || possible_side_effect_)
      deadline = SCHED_IMMEDIATE;

    /// If we are ready to die and there are no jobs left, then die.
    if (ready_to_die_ && jobs_.empty())
      deadline = SCHED_EXIT;

    // Compute statistics
    if (at_least_one_started)
      stats_.add_sample(get_time_() - start_time);

    return deadline;
  }

  void
  Scheduler::resume_scheduler(rJob job)
  {
    // If the job has not terminated and is side-effect free, then we
    // assume it will not take a long time as we are probably evaluating
    // a condition. In order to reduce the number of cycles spent to evaluate
    // the condition, continue until it asks to be suspended in another
    // way or until it is no longer side-effect free.

    bool side_effect_free_save = job->side_effect_free_get();

    if (job->state_get() == running && side_effect_free_save)
      return;

    if (job->state_get() == running &&
	job->prio_get() >= PRIO_RT_MIN &&
	!job->frozen())
      return;

    // We may have to suspend the job several time in case it makes no sense
    // to start it back. Let's do it in a loop and we'll break when we want
    // to resume the job.

    while (true)
    {
      // Add the job at the end of the scheduler queue unless the job has
      // already terminated.
      if (!job->terminated())
	jobs_.push_back(job);

      // Switch back to the scheduler. But in the case this job has been
      // destroyed, erase the local variable first so that it doesn't keep
      // a reference on it which will never be destroyed.
      assert(current_job_ == job);
      ECHO(*job << " has " << (job->terminated() ? "" : "not ") << "terminated\n\t"
	   << "state: " << state_name(job->state_get()) << std::endl);
      Coro* current_coro = job->coro_get();
      if (job->terminated())
	job = 0;
      coroutine_switch_to(current_coro, coro_);

      // If we regain control, we are not dead.
      assert(job);

      // We regained control, we are again in the context of the job.
      assert(!current_job_);
      current_job_ = job;
      ECHO("job " << *job << " resumed");

      // Execute a deferred exception if any; this may break out of this loop
      job->check_for_pending_exception();

      // If we are not frozen, it is time to resume regular execution
      if (!job->frozen())
	break;

      // Ok, we are frozen. Let's requeue ourselves after setting
      // the side_effect_free flag, and we will be in waiting mode.
      job->side_effect_free_set(true);
      job->state_set(waiting);
    }

    // Check that we are not near exhausting the stack space.
    job->check_stack_space();

    // Restore the side_effect_free flag
    job->side_effect_free_set(side_effect_free_save);

    // Resume job execution
  }

  void
  Scheduler::killall_jobs()
  {
    ECHO("killing all jobs!");

    // Mark the scheduler as ready to die when all the jobs are
    // really dead.
    ready_to_die_ = true;

    // Since killing the current job will result in its immediate
    // termination, kill all other jobs before.
    foreach (rJob job, jobs_get())
      if (job != current_job_)
	job->terminate_now();
    if (current_job_)
      current_job_->terminate_now();
  }

  void
  Scheduler::signal_stop(const rTag& tag, boost::any payload)
  {
    // Tell the jobs that a tag has been stopped, ending with
    // the current job to avoid interrupting this method early.
    foreach (rJob job, jobs_get())
    {
      // Job started at this cycle, reset to avoid stack references.
      if (!job)
	continue;
      // Job to be started during this cycle.
      if (job->state_get() == to_start)
      {
	// Check if this job deserves to be removed.
	foreach (const rTag& t, job->tags_get())
	  if (t->derives_from(*tag))
	  {
	    pending_.remove(job);
	    continue;
	  }
      }
      // Any other non-current job.
      else if (job != current_job_)
	job->register_stopped_tag(tag, payload);
    }
    if (current_job_)
      current_job_->register_stopped_tag(tag, payload);
  }

  jobs_type
  Scheduler::jobs_get() const
  {
    // If this method is called from within a job, return the currently
    // executing jobs (pending_), otherwise return the jobs_ content which
    // is complete.
    return current_job_ ? pending_ : jobs_;
  }

  const scheduler_stats_type&
  Scheduler::stats_get() const
  {
    return stats_;
  }

} // namespace scheduler
<commit_msg>Sort jobs according to their priority.<commit_after>/**
 ** \file scheduler/scheduler.cc
 ** \brief Implementation of scheduler::Scheduler.
 */

//#define ENABLE_DEBUG_TRACES

#include <algorithm>
#include <cassert>
#include <cstdlib>

#include <libport/compiler.hh>
#include <libport/containers.hh>
#include <libport/contract.hh>
#include <libport/foreach.hh>

#include <object/urbi-exception.hh>

#include <scheduler/scheduler.hh>
#include <scheduler/job.hh>

namespace scheduler
{

  // This function is required to start a new job using the libcoroutine.
  // Its only purpose is to create the context and start the execution
  // of the new job.
  static void
  run_job(Job* job)
  {
    job->run();
  }

  void
  Scheduler::add_job(rJob job)
  {
    assert(job);
    assert(!libport::has(jobs_, job));
    assert(!libport::has(pending_, job));
    // If we are currently in a job, add it to the pending_ queue so that
    // the job is started in the course of the current round. To make sure
    // that it is not started too late even if the creator is located after
    // the job that is causing the creation (think "at job handler" for
    // example), insert it right after the current job.
    if (current_job_)
    {
      jobs_type::iterator insert_before = job_p_;
      pending_.insert(++insert_before, job);
    }
    else
    {
      jobs_.push_back(job);
      jobs_to_start_ = true;
    }
  }

  libport::utime_t
  Scheduler::work()
  {
    ++cycle_;
    ECHO("======================================================== cycle "
	  << cycle_);

    libport::utime_t deadline = execute_round();

#ifdef ENABLE_DEBUG_TRACES
    if (deadline)
      ECHO("Scheduler asking to be woken up in "
	    << (deadline - get_time_()) / 1000000L << " seconds");
    else
      ECHO("Scheduler asking to be woken up ASAP");
#endif

    return deadline;
  }

  static bool prio_gt(const rJob& j1, const rJob& j2)
  {
    return j2->prio_get() < j1->prio_get();
  }

  libport::utime_t
  Scheduler::execute_round()
  {
    // Run all the jobs in the run queue once. If any job declares upon entry or
    // return that it is not side-effect free, we remember that for the next
    // cycle.
    pending_.clear();
    std::swap(pending_, jobs_);

    // Sort all the jobs according to their priority.
    {
      static std::vector<rJob> tmp;
      tmp.reserve(pending_.size());
      tmp.clear();
      foreach(rJob job, pending_)
	tmp.push_back(job);
      std::stable_sort(tmp.begin(), tmp.end(), prio_gt);
      pending_.clear();
      foreach(rJob job, tmp)
	pending_.push_back(job);
    }

    // By default, wake us up after one hour and consider that we have no
    // new job to start. Also, run waiting jobs only if the previous round
    // may have add a side effect and reset this indication for the current
    // job.
    libport::utime_t start_time = get_time_();
    libport::utime_t deadline = start_time +  3600000000LL;
    jobs_to_start_ = false;
    bool start_waiting = possible_side_effect_;
    possible_side_effect_ = false;
    bool at_least_one_started = false;

    ECHO(pending_.size() << " jobs in the queue for this round");

    // Do not use libport::foreach here, as the list of jobs may grow if
    // add_job() is called during the iteration.
    for (job_p_ = pending_.begin();
	 job_p_ != pending_.end();
	 ++job_p_)
    {
      rJob& job = *job_p_;
      // If the job has terminated during the previous round, remove the
      // references we have on it by just skipping it.
      if (job->terminated())
	continue;

      // Should the job be started?
      bool start = false;

      // Save the current time since we will use it several times during this job
      // analysis.
      libport::utime_t current_time = get_time_();

      ECHO("Considering " << *job << " in state " << state_name(job->state_get()));

      switch (job->state_get())
      {
      case to_start:
      {
	// New job. Start its coroutine but do not start the job as it would be queued
	// twice otherwise. It will start doing real work at the next cycle, so set
	// deadline to 0. Note that we use "continue" here to avoid having the job
	// requeued because it hasn't been started by setting "start".
	//
	// The code below takes care of destroying the rJob reference to the job, so
	// that it does not stay in the call stack as a local variable. If it did,
	// the job would never be destroyed. However, to prevent the job from being
	// prematurely destroyed, we set current_job_ (global to the scheduler) to
	// the rJob.
	ECHO("Starting job " << *job);
	current_job_ = job;
	ECHO("Job " << *job << " is starting");
	job = 0;
	coroutine_start(coro_, current_job_->coro_get(), run_job, current_job_.get());
	current_job_ = 0;
	deadline = SCHED_IMMEDIATE;
	at_least_one_started = true;
	continue;
      }
      case zombie:
	assert(false);
	break;
      case running:
	start = true;
	break;
      case sleeping:
	{
	  libport::utime_t job_deadline = job->deadline_get();

	  // If the job has been frozen, extend its deadline by the
	  // corresponding amount of time. The deadline will be adjusted
	  // later when the job is unfrozen using notice_not_frozen(),
	  // but in the meantime we do not want to cause an early wakeup.
	  if (libport::utime_t frozen_since = job->frozen_since_get())
	    job_deadline += current_time - frozen_since;

	  if (job_deadline <= current_time)
	    start = true;
	  else
	    deadline = std::min(deadline, job_deadline);
	}
	break;
      case waiting:
	// Since jobs keep their orders in the queue, start waiting jobs if
	// previous jobs in the run have had a possible side effect or if
	// the previous run may have had some. Without it, we may miss some
	// changes if the watching job is after the modifying job in the queue
	// and the watched condition gets true for only one cycle.
	start = start_waiting || possible_side_effect_;
	break;
      case joining:
	break;
      }

      // Tell the job whether it is frozen or not so that it can remember
      // since when it has been in this state.
      if (job->frozen())
	job->notice_frozen(current_time);
      else
	job->notice_not_frozen(current_time);

      // A job with an exception will start unconditionally.
      if (start || job->has_pending_exception())
      {
	at_least_one_started = true;
	ECHO("will resume job " << *job
	      << (job->side_effect_free_get() ? " (side-effect free)" : ""));
	possible_side_effect_ |= !job->side_effect_free_get();
	assert(!current_job_);
	coroutine_switch_to(coro_, job->coro_get());
	assert(current_job_);
	current_job_ = 0;
	possible_side_effect_ |= !job->side_effect_free_get();
	ECHO("back from job " << *job
	      << (job->side_effect_free_get() ? " (side-effect free)" : ""));
	switch (job->state_get())
	{
	case running:
	  deadline = SCHED_IMMEDIATE;
	  break;
	case sleeping:
	  deadline = std::min(deadline, job->deadline_get());
	  break;
	default:
	  break;
	}
      }
      else
	jobs_.push_back(job);   // Job not started, keep it in queue
    }

    /// If during this cycle a new job has been created by an existing job,
    /// start it. Also start if a possible side effect happened, it may have
    /// occurred later then the waiting jobs in the cycle.
    if (jobs_to_start_ || possible_side_effect_)
      deadline = SCHED_IMMEDIATE;

    /// If we are ready to die and there are no jobs left, then die.
    if (ready_to_die_ && jobs_.empty())
      deadline = SCHED_EXIT;

    // Compute statistics
    if (at_least_one_started)
      stats_.add_sample(get_time_() - start_time);

    return deadline;
  }

  void
  Scheduler::resume_scheduler(rJob job)
  {
    // If the job has not terminated and is side-effect free, then we
    // assume it will not take a long time as we are probably evaluating
    // a condition. In order to reduce the number of cycles spent to evaluate
    // the condition, continue until it asks to be suspended in another
    // way or until it is no longer side-effect free.

    bool side_effect_free_save = job->side_effect_free_get();

    if (job->state_get() == running && side_effect_free_save)
      return;

    if (job->state_get() == running &&
	job->prio_get() >= PRIO_RT_MIN &&
	!job->frozen())
      return;

    // We may have to suspend the job several time in case it makes no sense
    // to start it back. Let's do it in a loop and we'll break when we want
    // to resume the job.

    while (true)
    {
      // Add the job at the end of the scheduler queue unless the job has
      // already terminated.
      if (!job->terminated())
	jobs_.push_back(job);

      // Switch back to the scheduler. But in the case this job has been
      // destroyed, erase the local variable first so that it doesn't keep
      // a reference on it which will never be destroyed.
      assert(current_job_ == job);
      ECHO(*job << " has " << (job->terminated() ? "" : "not ") << "terminated\n\t"
	   << "state: " << state_name(job->state_get()) << std::endl);
      Coro* current_coro = job->coro_get();
      if (job->terminated())
	job = 0;
      coroutine_switch_to(current_coro, coro_);

      // If we regain control, we are not dead.
      assert(job);

      // We regained control, we are again in the context of the job.
      assert(!current_job_);
      current_job_ = job;
      ECHO("job " << *job << " resumed");

      // Execute a deferred exception if any; this may break out of this loop
      job->check_for_pending_exception();

      // If we are not frozen, it is time to resume regular execution
      if (!job->frozen())
	break;

      // Ok, we are frozen. Let's requeue ourselves after setting
      // the side_effect_free flag, and we will be in waiting mode.
      job->side_effect_free_set(true);
      job->state_set(waiting);
    }

    // Check that we are not near exhausting the stack space.
    job->check_stack_space();

    // Restore the side_effect_free flag
    job->side_effect_free_set(side_effect_free_save);

    // Resume job execution
  }

  void
  Scheduler::killall_jobs()
  {
    ECHO("killing all jobs!");

    // Mark the scheduler as ready to die when all the jobs are
    // really dead.
    ready_to_die_ = true;

    // Since killing the current job will result in its immediate
    // termination, kill all other jobs before.
    foreach (rJob job, jobs_get())
      if (job != current_job_)
	job->terminate_now();
    if (current_job_)
      current_job_->terminate_now();
  }

  void
  Scheduler::signal_stop(const rTag& tag, boost::any payload)
  {
    // Tell the jobs that a tag has been stopped, ending with
    // the current job to avoid interrupting this method early.
    foreach (rJob job, jobs_get())
    {
      // Job started at this cycle, reset to avoid stack references.
      if (!job)
	continue;
      // Job to be started during this cycle.
      if (job->state_get() == to_start)
      {
	// Check if this job deserves to be removed.
	foreach (const rTag& t, job->tags_get())
	  if (t->derives_from(*tag))
	  {
	    pending_.remove(job);
	    continue;
	  }
      }
      // Any other non-current job.
      else if (job != current_job_)
	job->register_stopped_tag(tag, payload);
    }
    if (current_job_)
      current_job_->register_stopped_tag(tag, payload);
  }

  jobs_type
  Scheduler::jobs_get() const
  {
    // If this method is called from within a job, return the currently
    // executing jobs (pending_), otherwise return the jobs_ content which
    // is complete.
    return current_job_ ? pending_ : jobs_;
  }

  const scheduler_stats_type&
  Scheduler::stats_get() const
  {
    return stats_;
  }

} // namespace scheduler
<|endoftext|>


<commit_before>#pragma once

#include "gcd_utility.hpp"
#include "human_interface_device.hpp"
#include "spdlog_utility.hpp"

namespace krbn {
class hid_observer final {
public:
  // Signals

  boost::signals2::signal<void(std::shared_ptr<human_interface_device>)> device_observed;

  boost::signals2::signal<void(std::shared_ptr<human_interface_device>)> device_unobserved;

  // Methods

  hid_observer(std::shared_ptr<human_interface_device> human_interface_device) : human_interface_device_(human_interface_device),
                                                                                observed_(false) {
  }

  ~hid_observer(void) {
    unobserve();
  }

  bool get_observed(void) const {
    return observed_;
  }

  void observe(void) {
    gcd_utility::dispatch_sync_in_main_queue(^{
      log_reducer_.reset();

      timer_ = nullptr;

      timer_ = std::make_unique<gcd_utility::fire_while_false_timer>(
          3 * NSEC_PER_SEC,
          ^{
            if (auto hid = human_interface_device_.lock()) {
              if (hid->get_removed()) {
                return true;
              }

              if (observed_) {
                return true;
              }

              // ----------------------------------------
              auto r = hid->open();
              if (r != kIOReturnSuccess) {
                auto message = fmt::format("IOHIDDeviceOpen error: {0} ({1}) {2}",
                                           iokit_utility::get_error_name(r),
                                           r,
                                           hid->get_name_for_log());
                log_reducer_.error(message);
                return false;
              }

              // ----------------------------------------
              observed_ = true;

              device_observed(hid);

              hid->queue_start();
              hid->schedule();
            }

            return true;
          });
    });
  }

  void unobserve(void) {
    gcd_utility::dispatch_sync_in_main_queue(^{
      timer_ = nullptr;

      if (auto hid = human_interface_device_.lock()) {
        if (!observed_) {
          return;
        }

        hid->unschedule();
        hid->queue_stop();
        hid->close();

        observed_ = false;

        device_unobserved(hid);
      }
    });
  }

private:
  std::weak_ptr<human_interface_device> human_interface_device_;
  bool observed_;
  std::unique_ptr<gcd_utility::fire_while_false_timer> timer_;
  spdlog_utility::log_reducer log_reducer_;
};
} // namespace krbn
<commit_msg>add hid_observer::get_human_interface_device<commit_after>#pragma once

#include "gcd_utility.hpp"
#include "human_interface_device.hpp"
#include "spdlog_utility.hpp"

namespace krbn {
class hid_observer final {
public:
  // Signals

  boost::signals2::signal<void(std::shared_ptr<human_interface_device>)> device_observed;

  boost::signals2::signal<void(std::shared_ptr<human_interface_device>)> device_unobserved;

  // Methods

  hid_observer(std::shared_ptr<human_interface_device> human_interface_device) : human_interface_device_(human_interface_device),
                                                                                observed_(false) {
  }

  ~hid_observer(void) {
    unobserve();
  }

  std::weak_ptr<human_interface_device> get_human_interface_device(void) {
    return human_interface_device_;
  }

  bool get_observed(void) const {
    return observed_;
  }

  void observe(void) {
    gcd_utility::dispatch_sync_in_main_queue(^{
      log_reducer_.reset();

      timer_ = nullptr;

      timer_ = std::make_unique<gcd_utility::fire_while_false_timer>(
          3 * NSEC_PER_SEC,
          ^{
            if (auto hid = human_interface_device_.lock()) {
              if (hid->get_removed()) {
                return true;
              }

              if (observed_) {
                return true;
              }

              // ----------------------------------------
              auto r = hid->open();
              if (r != kIOReturnSuccess) {
                auto message = fmt::format("IOHIDDeviceOpen error: {0} ({1}) {2}",
                                           iokit_utility::get_error_name(r),
                                           r,
                                           hid->get_name_for_log());
                log_reducer_.error(message);
                return false;
              }

              // ----------------------------------------
              observed_ = true;

              device_observed(hid);

              hid->queue_start();
              hid->schedule();
            }

            return true;
          });
    });
  }

  void unobserve(void) {
    gcd_utility::dispatch_sync_in_main_queue(^{
      timer_ = nullptr;

      if (auto hid = human_interface_device_.lock()) {
        if (!observed_) {
          return;
        }

        hid->unschedule();
        hid->queue_stop();
        hid->close();

        observed_ = false;

        device_unobserved(hid);
      }
    });
  }

private:
  std::weak_ptr<human_interface_device> human_interface_device_;
  bool observed_;
  std::unique_ptr<gcd_utility::fire_while_false_timer> timer_;
  spdlog_utility::log_reducer log_reducer_;
};
} // namespace krbn
<|endoftext|>


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

#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <cassert>
#include <set>
#include <string>
#include <vector>

#include "diffn.h"

void do_print_ifdefs_recursively(std::vector<FileInfo> &files,
                                 const std::vector<std::string> &macro_names,
                                 bool use_only_simple_ifs,
                                 const std::string &output_name)
{
    const size_t num_files = files.size();

    /* If what's in "files" is all regular files, diff them.
     * Otherwise, try stepping through each directory in parallel. */
    FileInfo *sample_regular = NULL;
    FileInfo *sample_directory = NULL;
    for (size_t i=0; i < num_files; ++i) {
        if (files[i].fp == NULL) {
            files[i].fp = fopen(files[i].name.c_str(), "r");
            if (files[i].fp == NULL)
                continue;
        }
        fstat(fileno(files[i].fp), &files[i].stat);
        if (S_ISDIR(files[i].stat.st_mode)) {
            sample_directory = &files[i];
        } else if (S_ISREG(files[i].stat.st_mode)) {
            sample_regular = &files[i];
        }
    }

    if (sample_regular != NULL && sample_directory != NULL) {
        do_error("Input paths '%s' and '%s' cannot be merged because one is a directory\n"
                 "and the other is a regular file.\n"
                 "Incomplete output may have been left in the output directory.",
                 sample_directory->name.c_str(), sample_regular->name.c_str());
    }

    if (sample_regular != NULL) {
        /* Let's diff these files! */
        Difdef difdef(num_files);
        for (size_t i=0; i < num_files; ++i) {
            if (files[i].fp == NULL) {
                /* This file couldn't be opened, above. */
                continue;
            }
            assert(!S_ISDIR(files[i].stat.st_mode));
            if (S_ISREG(files[i].stat.st_mode)) {
                difdef.replace_file(i, files[i].fp);
            } else {
                difdef.replace_file(i, NULL);
            }
            fclose(files[i].fp);
        }

        Difdef::Diff diff = difdef.merge();

        /* Try to open the output file. */
        FILE *out = fopen(output_name.c_str(), "w");
        if (out == NULL) {
            do_error("Output file '%s': Cannot create file", output_name.c_str());
        }

        /* Print out the diff. */
        verify_properly_nested_directives(diff, &files[0]);
        do_print_using_ifdefs(diff, macro_names, use_only_simple_ifs, out);
        fclose(out);

    } else {
        /* Recursively diff the contents of these directories. */
        if (mkdir(output_name.c_str(), 0777)) {
            do_error("Output path '%s': Cannot create directory", output_name.c_str());
        }
        std::set<std::string> processed_filenames;
        processed_filenames.insert(".");
        processed_filenames.insert("..");
        for (size_t i=0; i < num_files; ++i) {
            if (files[i].fp == NULL)
                continue;
            DIR *dir = opendir(files[i].name.c_str());
            while (struct dirent *file = readdir(dir)) {
                std::string relative_name = file->d_name;
                if (processed_filenames.find(relative_name) != processed_filenames.end()) {
                    /* This filename was matched and handled earlier. */
                    continue;
                }
                processed_filenames.insert(relative_name);

                std::vector<FileInfo> subfiles(files.size());
                for (size_t j=0; j < num_files; ++j) {
                    subfiles[j].name = files[j].name + "/" + relative_name;
                }
                std::string suboutput_name = output_name + "/" + relative_name;
                do_print_ifdefs_recursively(subfiles, macro_names, use_only_simple_ifs,
                                            suboutput_name);
            }
        }
    }
}
<commit_msg>Stop leaking file handles in do_print_ifdefs_recursively().<commit_after>/*
 * Copyright (C) 2012 Arthur O'Dwyer
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <cassert>
#include <set>
#include <string>
#include <vector>

#include "diffn.h"

void do_print_ifdefs_recursively(std::vector<FileInfo> &files,
                                 const std::vector<std::string> &macro_names,
                                 bool use_only_simple_ifs,
                                 const std::string &output_name)
{
    const size_t num_files = files.size();

    /* If what's in "files" is all regular files, diff them.
     * Otherwise, try stepping through each directory in parallel. */
    FileInfo *sample_regular = NULL;
    FileInfo *sample_directory = NULL;
    for (size_t i=0; i < num_files; ++i) {
        if (files[i].fp == NULL) {
            files[i].fp = fopen(files[i].name.c_str(), "r");
            if (files[i].fp == NULL)
                continue;
        }
        fstat(fileno(files[i].fp), &files[i].stat);
        if (S_ISDIR(files[i].stat.st_mode)) {
            sample_directory = &files[i];
        } else if (S_ISREG(files[i].stat.st_mode)) {
            sample_regular = &files[i];
        }
    }

    if (sample_regular != NULL && sample_directory != NULL) {
        do_error("Input paths '%s' and '%s' cannot be merged because one is a directory\n"
                 "and the other is a regular file.\n"
                 "Incomplete output may have been left in the output directory.",
                 sample_directory->name.c_str(), sample_regular->name.c_str());
    }

    if (sample_regular != NULL) {
        /* Let's diff these files! */
        Difdef difdef(num_files);
        for (size_t i=0; i < num_files; ++i) {
            if (files[i].fp == NULL) {
                /* This file couldn't be opened, above. */
                continue;
            }
            assert(!S_ISDIR(files[i].stat.st_mode));
            if (S_ISREG(files[i].stat.st_mode)) {
                difdef.replace_file(i, files[i].fp);
            } else {
                difdef.replace_file(i, NULL);
            }
            fclose(files[i].fp);
        }

        Difdef::Diff diff = difdef.merge();

        /* Try to open the output file. */
        FILE *out = fopen(output_name.c_str(), "w");
        if (out == NULL) {
            do_error("Output file '%s': Cannot create file", output_name.c_str());
        }

        /* Print out the diff. */
        verify_properly_nested_directives(diff, &files[0]);
        do_print_using_ifdefs(diff, macro_names, use_only_simple_ifs, out);
        fclose(out);

    } else {
        /* Recursively diff the contents of these directories. */
        if (mkdir(output_name.c_str(), 0777)) {
            do_error("Output path '%s': Cannot create directory", output_name.c_str());
        }
        std::set<std::string> processed_filenames;
        processed_filenames.insert(".");
        processed_filenames.insert("..");
        for (size_t i=0; i < num_files; ++i) {
            if (files[i].fp == NULL)
                continue;
            fclose(files[i].fp);
            DIR *dir = opendir(files[i].name.c_str());
            assert(dir != NULL);
            while (struct dirent *file = readdir(dir)) {
                std::string relative_name = file->d_name;
                if (processed_filenames.find(relative_name) != processed_filenames.end()) {
                    /* This filename was matched and handled earlier. */
                    continue;
                }
                processed_filenames.insert(relative_name);

                std::vector<FileInfo> subfiles(files.size());
                for (size_t j=0; j < num_files; ++j) {
                    subfiles[j].name = files[j].name + "/" + relative_name;
                }
                std::string suboutput_name = output_name + "/" + relative_name;
                do_print_ifdefs_recursively(subfiles, macro_names, use_only_simple_ifs,
                                            suboutput_name);
            }
            closedir(dir);
        }
    }
}
<|endoftext|>


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

#include "reducer.h"

#include <colm/colm.h>
#include <colm/tree.h>

#include <errno.h>

using std::endl;
using std::ifstream;
extern colm_sections rlparse_object;

void TopLevel::loadMachineName( string data )
{
	/* Make/get the priority key. The name may have already been referenced
	 * and therefore exist. */
	PriorDictEl *priorDictEl;
	if ( pd->priorDict.insert( data, pd->fsmCtx->nextPriorKey, &priorDictEl ) )
		pd->fsmCtx->nextPriorKey += 1;
	pd->curDefPriorKey = priorDictEl->value;

	/* Make/get the local error key. */
	LocalErrDictEl *localErrDictEl;
	if ( pd->localErrDict.insert( data, pd->nextLocalErrKey, &localErrDictEl ) )
		pd->nextLocalErrKey += 1;
	pd->curDefLocalErrKey = localErrDictEl->value;
}

void TopLevel::tryMachineDef( InputLoc &loc, std::string name,
		MachineDef *machineDef, bool isInstance )
{
	GraphDictEl *newEl = pd->graphDict.insert( name );
	if ( newEl != 0 ) {
		/* New element in the dict, all good. */
		newEl->value = new VarDef( name, machineDef );
		newEl->isInstance = isInstance;
		newEl->loc = loc;
		newEl->value->isExport = exportContext[exportContext.length()-1];

		/* It it is an instance, put on the instance list. */
		if ( isInstance )
			pd->instanceList.append( newEl );
	}
	else {
		// Recover by ignoring the duplicate.
		pd->id->error(loc) << "fsm \"" << name << "\" previously defined" << endl;
	}
}

long TopLevel::tryLongScan( const InputLoc &loc, const char *data )
{
	/* Convert the priority number to a long. Check for overflow. */
	long priorityNum;
	errno = 0;

	long aug = strtol( data, 0, 10 );
	if ( errno == ERANGE && aug == LONG_MAX ) {
		/* Priority number too large. Recover by setting the priority to 0. */
		pd->id->error(loc) << "priority number " << data <<
				" overflows" << endl;
		priorityNum = 0;
	}
	else if ( errno == ERANGE && aug == LONG_MIN ) {
		/* Priority number too large in the neg. Recover by using 0. */
		pd->id->error(loc) << "priority number " << data <<
				" underflows" << endl;
		priorityNum = 0;
	}
	else {
		/* No overflow or underflow. */
		priorityNum = aug;
	}

	return priorityNum;
}

void TopLevel::include( const InputLoc &incLoc, bool fileSpecified, string fileName, string machine )
{
	/* Stash the current section name and pd. */
	string sectionName = pd->sectionName;
	ParseData *pd0 = pd;
	std::string foundFileName;

//	IncludeRec *el = id->includeDict.find( FnMachine( fileName, machine ) );
//	if ( el == 0 ) {
//		el = new IncludeRec( fileName, machine );

		const char **includeChecks = 0;
		long found = 0;

//		/* First collect the locations of the text using an include pass. */
//		IncludePass includePass( id, machine );
//		if ( id->inLibRagel && !fileSpecified ) {
//			el->foundFileName = curFileName;
//
//			/* In LibRagel and no file was specified in the include statement.
//			 * In this case we run the include pass on the input text supplied. */
//			includePass.reduceStr( fileName.c_str(), id->hostLang, id->input );
//		}
//		else {
			const char *inclSectionName = machine.c_str();

			/* Implement defaults for the input file and section name. */
			if ( inclSectionName == 0 )
				inclSectionName = sectionName.c_str();

			if ( fileSpecified )
				includeChecks = pd->id->makeIncludePathChecks( curFileName, fileName.c_str() );
			else {
				char *test = new char[strlen(curFileName)+1];
				strcpy( test, curFileName );

				includeChecks = new const char*[2];

				includeChecks[0] = test;
				includeChecks[1] = 0;
			}

			ifstream *inFile = pd->id->tryOpenInclude( includeChecks, found );
			if ( inFile == 0 ) {
				id->error(incLoc) << "include: failed to locate file" << endl;
				const char **tried = includeChecks;
				while ( *tried != 0 )
					id->error(incLoc) << "include: attempted: \"" << *tried++ << '\"' << endl;
			}
			else {
				delete inFile;
				foundFileName = curFileName;

//				/* Don't include anything that's already been included. */
//				if ( !pd->duplicateInclude( includeChecks[found], inclSectionName ) ) {
//					pd->includeHistory.push_back( IncludeHistoryItem(
//							includeChecks[found], inclSectionName ) );
//
//					/* Either we are not in the lib, or a file was specifed, use the
//					 * file-based include pass. */
//					includePass.reduceFile( includeChecks[found], id->hostLang );
//				}
			}
//		}

//		if ( includePass.incItems.length() == 0 ) {
//			pd->id->error(incLoc) << "could not find machine " << machine <<
//					" in " << fileName << endp;
//		}
//		else {
//			/* Load the data into include el. Save in the dict. */
//			loadIncludeData( el, includePass, includeChecks[found] );
//			id->includeDict.insert( el );
//			includePass.incItems.empty();
//		}
//	}

	const char *targetMachine0 = targetMachine;
	const char *searchMachine0 = searchMachine;

	includeDepth += 1;
	pd = 0;

	targetMachine = sectionName.c_str();
	searchMachine = machine.c_str();

	// std::cout << "reducing: " << includeChecks[found] << " d: " << includeDepth << std::endl;
	reduceFile( includeChecks[found] );
	// std::cout << "include complete d: " << includeDepth << std::endl;

	pd = pd0;
	includeDepth -= 1;

	targetMachine = targetMachine0;
	searchMachine = searchMachine0;
}

void TopLevel::reduceFile( const char *inputFileName )
{
	char idstr[64];
	sprintf( idstr, "%d", includeDepth );
	const char *argv[8];

	argv[0] = "rlparse";
	argv[1] = "toplevel-reduce-file";
	argv[2] = inputFileName;
	argv[3] = id->hostLang->rlhcArg;
	argv[4] = idstr;
	argv[5] = targetMachine == 0 ? "" : targetMachine;
	argv[6] = searchMachine == 0 ? "" : searchMachine;
	argv[7] = 0;

	const char *prevCurFileName = curFileName;
	curFileName = inputFileName;

	colm_program *program = colm_new_program( &rlparse_object );
	colm_set_debug( program, 0 );
	colm_set_reduce_ctx( program, this );
	colm_run_program( program, 7, argv );
	id->streamFileNames.append( colm_extract_fns( program ) );

	// std::cout << "colm-program done" << std::endl;

	int length = 0;
	const char *err = colm_error( program, &length );
	if ( err != 0 ) {
		// std::cout << "error" << std::endl;
		id->error_plain() << string( err, length ) << std::endl;
	}

	colm_delete_program( program );

	curFileName = prevCurFileName;

	// std::cout << "reduceFile complete" << std::endl;
}

void Import::tryMachineDef( const InputLoc &loc, std::string name,
		MachineDef *machineDef, bool isInstance )
{
	GraphDictEl *newEl = pd->graphDict.insert( name );
	if ( newEl != 0 ) {
		/* New element in the dict, all good. */
		newEl->value = new VarDef( name, machineDef );
		newEl->isInstance = isInstance;
		newEl->loc = loc;
		newEl->value->isExport = false; //exportContext[exportContext.length()-1];

		/* It it is an instance, put on the instance list. */
		if ( isInstance )
			pd->instanceList.append( newEl );
	}
	else {
		// Recover by ignoring the duplicate.
		pd->id->error(loc) << "fsm \"" << name << "\" previously defined" << endl;
	}
}

void Import::import( const InputLoc &loc, std::string name, Literal *literal )
{
	MachineDef *machineDef = new MachineDef(
			new Join(
				new Expression(
					new Term(
						new FactorWithAug(
							new FactorWithRep(
								new FactorWithNeg( new Factor( literal ) )
								)
							)
						)
					)
				)
			);

	/* Generic creation of machine for instantiation and assignment. */
	tryMachineDef( loc, name, machineDef, false );
	machineDef->join->loc = loc;
}

void Import::reduceImport( std::string fileName )
{
	const char *argv[5];
	argv[0] = "rlparse";
	argv[1] = "reduce-import";
	argv[2] = fileName.c_str();
	argv[3] = id->hostLang->rlhcArg;
	argv[4] = 0;

	const char *prevCurFileName = curFileName;
	curFileName = fileName.c_str();

	colm_program *program = colm_new_program( &rlparse_object );
	colm_set_debug( program, 0 );
	colm_set_reduce_ctx( program, this );
	colm_run_program( program, 4, argv );
	id->streamFileNames.append( colm_extract_fns( program ) );

	int length = 0;
	const char *err = colm_error( program, &length );
	if ( err != 0 )
		id->error_plain() << string( err, length ) << std::endl;

	colm_delete_program( program );

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

#include "reducer.h"

#include <colm/colm.h>
#include <colm/tree.h>

#include <errno.h>

using std::endl;
using std::ifstream;
extern colm_sections rlparse_object;

void TopLevel::loadMachineName( string data )
{
	/* Make/get the priority key. The name may have already been referenced
	 * and therefore exist. */
	PriorDictEl *priorDictEl;
	if ( pd->priorDict.insert( data, pd->fsmCtx->nextPriorKey, &priorDictEl ) )
		pd->fsmCtx->nextPriorKey += 1;
	pd->curDefPriorKey = priorDictEl->value;

	/* Make/get the local error key. */
	LocalErrDictEl *localErrDictEl;
	if ( pd->localErrDict.insert( data, pd->nextLocalErrKey, &localErrDictEl ) )
		pd->nextLocalErrKey += 1;
	pd->curDefLocalErrKey = localErrDictEl->value;
}

void TopLevel::tryMachineDef( InputLoc &loc, std::string name,
		MachineDef *machineDef, bool isInstance )
{
	GraphDictEl *newEl = pd->graphDict.insert( name );
	if ( newEl != 0 ) {
		/* New element in the dict, all good. */
		newEl->value = new VarDef( name, machineDef );
		newEl->isInstance = isInstance;
		newEl->loc = loc;
		newEl->value->isExport = exportContext[exportContext.length()-1];

		/* It it is an instance, put on the instance list. */
		if ( isInstance )
			pd->instanceList.append( newEl );
	}
	else {
		// Recover by ignoring the duplicate.
		pd->id->error(loc) << "fsm \"" << name << "\" previously defined" << endl;
	}
}

long TopLevel::tryLongScan( const InputLoc &loc, const char *data )
{
	/* Convert the priority number to a long. Check for overflow. */
	long priorityNum;
	errno = 0;

	long aug = strtol( data, 0, 10 );
	if ( errno == ERANGE && aug == LONG_MAX ) {
		/* Priority number too large. Recover by setting the priority to 0. */
		pd->id->error(loc) << "priority number " << data <<
				" overflows" << endl;
		priorityNum = 0;
	}
	else if ( errno == ERANGE && aug == LONG_MIN ) {
		/* Priority number too large in the neg. Recover by using 0. */
		pd->id->error(loc) << "priority number " << data <<
				" underflows" << endl;
		priorityNum = 0;
	}
	else {
		/* No overflow or underflow. */
		priorityNum = aug;
	}

	return priorityNum;
}

void TopLevel::include( const InputLoc &incLoc, bool fileSpecified, string fileName, string machine )
{
	/* Stash the current section name and pd. */
	string sectionName = pd->sectionName;
	ParseData *pd0 = pd;

	const char **includeChecks = 0;
	long found = 0;

	const char *inclSectionName = machine.c_str();

	/* Implement defaults for the input file and section name. */
	if ( inclSectionName == 0 )
		inclSectionName = sectionName.c_str();

	/* Build the include checks. */
	if ( fileSpecified )
		includeChecks = pd->id->makeIncludePathChecks( curFileName, fileName.c_str() );
	else {
		char *test = new char[strlen(curFileName)+1];
		strcpy( test, curFileName );

		includeChecks = new const char*[2];

		includeChecks[0] = test;
		includeChecks[1] = 0;
	}

	/* Try to find the file. */
	ifstream *inFile = pd->id->tryOpenInclude( includeChecks, found );
	if ( inFile == 0 ) {
		id->error(incLoc) << "include: failed to locate file" << endl;
		const char **tried = includeChecks;
		while ( *tried != 0 )
			id->error(incLoc) << "include: attempted: \"" << *tried++ << '\"' << endl;

		return;
	}

	delete inFile;

//	/* Don't include anything that's already been included. */
//	if ( !pd->duplicateInclude( includeChecks[found], inclSectionName ) ) {
//		pd->includeHistory.push_back( IncludeHistoryItem(
//				includeChecks[found], inclSectionName ) );
//
//		/* Either we are not in the lib, or a file was specifed, use the
//		 * file-based include pass. */
//		includePass.reduceFile( includeChecks[found], id->hostLang );
//	}

	const char *targetMachine0 = targetMachine;
	const char *searchMachine0 = searchMachine;

	includeDepth += 1;
	pd = 0;

	targetMachine = sectionName.c_str();
	searchMachine = machine.c_str();

	reduceFile( includeChecks[found] );

//	if ( includePass.incItems.length() == 0 ) {
//		pd->id->error(incLoc) << "could not find machine " << machine <<
//				" in " << fileName << endp;
//	}
//	else {
//		/* Load the data into include el. Save in the dict. */
//		loadIncludeData( el, includePass, includeChecks[found] );
//		id->includeDict.insert( el );
//		includePass.incItems.empty();
//	}

	pd = pd0;
	includeDepth -= 1;

	targetMachine = targetMachine0;
	searchMachine = searchMachine0;
}

void TopLevel::reduceFile( const char *inputFileName )
{
	char idstr[64];
	sprintf( idstr, "%d", includeDepth );
	const char *argv[8];

	argv[0] = "rlparse";
	argv[1] = "toplevel-reduce-file";
	argv[2] = inputFileName;
	argv[3] = id->hostLang->rlhcArg;
	argv[4] = idstr;
	argv[5] = targetMachine == 0 ? "" : targetMachine;
	argv[6] = searchMachine == 0 ? "" : searchMachine;
	argv[7] = 0;

	const char *prevCurFileName = curFileName;
	curFileName = inputFileName;

	colm_program *program = colm_new_program( &rlparse_object );
	colm_set_debug( program, 0 );
	colm_set_reduce_ctx( program, this );
	colm_run_program( program, 7, argv );
	id->streamFileNames.append( colm_extract_fns( program ) );

	// std::cout << "colm-program done" << std::endl;

	int length = 0;
	const char *err = colm_error( program, &length );
	if ( err != 0 ) {
		// std::cout << "error" << std::endl;
		id->error_plain() << string( err, length ) << std::endl;
	}

	colm_delete_program( program );

	curFileName = prevCurFileName;

	// std::cout << "reduceFile complete" << std::endl;
}

void Import::tryMachineDef( const InputLoc &loc, std::string name,
		MachineDef *machineDef, bool isInstance )
{
	GraphDictEl *newEl = pd->graphDict.insert( name );
	if ( newEl != 0 ) {
		/* New element in the dict, all good. */
		newEl->value = new VarDef( name, machineDef );
		newEl->isInstance = isInstance;
		newEl->loc = loc;
		newEl->value->isExport = false; //exportContext[exportContext.length()-1];

		/* It it is an instance, put on the instance list. */
		if ( isInstance )
			pd->instanceList.append( newEl );
	}
	else {
		// Recover by ignoring the duplicate.
		pd->id->error(loc) << "fsm \"" << name << "\" previously defined" << endl;
	}
}

void Import::import( const InputLoc &loc, std::string name, Literal *literal )
{
	MachineDef *machineDef = new MachineDef(
			new Join(
				new Expression(
					new Term(
						new FactorWithAug(
							new FactorWithRep(
								new FactorWithNeg( new Factor( literal ) )
								)
							)
						)
					)
				)
			);

	/* Generic creation of machine for instantiation and assignment. */
	tryMachineDef( loc, name, machineDef, false );
	machineDef->join->loc = loc;
}

void Import::reduceImport( std::string fileName )
{
	const char *argv[5];
	argv[0] = "rlparse";
	argv[1] = "reduce-import";
	argv[2] = fileName.c_str();
	argv[3] = id->hostLang->rlhcArg;
	argv[4] = 0;

	const char *prevCurFileName = curFileName;
	curFileName = fileName.c_str();

	colm_program *program = colm_new_program( &rlparse_object );
	colm_set_debug( program, 0 );
	colm_set_reduce_ctx( program, this );
	colm_run_program( program, 4, argv );
	id->streamFileNames.append( colm_extract_fns( program ) );

	int length = 0;
	const char *err = colm_error( program, &length );
	if ( err != 0 )
		id->error_plain() << string( err, length ) << std::endl;

	colm_delete_program( program );

	curFileName = prevCurFileName;
}
<|endoftext|>