<commit_before>/**
 * @file rules.cpp
 *
 * This file contains consensus rules and restrictions.
 */

#include "omnicore/rules.h"

#include "omnicore/log.h"
#include "omnicore/omnicore.h"
#include "omnicore/utilsbitcoin.h"

#include "script/standard.h"

#include <openssl/sha.h>
#include <stdint.h>

namespace mastercore
{

struct ConsensusCheckpoint
{
    int blockHeight;
    uint256 blockHash;
    uint256 consensusHash;
};

/** Checkpoints - block, block hash and consensus hash.
 */
static const ConsensusCheckpoint vCheckpoints[] = {
    { 250000, uint256("000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"),
              uint256("f8ca97346756bbe3b530d052c884b2f54c14edc1498ba2176214857dee13f3ca") },
    { 260000, uint256("000000000000001fb91fbcebaaba0e2d926f04908d798a8b598c3bd962951080"),
              uint256("e8b5445bbfc915e59164a6c22e4d84b23539569ee3c95b49eefaeaca86ea98a0") },
    { 270000, uint256("0000000000000002a775aec59dc6a9e4bb1c025cf1b8c2195dd9dc3998c827c5"),
              uint256("486a81cb5b0c89d26543e85f2635f225468e87bda89e752ab2dcebf1d2f74248") },
    { 280000, uint256("0000000000000001c091ada69f444dc0282ecaabe4808ddbb2532e5555db0c03"),
              uint256("801a9d4099802a49bdea1e7567680e11a50e120e5446a3be0a1c3757eff3b2b3") },
    { 290000, uint256("0000000000000000fa0b2badd05db0178623ebf8dd081fe7eb874c26e27d0b3b"),
              uint256("a6ad14928b6a96ca2c2b1426e264d5c461e723145c7169248dadb87b7693a7dd") },
    { 300000, uint256("000000000000000082ccf8f1557c5d40b21edabb18d2d691cfbf87118bac7254"),
              uint256("a26c7c6cea0ebbb52b7b75262e3c7ac036f6812b0f5b5b09c64efa5afacc6a83") },
    { 310000, uint256("0000000000000000125a28cc9e9209ddb75718f599a8039f6c9e7d9f1fb021e0"),
              uint256("73f207b07090f29aa9e7cc793e16b49ddd14ff201bbd1103c812ceabcf594b38") },
    { 320000, uint256("000000000000000015aab005b28a326ade60f07515c33517ea5cb598f28fb7ea"),
              uint256("0b510ba8e4ba26e563337053922b31a4f2ec78eac62f73b4b70bad7d026a0b65") },
    { 330000, uint256("00000000000000000faabab19f17c0178c754dbed023e6c871dcaf74159c5f02"),
              uint256("fb027d26256267583eed58d40c7330435f91b85014d7bbab452d1b47264a6e88") },
    { 340000, uint256("00000000000000000d9b2508615d569e18f00c034d71474fc44a43af8d4a5003"),
              uint256("510f73407a607d6b8c684a8a0bb70187802e418769adb8d30080bd46df71dab1") },
    { 350000, uint256("0000000000000000053cf64f0400bb38e0c4b3872c38795ddde27acb40a112bb"),
              uint256("7fdbd8b028dba2cb7253e29378c88e0411d883ccd49422230b446df4a17e3785") },
    { 360000, uint256("00000000000000000ca6e07cf681390ff888b7f96790286a440da0f2b87c8ea6"),
              uint256("943732e46304fc30099c6a728616c998efe689384f81b7108a65b051381656a6") },
};

/** A mapping of transaction types, versions and the blocks at which they are enabled.
 */
static const int txRestrictionsRules[][3] = {
    {MSC_TYPE_SIMPLE_SEND,                GENESIS_BLOCK,          MP_TX_PKT_V0},
    {MSC_TYPE_TRADE_OFFER,                MSC_DEX_BLOCK,          MP_TX_PKT_V1},
    {MSC_TYPE_ACCEPT_OFFER_BTC,           MSC_DEX_BLOCK,          MP_TX_PKT_V0},
    {MSC_TYPE_CREATE_PROPERTY_FIXED,      MSC_SP_BLOCK,           MP_TX_PKT_V0},
    {MSC_TYPE_CREATE_PROPERTY_VARIABLE,   MSC_SP_BLOCK,           MP_TX_PKT_V1},
    {MSC_TYPE_CLOSE_CROWDSALE,            MSC_SP_BLOCK,           MP_TX_PKT_V0},
    {MSC_TYPE_CREATE_PROPERTY_MANUAL,     MSC_MANUALSP_BLOCK,     MP_TX_PKT_V0},
    {MSC_TYPE_GRANT_PROPERTY_TOKENS,      MSC_MANUALSP_BLOCK,     MP_TX_PKT_V0},
    {MSC_TYPE_REVOKE_PROPERTY_TOKENS,     MSC_MANUALSP_BLOCK,     MP_TX_PKT_V0},
    {MSC_TYPE_CHANGE_ISSUER_ADDRESS,      MSC_MANUALSP_BLOCK,     MP_TX_PKT_V0},
    {MSC_TYPE_SEND_TO_OWNERS,             MSC_STO_BLOCK,          MP_TX_PKT_V0},
    {MSC_TYPE_METADEX_TRADE,              MSC_METADEX_BLOCK,      MP_TX_PKT_V0},
    {MSC_TYPE_METADEX_CANCEL_PRICE,       MSC_METADEX_BLOCK,      MP_TX_PKT_V0},
    {MSC_TYPE_METADEX_CANCEL_PAIR,        MSC_METADEX_BLOCK,      MP_TX_PKT_V0},
    {MSC_TYPE_METADEX_CANCEL_ECOSYSTEM,   MSC_METADEX_BLOCK,      MP_TX_PKT_V0},
    {MSC_TYPE_OFFER_ACCEPT_A_BET,         MSC_BET_BLOCK,          MP_TX_PKT_V0},

    // end of array marker, in addition to sizeof/sizeof
    {-1,-1},
};

/**
 * Checks, if the script type is allowed as input.
 */
bool IsAllowedInputType(int whichType, int nBlock)
{
    switch (whichType)
    {
        case TX_PUBKEYHASH:
            return true;

        case TX_SCRIPTHASH:
            return (P2SH_BLOCK <= nBlock || isNonMainNet());
    }

    return false;
}

/**
 * Checks, if the script type qualifies as output.
 */
bool IsAllowedOutputType(int whichType, int nBlock)
{
    switch (whichType)
    {
        case TX_PUBKEYHASH:
            return true;

        case TX_MULTISIG:
            return true;

        case TX_SCRIPTHASH:
            return (P2SH_BLOCK <= nBlock || isNonMainNet());

        case TX_NULL_DATA:
            return (OP_RETURN_BLOCK <= nBlock || isNonMainNet());
    }

    return false;
}

/**
 * Checks, if the transaction type and version is supported and enabled.
 *
 * Certain transaction types are not live/enabled until some specific block height.
 * Certain transactions will be unknown to the client, i.e. "black holes" based on their version.
 *
 * The restrictions array is as such:
 *   type, block-allowed-in, top-version-allowed
 */
bool IsTransactionTypeAllowed(int txBlock, uint32_t txProperty, uint16_t txType, uint16_t version, bool bAllowNullProperty) {
    bool bAllowed = false;
    bool bBlackHole = false;
    unsigned int type;
    int block_FirstAllowed;
    unsigned short version_TopAllowed;

    // bitcoin as property is never allowed, unless explicitly stated otherwise
    if ((OMNI_PROPERTY_BTC == txProperty) && !bAllowNullProperty) return false;

    // everything is always allowed on Bitcoin's TestNet or with TMSC/TestEcosystem on MainNet
    if (isNonMainNet() || isTestEcosystemProperty(txProperty)) {
        bAllowed = true;
    }

    for (unsigned int i = 0; i < sizeof(txRestrictionsRules)/sizeof(txRestrictionsRules[0]); i++) {
        type = txRestrictionsRules[i][0];
        block_FirstAllowed = txRestrictionsRules[i][1];
        version_TopAllowed = txRestrictionsRules[i][2];

        if (txType != type) continue;

        if (version_TopAllowed < version) {
            PrintToLog("Black Hole identified !!! %d, %u, %u, %u\n", txBlock, txProperty, txType, version);

            bBlackHole = true;

            // TODO: what else?
            // ...
        }

        if (0 > block_FirstAllowed) break; // array contains a negative -- nothing's allowed or done parsing

        if (block_FirstAllowed <= txBlock) bAllowed = true;
    }

    return bAllowed && !bBlackHole;
}

/** Obtains a hash of all balances to use for consensus verification & checkpointing. */
uint256 GetConsensusHash()
{
    // allocate and init a SHA256_CTX
    SHA256_CTX shaCtx;
    SHA256_Init(&shaCtx);

    LOCK(cs_tally);

    if (msc_debug_consensus_hash) PrintToLog("Beginning generation of current consensus hash...\n");

    // loop through the tally map, updating the sha context with the data from each balance & type
    for (std::map<string, CMPTally>::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) {
        const std::string& address = my_it->first;
        CMPTally& tally = my_it->second;
        tally.init();
        uint32_t propertyId;
        while (0 != (propertyId = (tally.next()))) {
            /*
            for maximum flexibility so other implementations (eg OmniWallet & Chest) can also apply this methodology without
            necessarily using the same exact data types (which would be needed to hash the data bytes directly), create a
            string in the following format for each address/property id combo to use for hashing:

                address|propertyid|balance|selloffer_reserve|accept_reserve|metadex_reserve

            note: pending tally is ignored
            */

            int64_t balance = tally.getMoney(propertyId, BALANCE);
            int64_t sellOfferReserve = tally.getMoney(propertyId, SELLOFFER_RESERVE);
            int64_t acceptReserve = tally.getMoney(propertyId, ACCEPT_RESERVE);
            int64_t metaDExReserve = tally.getMoney(propertyId, METADEX_RESERVE);

            // skip this entry if all balances are empty
            if (!balance && !sellOfferReserve && !acceptReserve && !metaDExReserve) continue;

            const std::string& dataStr = address + "|" + FormatIndivisibleMP(propertyId) + "|" +
                                         FormatIndivisibleMP(balance) + "|" +
                                         FormatIndivisibleMP(sellOfferReserve) + "|" +
                                         FormatIndivisibleMP(acceptReserve) + "|" +
                                         FormatIndivisibleMP(metaDExReserve);

            if (msc_debug_consensus_hash) PrintToLog("Adding data to consensus hash: %s\n", dataStr);

            // update the sha context with the data string
            SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
        }
    }

    // extract the final result and return the hash
    uint256 consensusHash;
    SHA256_Final((unsigned char*)&consensusHash, &shaCtx);
    if (msc_debug_consensus_hash) PrintToLog("Finished generation of consensus hash.  Result: %s\n", consensusHash.GetHex());

    return consensusHash;
}

/** Compares a supplied block, block hash and consensus hash against a hardcoded list of checkpoints */
bool VerifyCheckpoint(int block, uint256 blockHash)
{
    // checkpoints are only verified for mainnet
    if (isNonMainNet()) return true;

    for (unsigned int i = 0; i < sizeof(vCheckpoints)/sizeof(vCheckpoints[0]); i++) {
        if (block != vCheckpoints[i].blockHeight) continue;

        if (blockHash != vCheckpoints[i].blockHash) {
            PrintToLog("%s(): block hash mismatch - expected %s, received %s\n", __func__, vCheckpoints[i].blockHash.GetHex(), blockHash.GetHex());
            return false;
        }

        // only verify if there is a checkpoint to verify against
        uint256 consensusHash = GetConsensusHash();
        if (consensusHash != vCheckpoints[i].consensusHash) {
            PrintToLog("%s(): consensus hash mismatch - expected %s, received %s\n", __func__, vCheckpoints[i].consensusHash.GetHex(), consensusHash.GetHex());
//            return false;
        }
    }

    // either checkpoint matched or we don't have a checkpoint for this block
    return true;
}

} // namespace mastercore
<commit_msg>Remove bypass on checkpoints<commit_after>/**
 * @file rules.cpp
 *
 * This file contains consensus rules and restrictions.
 */

#include "omnicore/rules.h"

#include "omnicore/log.h"
#include "omnicore/omnicore.h"
#include "omnicore/utilsbitcoin.h"

#include "script/standard.h"

#include <openssl/sha.h>
#include <stdint.h>

namespace mastercore
{

struct ConsensusCheckpoint
{
    int blockHeight;
    uint256 blockHash;
    uint256 consensusHash;
};

/** Checkpoints - block, block hash and consensus hash.
 */
static const ConsensusCheckpoint vCheckpoints[] = {
    { 250000, uint256("000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"),
              uint256("f8ca97346756bbe3b530d052c884b2f54c14edc1498ba2176214857dee13f3ca") },
    { 260000, uint256("000000000000001fb91fbcebaaba0e2d926f04908d798a8b598c3bd962951080"),
              uint256("e8b5445bbfc915e59164a6c22e4d84b23539569ee3c95b49eefaeaca86ea98a0") },
    { 270000, uint256("0000000000000002a775aec59dc6a9e4bb1c025cf1b8c2195dd9dc3998c827c5"),
              uint256("486a81cb5b0c89d26543e85f2635f225468e87bda89e752ab2dcebf1d2f74248") },
    { 280000, uint256("0000000000000001c091ada69f444dc0282ecaabe4808ddbb2532e5555db0c03"),
              uint256("801a9d4099802a49bdea1e7567680e11a50e120e5446a3be0a1c3757eff3b2b3") },
    { 290000, uint256("0000000000000000fa0b2badd05db0178623ebf8dd081fe7eb874c26e27d0b3b"),
              uint256("a6ad14928b6a96ca2c2b1426e264d5c461e723145c7169248dadb87b7693a7dd") },
    { 300000, uint256("000000000000000082ccf8f1557c5d40b21edabb18d2d691cfbf87118bac7254"),
              uint256("a26c7c6cea0ebbb52b7b75262e3c7ac036f6812b0f5b5b09c64efa5afacc6a83") },
    { 310000, uint256("0000000000000000125a28cc9e9209ddb75718f599a8039f6c9e7d9f1fb021e0"),
              uint256("73f207b07090f29aa9e7cc793e16b49ddd14ff201bbd1103c812ceabcf594b38") },
    { 320000, uint256("000000000000000015aab005b28a326ade60f07515c33517ea5cb598f28fb7ea"),
              uint256("0b510ba8e4ba26e563337053922b31a4f2ec78eac62f73b4b70bad7d026a0b65") },
    { 330000, uint256("00000000000000000faabab19f17c0178c754dbed023e6c871dcaf74159c5f02"),
              uint256("fb027d26256267583eed58d40c7330435f91b85014d7bbab452d1b47264a6e88") },
    { 340000, uint256("00000000000000000d9b2508615d569e18f00c034d71474fc44a43af8d4a5003"),
              uint256("510f73407a607d6b8c684a8a0bb70187802e418769adb8d30080bd46df71dab1") },
    { 350000, uint256("0000000000000000053cf64f0400bb38e0c4b3872c38795ddde27acb40a112bb"),
              uint256("7fdbd8b028dba2cb7253e29378c88e0411d883ccd49422230b446df4a17e3785") },
    { 360000, uint256("00000000000000000ca6e07cf681390ff888b7f96790286a440da0f2b87c8ea6"),
              uint256("943732e46304fc30099c6a728616c998efe689384f81b7108a65b051381656a6") },
};

/** A mapping of transaction types, versions and the blocks at which they are enabled.
 */
static const int txRestrictionsRules[][3] = {
    {MSC_TYPE_SIMPLE_SEND,                GENESIS_BLOCK,          MP_TX_PKT_V0},
    {MSC_TYPE_TRADE_OFFER,                MSC_DEX_BLOCK,          MP_TX_PKT_V1},
    {MSC_TYPE_ACCEPT_OFFER_BTC,           MSC_DEX_BLOCK,          MP_TX_PKT_V0},
    {MSC_TYPE_CREATE_PROPERTY_FIXED,      MSC_SP_BLOCK,           MP_TX_PKT_V0},
    {MSC_TYPE_CREATE_PROPERTY_VARIABLE,   MSC_SP_BLOCK,           MP_TX_PKT_V1},
    {MSC_TYPE_CLOSE_CROWDSALE,            MSC_SP_BLOCK,           MP_TX_PKT_V0},
    {MSC_TYPE_CREATE_PROPERTY_MANUAL,     MSC_MANUALSP_BLOCK,     MP_TX_PKT_V0},
    {MSC_TYPE_GRANT_PROPERTY_TOKENS,      MSC_MANUALSP_BLOCK,     MP_TX_PKT_V0},
    {MSC_TYPE_REVOKE_PROPERTY_TOKENS,     MSC_MANUALSP_BLOCK,     MP_TX_PKT_V0},
    {MSC_TYPE_CHANGE_ISSUER_ADDRESS,      MSC_MANUALSP_BLOCK,     MP_TX_PKT_V0},
    {MSC_TYPE_SEND_TO_OWNERS,             MSC_STO_BLOCK,          MP_TX_PKT_V0},
    {MSC_TYPE_METADEX_TRADE,              MSC_METADEX_BLOCK,      MP_TX_PKT_V0},
    {MSC_TYPE_METADEX_CANCEL_PRICE,       MSC_METADEX_BLOCK,      MP_TX_PKT_V0},
    {MSC_TYPE_METADEX_CANCEL_PAIR,        MSC_METADEX_BLOCK,      MP_TX_PKT_V0},
    {MSC_TYPE_METADEX_CANCEL_ECOSYSTEM,   MSC_METADEX_BLOCK,      MP_TX_PKT_V0},
    {MSC_TYPE_OFFER_ACCEPT_A_BET,         MSC_BET_BLOCK,          MP_TX_PKT_V0},

    // end of array marker, in addition to sizeof/sizeof
    {-1,-1},
};

/**
 * Checks, if the script type is allowed as input.
 */
bool IsAllowedInputType(int whichType, int nBlock)
{
    switch (whichType)
    {
        case TX_PUBKEYHASH:
            return true;

        case TX_SCRIPTHASH:
            return (P2SH_BLOCK <= nBlock || isNonMainNet());
    }

    return false;
}

/**
 * Checks, if the script type qualifies as output.
 */
bool IsAllowedOutputType(int whichType, int nBlock)
{
    switch (whichType)
    {
        case TX_PUBKEYHASH:
            return true;

        case TX_MULTISIG:
            return true;

        case TX_SCRIPTHASH:
            return (P2SH_BLOCK <= nBlock || isNonMainNet());

        case TX_NULL_DATA:
            return (OP_RETURN_BLOCK <= nBlock || isNonMainNet());
    }

    return false;
}

/**
 * Checks, if the transaction type and version is supported and enabled.
 *
 * Certain transaction types are not live/enabled until some specific block height.
 * Certain transactions will be unknown to the client, i.e. "black holes" based on their version.
 *
 * The restrictions array is as such:
 *   type, block-allowed-in, top-version-allowed
 */
bool IsTransactionTypeAllowed(int txBlock, uint32_t txProperty, uint16_t txType, uint16_t version, bool bAllowNullProperty) {
    bool bAllowed = false;
    bool bBlackHole = false;
    unsigned int type;
    int block_FirstAllowed;
    unsigned short version_TopAllowed;

    // bitcoin as property is never allowed, unless explicitly stated otherwise
    if ((OMNI_PROPERTY_BTC == txProperty) && !bAllowNullProperty) return false;

    // everything is always allowed on Bitcoin's TestNet or with TMSC/TestEcosystem on MainNet
    if (isNonMainNet() || isTestEcosystemProperty(txProperty)) {
        bAllowed = true;
    }

    for (unsigned int i = 0; i < sizeof(txRestrictionsRules)/sizeof(txRestrictionsRules[0]); i++) {
        type = txRestrictionsRules[i][0];
        block_FirstAllowed = txRestrictionsRules[i][1];
        version_TopAllowed = txRestrictionsRules[i][2];

        if (txType != type) continue;

        if (version_TopAllowed < version) {
            PrintToLog("Black Hole identified !!! %d, %u, %u, %u\n", txBlock, txProperty, txType, version);

            bBlackHole = true;

            // TODO: what else?
            // ...
        }

        if (0 > block_FirstAllowed) break; // array contains a negative -- nothing's allowed or done parsing

        if (block_FirstAllowed <= txBlock) bAllowed = true;
    }

    return bAllowed && !bBlackHole;
}

/** Obtains a hash of all balances to use for consensus verification & checkpointing. */
uint256 GetConsensusHash()
{
    // allocate and init a SHA256_CTX
    SHA256_CTX shaCtx;
    SHA256_Init(&shaCtx);

    LOCK(cs_tally);

    if (msc_debug_consensus_hash) PrintToLog("Beginning generation of current consensus hash...\n");

    // loop through the tally map, updating the sha context with the data from each balance & type
    for (std::map<string, CMPTally>::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it) {
        const std::string& address = my_it->first;
        CMPTally& tally = my_it->second;
        tally.init();
        uint32_t propertyId;
        while (0 != (propertyId = (tally.next()))) {
            /*
            for maximum flexibility so other implementations (eg OmniWallet & Chest) can also apply this methodology without
            necessarily using the same exact data types (which would be needed to hash the data bytes directly), create a
            string in the following format for each address/property id combo to use for hashing:

                address|propertyid|balance|selloffer_reserve|accept_reserve|metadex_reserve

            note: pending tally is ignored
            */

            int64_t balance = tally.getMoney(propertyId, BALANCE);
            int64_t sellOfferReserve = tally.getMoney(propertyId, SELLOFFER_RESERVE);
            int64_t acceptReserve = tally.getMoney(propertyId, ACCEPT_RESERVE);
            int64_t metaDExReserve = tally.getMoney(propertyId, METADEX_RESERVE);

            // skip this entry if all balances are empty
            if (!balance && !sellOfferReserve && !acceptReserve && !metaDExReserve) continue;

            const std::string& dataStr = address + "|" + FormatIndivisibleMP(propertyId) + "|" +
                                         FormatIndivisibleMP(balance) + "|" +
                                         FormatIndivisibleMP(sellOfferReserve) + "|" +
                                         FormatIndivisibleMP(acceptReserve) + "|" +
                                         FormatIndivisibleMP(metaDExReserve);

            if (msc_debug_consensus_hash) PrintToLog("Adding data to consensus hash: %s\n", dataStr);

            // update the sha context with the data string
            SHA256_Update(&shaCtx, dataStr.c_str(), dataStr.length());
        }
    }

    // extract the final result and return the hash
    uint256 consensusHash;
    SHA256_Final((unsigned char*)&consensusHash, &shaCtx);
    if (msc_debug_consensus_hash) PrintToLog("Finished generation of consensus hash.  Result: %s\n", consensusHash.GetHex());

    return consensusHash;
}

/** Compares a supplied block, block hash and consensus hash against a hardcoded list of checkpoints */
bool VerifyCheckpoint(int block, uint256 blockHash)
{
    // checkpoints are only verified for mainnet
    if (isNonMainNet()) return true;

    for (unsigned int i = 0; i < sizeof(vCheckpoints)/sizeof(vCheckpoints[0]); i++) {
        if (block != vCheckpoints[i].blockHeight) continue;

        if (blockHash != vCheckpoints[i].blockHash) {
            PrintToLog("%s(): block hash mismatch - expected %s, received %s\n", __func__, vCheckpoints[i].blockHash.GetHex(), blockHash.GetHex());
            return false;
        }

        // only verify if there is a checkpoint to verify against
        uint256 consensusHash = GetConsensusHash();
        if (consensusHash != vCheckpoints[i].consensusHash) {
            PrintToLog("%s(): consensus hash mismatch - expected %s, received %s\n", __func__, vCheckpoints[i].consensusHash.GetHex(), consensusHash.GetHex());
            return false;
        }
    }

    // either checkpoint matched or we don't have a checkpoint for this block
    return true;
}

} // namespace mastercore
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
//  oryol-shdc
//------------------------------------------------------------------------------
#include "ExportUtil/CmdLineArgs.h"
#include "ExportUtil/Log.h"
#include "spirv_hlsl.hpp"
#include "spirv_msl.hpp"
#include "pystring.h"
#include "cJSON.h"
#include <stdio.h>

using namespace OryolTools;
using namespace spv;
using namespace spirv_cross;
using namespace std;

//------------------------------------------------------------------------------
vector<uint32_t> read_spirv_file(const string& path) {
    FILE* fp = fopen(path.c_str(), "rb");
    if (!fp) {
        Log::Fatal("Failed to open SPIRV file '%s'\n", path.c_str());
    }
    fseek(fp, 0, SEEK_END);
    long len = ftell(fp) / sizeof(uint32_t);
    fseek(fp, 0, SEEK_SET);
    vector<uint32_t> spirv(len);
    if (fread(spirv.data(), sizeof(uint32_t), len, fp) != size_t(len)) {
        Log::Fatal("Error reading SPIRV file '%s'\n", path.c_str());
    }
    fclose(fp);
    return spirv;
}

//------------------------------------------------------------------------------
void write_source_file(const string& path, const string& content) {
    FILE* fp = fopen(path.c_str(), "w");
    if (!fp) {
        Log::Fatal("Failed to open '%s' for writing\n", path.c_str());
    }
    fwrite(content.c_str(), 1, content.length(), fp);
    fclose(fp);
}

//------------------------------------------------------------------------------
const char* type_to_uniform_type(const SPIRType& type) {
    if (type.basetype == SPIRType::Float) {
        if (type.columns == 1) {
            // scalar or vec
            switch (type.vecsize) {
                case 1: return "float";
                case 2: return "vec2";
                case 3: return "vec3";
                case 4: return "vec4";
            }
        }
        else {
            // a matrix
            if ((type.vecsize == 2) && (type.columns == 2)) {
                return "mat2";
            }
            else if ((type.vecsize == 3) && (type.columns == 3)) {
                return "mat3";
            }
            else if ((type.vecsize == 4) && (type.columns == 4)) {
                return "mat4";
            }
        }
    }
    else if (type.basetype == SPIRType::Int) {
        return "int";
    }
    else if (type.basetype == SPIRType::Boolean) {
        return "bool";
    }
    Log::Fatal("Invalid member type in uniform block! (expected: float, vec2, vec3, vec4, mat2, mat3, mat4, int, bool)\n");
    return nullptr;
}

//------------------------------------------------------------------------------
const char* type_to_attr_format(const SPIRType& type) {
    if (type.basetype == SPIRType::Float && type.columns == 1) {
        switch (type.vecsize) {
            case 1: return "float";
            case 2: return "vec2";
            case 3: return "vec3";
            case 4: return "vec4";
        }
    }
    Log::Fatal("Invalid vertex attribute type! (expected: float, vec2, vec3, vec4)\n");
    return nullptr;
}

//------------------------------------------------------------------------------
cJSON* extract_resource_info(Compiler* compiler) {
    cJSON* root = cJSON_CreateObject();

    // shader stage
    const char* stage_str = nullptr;
    switch (compiler->get_execution_model()) {
        case ExecutionModelVertex: stage_str = "vs"; break;
        case ExecutionModelFragment: stage_str = "fs"; break;
        default: break;
    }
    if (stage_str) {
        cJSON_AddItemToObject(root, "stage", cJSON_CreateString(stage_str));
    }
    else {
        Log::Fatal("only vertex- or fragment-shaders allowed!\n");
    }

    // uniform blocks
    int ub_slot = 0;
    ShaderResources res = compiler->get_shader_resources();
    cJSON* ub_array = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "uniform_blocks", ub_array);
    for (const Resource& ub_res : res.uniform_buffers) {
        const SPIRType& ub_type = compiler->get_type(ub_res.base_type_id);
        string ub_name = compiler->get_name(ub_res.id);
        if (ub_name.empty()) {
            char buf[64];
            snprintf(buf, sizeof(buf), "_%d", ub_res.id);
            ub_name = buf;
        }
        cJSON* ub = cJSON_CreateObject();
        cJSON_AddItemToArray(ub_array, ub);
        cJSON_AddItemToObject(ub, "type", cJSON_CreateString(ub_res.name.c_str()));
        cJSON_AddItemToObject(ub, "name", cJSON_CreateString(ub_name.c_str()));
        cJSON_AddItemToObject(ub, "slot", cJSON_CreateNumber(ub_slot++));
        cJSON* ub_members = cJSON_CreateArray();
        cJSON_AddItemToObject(ub, "members", ub_members);
        for (int m_index = 0; m_index < int(ub_type.member_types.size()); m_index++) {
            cJSON* ub_member = cJSON_CreateObject();
            cJSON_AddItemToArray(ub_members, ub_member);
            string m_name = compiler->get_member_name(ub_res.base_type_id, m_index);
            const SPIRType& m_type = compiler->get_type(ub_type.member_types[m_index]);
            const char* m_type_str = type_to_uniform_type(m_type);
            cJSON_AddItemToObject(ub_member, "name", cJSON_CreateString(m_name.c_str()));
            cJSON_AddItemToObject(ub_member, "type", cJSON_CreateString(m_type_str));
            int num = 1;
            if (m_type.array.size() > 0) {
                num = m_type.array[0];
            }
            cJSON_AddItemToObject(ub_member, "num", cJSON_CreateNumber(num));
        }
    }

    // textures
    int tex_slot = 0;
    cJSON* tex_array = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "textures", tex_array);
    for (const Resource& img_res : res.sampled_images) {
        const SPIRType& img_type = compiler->get_type(img_res.type_id);
        cJSON* tex = cJSON_CreateObject();
        cJSON_AddItemToArray(tex_array, tex);
        const char* tex_type_str = nullptr;
        if (img_type.image.arrayed) {
            if (img_type.image.dim == Dim2D) {
                tex_type_str = "sampler2DArray";
            }
        }
        else {
            switch (img_type.image.dim) {
                case Dim2D:     tex_type_str = "sampler2D"; break;
                case DimCube:   tex_type_str = "samplerCube"; break;
                case Dim3D:     tex_type_str = "sampler3D"; break;
                default:        break;
            }
        }
        if (!tex_type_str) {
            Log::Fatal("Invalid texture type! (expected: 2D, Cube, 3D or 2D-array)\n");
        }
        cJSON_AddItemToObject(tex, "name", cJSON_CreateString(img_res.name.c_str()));
        cJSON_AddItemToObject(tex, "type", cJSON_CreateString(tex_type_str));
        cJSON_AddItemToObject(tex, "slot", cJSON_CreateNumber(tex_slot++));
    }

    // stage inputs
    cJSON* inputs_array = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "inputs", inputs_array);
    for (const Resource& stage_input : res.stage_inputs) {
        cJSON* input = cJSON_CreateObject();
        cJSON_AddItemToArray(inputs_array, input);
        const SPIRType& type = compiler->get_type(stage_input.base_type_id);
        const char* type_str = type_to_attr_format(type);
        cJSON_AddItemToObject(input, "name", cJSON_CreateString(stage_input.name.c_str()));
        cJSON_AddItemToObject(input, "type", cJSON_CreateString(type_str));
        if (compiler->get_execution_model() == ExecutionModelVertex) {
            uint32_t loc = compiler->get_decoration(stage_input.id, DecorationLocation);
            cJSON_AddItemToObject(input, "slot", cJSON_CreateNumber(loc));
        }
    }

    // stage outputs
    cJSON* outputs_array = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "outputs", outputs_array);
    for (const Resource& stage_output : res.stage_outputs) {
        cJSON* output = cJSON_CreateObject();
        cJSON_AddItemToArray(outputs_array, output);
        const SPIRType& type = compiler->get_type(stage_output.base_type_id);
        const char* type_str = type_to_attr_format(type);
        cJSON_AddItemToObject(output, "name", cJSON_CreateString(stage_output.name.c_str()));
        cJSON_AddItemToObject(output, "type", cJSON_CreateString(type_str));
    }

    return root;
}

//------------------------------------------------------------------------------
void fix_vertex_attr_locations(Compiler* compiler) {
    if (compiler->get_execution_model() == ExecutionModelVertex) {
        ShaderResources res = compiler->get_shader_resources();
        for (const auto& input : res.stage_inputs) {
            int loc = -1;
            if (input.name == "position")       loc = 0;
            else if (input.name == "normal")    loc = 1;
            else if (input.name == "texcoord0") loc = 2;
            else if (input.name == "texcoord1") loc = 3;
            else if (input.name == "texcoord2") loc = 4;
            else if (input.name == "texcoord3") loc = 5;
            else if (input.name == "tangent")   loc = 6;
            else if (input.name == "binormal")  loc = 7;
            else if (input.name == "weights")   loc = 8;
            else if (input.name == "indices")   loc = 9;
            else if (input.name == "color0")    loc = 10;
            else if (input.name == "color1")    loc = 11;
            else if (input.name == "instance0") loc = 12;
            else if (input.name == "instance1") loc = 13;
            else if (input.name == "instance2") loc = 14;
            else if (input.name == "instance3") loc = 15;
            if (-1 != loc) {
                compiler->set_decoration(input.id, DecorationLocation, (uint32_t)loc);
            }
        }
    }
}

//------------------------------------------------------------------------------
void to_reflection_json(const vector<uint32_t>& spirv, const string& base_path) {
    CompilerGLSL compiler(spirv);
    fix_vertex_attr_locations(&compiler);
    cJSON* json = extract_resource_info(&compiler);
    char* json_raw_str = cJSON_Print(json);
    string json_str(json_raw_str);
    std::free(json_raw_str);
    cJSON_Delete(json);
    write_source_file(base_path + ".json", json_str);
}

//------------------------------------------------------------------------------
void to_glsl(const vector<uint32_t>& spirv, const string& base_path, const string& file_ext, uint32_t version, bool is_es) {
    CompilerGLSL compiler(spirv);
    auto opts = compiler.get_options();
    opts.version = version;
    opts.es = is_es;
    opts.vertex.fixup_clipspace = false;
    compiler.set_options(opts);
    fix_vertex_attr_locations(&compiler);
    string src = compiler.compile();
    if (src.empty()) {
        Log::Fatal("Failed to compile GLSL v100 source for '%s'!\n", base_path.c_str());
    }
    else {
        write_source_file(base_path + file_ext, src);
    }
}

//------------------------------------------------------------------------------
void to_hlsl_sm5(const vector<uint32_t>& spirv, const string& base_path) {
    CompilerHLSL compiler(spirv);
    auto opts = compiler.get_options();
    opts.shader_model = 50;
    compiler.set_options(opts);
    fix_vertex_attr_locations(&compiler);
    string src = compiler.compile();
    if (src.empty()) {
        Log::Fatal("Failed to compile HLSL5 source for '%s'!\n", base_path.c_str());
    }
    else {
        write_source_file(base_path + ".hlsl", src);
    }
}

//------------------------------------------------------------------------------
void to_mlsl(const vector<uint32_t>& spirv, const string& base_path) {
    CompilerMSL compiler(spirv);
    fix_vertex_attr_locations(&compiler);
    string src = compiler.compile();
    if (src.empty()) {
        Log::Fatal("Failed to compile MetalSL source for '%s'!\n", base_path.c_str());
    }
    else {
        write_source_file(base_path + ".metal", src);
    }
}

//------------------------------------------------------------------------------
int main(int argc, const char** argv) {
    CmdLineArgs args;
    args.AddBool("-help", "show help");
    args.AddString("-spirv", "SPIR-V input file", "");
    if (!args.Parse(argc, argv)) {
        Log::Warn("Failed to parse args!\n");
        return 10;
    }

    if (args.HasArg("-help")) {
        Log::Info("Oryol SPIR-V to GLSL/HLSL/MSL cross-compiler\n"
                  "Based on SPIRV-Cross: https://github.com/KhronosGroup/SPIRV-Cross\n");
        args.ShowHelp();
        return 0;
    }
    string spirv_path = args.GetString("-spirv");
    if (spirv_path.empty()) {
        Log::Fatal("-spirv arg expected");
    }

    // load SPIRV byte code
    auto spirv = read_spirv_file(spirv_path);

    // ...translate and write to output files...
    string base_path, ext;
    pystring::os::path::splitext(base_path, ext, spirv_path);
    to_reflection_json(spirv, base_path);
    to_glsl(spirv, base_path, ".glsl100.glsl", 100, true);
    to_glsl(spirv, base_path, ".glsl120.glsl", 120, false);
    to_glsl(spirv, base_path, ".glsles3.glsl", 300, true);
    to_glsl(spirv, base_path, ".glsl330.glsl", 330, false);
    to_hlsl_sm5(spirv, base_path);
    to_mlsl(spirv, base_path);

    return 0;
}
<commit_msg>shdc: fixup_clipspace option for HLSL<commit_after>//------------------------------------------------------------------------------
//  oryol-shdc
//------------------------------------------------------------------------------
#include "ExportUtil/CmdLineArgs.h"
#include "ExportUtil/Log.h"
#include "spirv_hlsl.hpp"
#include "spirv_msl.hpp"
#include "pystring.h"
#include "cJSON.h"
#include <stdio.h>

using namespace OryolTools;
using namespace spv;
using namespace spirv_cross;
using namespace std;

//------------------------------------------------------------------------------
vector<uint32_t> read_spirv_file(const string& path) {
    FILE* fp = fopen(path.c_str(), "rb");
    if (!fp) {
        Log::Fatal("Failed to open SPIRV file '%s'\n", path.c_str());
    }
    fseek(fp, 0, SEEK_END);
    long len = ftell(fp) / sizeof(uint32_t);
    fseek(fp, 0, SEEK_SET);
    vector<uint32_t> spirv(len);
    if (fread(spirv.data(), sizeof(uint32_t), len, fp) != size_t(len)) {
        Log::Fatal("Error reading SPIRV file '%s'\n", path.c_str());
    }
    fclose(fp);
    return spirv;
}

//------------------------------------------------------------------------------
void write_source_file(const string& path, const string& content) {
    FILE* fp = fopen(path.c_str(), "w");
    if (!fp) {
        Log::Fatal("Failed to open '%s' for writing\n", path.c_str());
    }
    fwrite(content.c_str(), 1, content.length(), fp);
    fclose(fp);
}

//------------------------------------------------------------------------------
const char* type_to_uniform_type(const SPIRType& type) {
    if (type.basetype == SPIRType::Float) {
        if (type.columns == 1) {
            // scalar or vec
            switch (type.vecsize) {
                case 1: return "float";
                case 2: return "vec2";
                case 3: return "vec3";
                case 4: return "vec4";
            }
        }
        else {
            // a matrix
            if ((type.vecsize == 2) && (type.columns == 2)) {
                return "mat2";
            }
            else if ((type.vecsize == 3) && (type.columns == 3)) {
                return "mat3";
            }
            else if ((type.vecsize == 4) && (type.columns == 4)) {
                return "mat4";
            }
        }
    }
    else if (type.basetype == SPIRType::Int) {
        return "int";
    }
    else if (type.basetype == SPIRType::Boolean) {
        return "bool";
    }
    Log::Fatal("Invalid member type in uniform block! (expected: float, vec2, vec3, vec4, mat2, mat3, mat4, int, bool)\n");
    return nullptr;
}

//------------------------------------------------------------------------------
const char* type_to_attr_format(const SPIRType& type) {
    if (type.basetype == SPIRType::Float && type.columns == 1) {
        switch (type.vecsize) {
            case 1: return "float";
            case 2: return "vec2";
            case 3: return "vec3";
            case 4: return "vec4";
        }
    }
    Log::Fatal("Invalid vertex attribute type! (expected: float, vec2, vec3, vec4)\n");
    return nullptr;
}

//------------------------------------------------------------------------------
cJSON* extract_resource_info(Compiler* compiler) {
    cJSON* root = cJSON_CreateObject();

    // shader stage
    const char* stage_str = nullptr;
    switch (compiler->get_execution_model()) {
        case ExecutionModelVertex: stage_str = "vs"; break;
        case ExecutionModelFragment: stage_str = "fs"; break;
        default: break;
    }
    if (stage_str) {
        cJSON_AddItemToObject(root, "stage", cJSON_CreateString(stage_str));
    }
    else {
        Log::Fatal("only vertex- or fragment-shaders allowed!\n");
    }

    // uniform blocks
    int ub_slot = 0;
    ShaderResources res = compiler->get_shader_resources();
    cJSON* ub_array = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "uniform_blocks", ub_array);
    for (const Resource& ub_res : res.uniform_buffers) {
        const SPIRType& ub_type = compiler->get_type(ub_res.base_type_id);
        string ub_name = compiler->get_name(ub_res.id);
        if (ub_name.empty()) {
            char buf[64];
            snprintf(buf, sizeof(buf), "_%d", ub_res.id);
            ub_name = buf;
        }
        cJSON* ub = cJSON_CreateObject();
        cJSON_AddItemToArray(ub_array, ub);
        cJSON_AddItemToObject(ub, "type", cJSON_CreateString(ub_res.name.c_str()));
        cJSON_AddItemToObject(ub, "name", cJSON_CreateString(ub_name.c_str()));
        cJSON_AddItemToObject(ub, "slot", cJSON_CreateNumber(ub_slot++));
        cJSON* ub_members = cJSON_CreateArray();
        cJSON_AddItemToObject(ub, "members", ub_members);
        for (int m_index = 0; m_index < int(ub_type.member_types.size()); m_index++) {
            cJSON* ub_member = cJSON_CreateObject();
            cJSON_AddItemToArray(ub_members, ub_member);
            string m_name = compiler->get_member_name(ub_res.base_type_id, m_index);
            const SPIRType& m_type = compiler->get_type(ub_type.member_types[m_index]);
            const char* m_type_str = type_to_uniform_type(m_type);
            cJSON_AddItemToObject(ub_member, "name", cJSON_CreateString(m_name.c_str()));
            cJSON_AddItemToObject(ub_member, "type", cJSON_CreateString(m_type_str));
            int num = 1;
            if (m_type.array.size() > 0) {
                num = m_type.array[0];
            }
            cJSON_AddItemToObject(ub_member, "num", cJSON_CreateNumber(num));
        }
    }

    // textures
    int tex_slot = 0;
    cJSON* tex_array = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "textures", tex_array);
    for (const Resource& img_res : res.sampled_images) {
        const SPIRType& img_type = compiler->get_type(img_res.type_id);
        cJSON* tex = cJSON_CreateObject();
        cJSON_AddItemToArray(tex_array, tex);
        const char* tex_type_str = nullptr;
        if (img_type.image.arrayed) {
            if (img_type.image.dim == Dim2D) {
                tex_type_str = "sampler2DArray";
            }
        }
        else {
            switch (img_type.image.dim) {
                case Dim2D:     tex_type_str = "sampler2D"; break;
                case DimCube:   tex_type_str = "samplerCube"; break;
                case Dim3D:     tex_type_str = "sampler3D"; break;
                default:        break;
            }
        }
        if (!tex_type_str) {
            Log::Fatal("Invalid texture type! (expected: 2D, Cube, 3D or 2D-array)\n");
        }
        cJSON_AddItemToObject(tex, "name", cJSON_CreateString(img_res.name.c_str()));
        cJSON_AddItemToObject(tex, "type", cJSON_CreateString(tex_type_str));
        cJSON_AddItemToObject(tex, "slot", cJSON_CreateNumber(tex_slot++));
    }

    // stage inputs
    cJSON* inputs_array = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "inputs", inputs_array);
    for (const Resource& stage_input : res.stage_inputs) {
        cJSON* input = cJSON_CreateObject();
        cJSON_AddItemToArray(inputs_array, input);
        const SPIRType& type = compiler->get_type(stage_input.base_type_id);
        const char* type_str = type_to_attr_format(type);
        cJSON_AddItemToObject(input, "name", cJSON_CreateString(stage_input.name.c_str()));
        cJSON_AddItemToObject(input, "type", cJSON_CreateString(type_str));
        if (compiler->get_execution_model() == ExecutionModelVertex) {
            uint32_t loc = compiler->get_decoration(stage_input.id, DecorationLocation);
            cJSON_AddItemToObject(input, "slot", cJSON_CreateNumber(loc));
        }
    }

    // stage outputs
    cJSON* outputs_array = cJSON_CreateArray();
    cJSON_AddItemToObject(root, "outputs", outputs_array);
    for (const Resource& stage_output : res.stage_outputs) {
        cJSON* output = cJSON_CreateObject();
        cJSON_AddItemToArray(outputs_array, output);
        const SPIRType& type = compiler->get_type(stage_output.base_type_id);
        const char* type_str = type_to_attr_format(type);
        cJSON_AddItemToObject(output, "name", cJSON_CreateString(stage_output.name.c_str()));
        cJSON_AddItemToObject(output, "type", cJSON_CreateString(type_str));
    }

    return root;
}

//------------------------------------------------------------------------------
void fix_vertex_attr_locations(Compiler* compiler) {
    if (compiler->get_execution_model() == ExecutionModelVertex) {
        ShaderResources res = compiler->get_shader_resources();
        for (const auto& input : res.stage_inputs) {
            int loc = -1;
            if (input.name == "position")       loc = 0;
            else if (input.name == "normal")    loc = 1;
            else if (input.name == "texcoord0") loc = 2;
            else if (input.name == "texcoord1") loc = 3;
            else if (input.name == "texcoord2") loc = 4;
            else if (input.name == "texcoord3") loc = 5;
            else if (input.name == "tangent")   loc = 6;
            else if (input.name == "binormal")  loc = 7;
            else if (input.name == "weights")   loc = 8;
            else if (input.name == "indices")   loc = 9;
            else if (input.name == "color0")    loc = 10;
            else if (input.name == "color1")    loc = 11;
            else if (input.name == "instance0") loc = 12;
            else if (input.name == "instance1") loc = 13;
            else if (input.name == "instance2") loc = 14;
            else if (input.name == "instance3") loc = 15;
            if (-1 != loc) {
                compiler->set_decoration(input.id, DecorationLocation, (uint32_t)loc);
            }
        }
    }
}

//------------------------------------------------------------------------------
void to_reflection_json(const vector<uint32_t>& spirv, const string& base_path) {
    CompilerGLSL compiler(spirv);
    fix_vertex_attr_locations(&compiler);
    cJSON* json = extract_resource_info(&compiler);
    char* json_raw_str = cJSON_Print(json);
    string json_str(json_raw_str);
    std::free(json_raw_str);
    cJSON_Delete(json);
    write_source_file(base_path + ".json", json_str);
}

//------------------------------------------------------------------------------
void to_glsl(const vector<uint32_t>& spirv, const string& base_path, const string& file_ext, uint32_t version, bool is_es) {
    CompilerGLSL compiler(spirv);
    auto opts = compiler.get_options();
    opts.version = version;
    opts.es = is_es;
    opts.vertex.fixup_clipspace = false;
    compiler.set_options(opts);
    fix_vertex_attr_locations(&compiler);
    string src = compiler.compile();
    if (src.empty()) {
        Log::Fatal("Failed to compile GLSL v100 source for '%s'!\n", base_path.c_str());
    }
    else {
        write_source_file(base_path + file_ext, src);
    }
}

//------------------------------------------------------------------------------
void to_hlsl_sm5(const vector<uint32_t>& spirv, const string& base_path) {
    CompilerHLSL compiler(spirv);
    auto opts = compiler.get_options();
    opts.shader_model = 50;
    opts.fixup_clipspace = true;
    compiler.set_options(opts);
    fix_vertex_attr_locations(&compiler);
    string src = compiler.compile();
    if (src.empty()) {
        Log::Fatal("Failed to compile HLSL5 source for '%s'!\n", base_path.c_str());
    }
    else {
        write_source_file(base_path + ".hlsl", src);
    }
}

//------------------------------------------------------------------------------
void to_mlsl(const vector<uint32_t>& spirv, const string& base_path) {
    CompilerMSL compiler(spirv);
    fix_vertex_attr_locations(&compiler);
    string src = compiler.compile();
    if (src.empty()) {
        Log::Fatal("Failed to compile MetalSL source for '%s'!\n", base_path.c_str());
    }
    else {
        write_source_file(base_path + ".metal", src);
    }
}

//------------------------------------------------------------------------------
int main(int argc, const char** argv) {
    CmdLineArgs args;
    args.AddBool("-help", "show help");
    args.AddString("-spirv", "SPIR-V input file", "");
    if (!args.Parse(argc, argv)) {
        Log::Warn("Failed to parse args!\n");
        return 10;
    }

    if (args.HasArg("-help")) {
        Log::Info("Oryol SPIR-V to GLSL/HLSL/MSL cross-compiler\n"
                  "Based on SPIRV-Cross: https://github.com/KhronosGroup/SPIRV-Cross\n");
        args.ShowHelp();
        return 0;
    }
    string spirv_path = args.GetString("-spirv");
    if (spirv_path.empty()) {
        Log::Fatal("-spirv arg expected");
    }

    // load SPIRV byte code
    auto spirv = read_spirv_file(spirv_path);

    // ...translate and write to output files...
    string base_path, ext;
    pystring::os::path::splitext(base_path, ext, spirv_path);
    to_reflection_json(spirv, base_path);
    to_glsl(spirv, base_path, ".glsl100.glsl", 100, true);
    to_glsl(spirv, base_path, ".glsl120.glsl", 120, false);
    to_glsl(spirv, base_path, ".glsles3.glsl", 300, true);
    to_glsl(spirv, base_path, ".glsl330.glsl", 330, false);
    to_hlsl_sm5(spirv, base_path);
    to_mlsl(spirv, base_path);

    return 0;
}
<|endoftext|>


<commit_before>/******************************************************************
*
*  CyberLink for C++
*
*  Copyright (C) Satoshi Konno 2002
*
*  File: ServiceData.cpp
*
*  Revision;
*
*  04/26/04
*    - first revision
*  01/06/04
*    - Moved setQueryListener() and getQueryListener() to StateVariableData class.
*  05/19/04
*    - Changed the header include order for Cygwin.
*
******************************************************************/

#include <cybergarage/upnp/Service.h>
#include <cybergarage/upnp/xml/ServiceData.h>

using namespace CyberLink;

////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////

ServiceData::ServiceData()  {
  service = NULL;
  scpdNode = NULL;
}

////////////////////////////////////////////////
// scpdNode
////////////////////////////////////////////////

void ServiceData::setSCPDNode(CyberXML::Node *node) {
  if (scpdNode != NULL)
    delete scpdNode;
  scpdNode = node;
}

<commit_msg>* Fixed ServiceData::setSCPDNode() not to release a preset SCPD node.<commit_after>/******************************************************************
*
*  CyberLink for C++
*
*  Copyright (C) Satoshi Konno 2002
*
*  File: ServiceData.cpp
*
*  Revision;
*
*  04/26/04
*    - first revision
*  01/06/04
*    - Moved setQueryListener() and getQueryListener() to StateVariableData class.
*  05/19/04
*    - Changed the header include order for Cygwin.
*
******************************************************************/

#include <cybergarage/upnp/Service.h>
#include <cybergarage/upnp/xml/ServiceData.h>

using namespace CyberLink;

////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////

ServiceData::ServiceData()  {
  service = NULL;
  scpdNode = NULL;
}

////////////////////////////////////////////////
// scpdNode
////////////////////////////////////////////////

void ServiceData::setSCPDNode(CyberXML::Node *node) {
  scpdNode = node;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Freie Universität Berlin
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 */

/**
 * @defgroup    sys_arduino_api Arduino API
 * @ingroup     sys_arduino
 * @brief       Implementation of the Arduino API in RIOT
 * @{
 *
 * @file
 * @brief       Main interface definition of the Arduino API
 *
 * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
 */

#ifndef ARDUINO_HPP
#define ARDUINO_HPP

extern "C" {
#include <stdint.h>
#include "irq.h"
#include "periph/gpio.h"
#include "arduino_board.h"
}

#include "serialport.hpp"

/**
 * @brief    Arduino boolean data type definion
 */
typedef bool boolean;

/**
 * @brief    Arduino byte data type definion
 */
typedef uint8_t byte;

/**
 * @brief   Possible pin configurations
 */
enum {
    INPUT,              /**< configure pin as input */
    OUTPUT,             /**< configure pin as output */
    INPUT_PULLUP        /**< configure pin as input with pull-up resistor */
};

/**
 * @brief   Possible pin states
 */
enum {
    LOW = 0,            /**< pin is cleared */
    HIGH = 1            /**< pin is set */
};

#ifndef ARDUINO_UART_DEV
/**
 * @brief UART device to use for Arduino serial
 */
#define ARDUINO_UART_DEV        UART_DEV(0)
#endif

/**
 * @brief   Primary serial port (mapped to ARDUINO_UART_DEV)
 */
static SerialPort Serial(ARDUINO_UART_DEV);

/**
 * @brief   Configure a pin as either input or output
 *
 * @param[in] pin       pin to configure
 * @param[in] mode      mode to set the pin to
 */
void pinMode(int pin, int mode);

/**
 * @brief   Set the value for the given pin
 *
 * @param[in] pin       pin to set
 * @param[in] state     HIGH or LOW
 */
void digitalWrite(int pin, int state);

/**
 * @brief   Read the current state of the given pin
 *
 * @param[in] pin       pin to read
 *
 * @return  state of the given pin, HIGH or LOW
 */
int digitalRead(int pin);

/**
 * @brief   Sleep for a given amount of time [milliseconds]
 *
 * @param[in] msec      number of milliseconds to sleep
 */
void delay(unsigned long msec);

/**
 * @brief   Sleep for a given amount of time [microseconds]
 *
 * @param[in] usec      number of microseconds to sleep
 */
void delayMicroseconds(unsigned long usec);

/**
 * @brief   Returns the number of microseconds since start
 *
 * @return value of microseconds since start
 */
unsigned long micros();

/**
 * @brief   Returns the number of milliseconds since start
 *
 * @return value of milliseconds since start
 */
unsigned long millis();

#if MODULE_PERIPH_ADC || DOXYGEN
/**
 * @brief   Read the current value of the given analog pin
 *
 * @param[in] pin       pin to read
 *
 * @return a value between 0 to 1023 that is proportionnal
 * to the voltage applied to the pin
 */
int analogRead(int pin);
#endif

#if MODULE_PERIPH_PWM || DOXYGEN
/**
 * @brief   PWM default frequency
 *
 * Can be overridden at board level in arduino_board.h.
 *
 * See table from https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/
 * for reference values.
 */
#ifndef ARDUINO_PWM_FREQU
#define ARDUINO_PWM_FREQU           (1000U)
#endif

/**
 * @brief   PWM mode
 */
#define ARDUINO_PWM_MODE            PWM_LEFT

/**
 * @brief   PWM steps
 */
#define ARDUINO_PWM_STEPS           (256U)

/**
 * @brief   Write an analog value to a pin
 *
 * @param[in] pin       pin to write
 * @param[in] value     duty cycle value, between 0 and 255
 */
void analogWrite(int pin, int value);
#endif

/**
 * @brief   Enables interrupts
 */
static inline void interrupts(void)
{
    irq_enable();
}

/**
 * @brief   Disables interrupts
 */
static inline void noInterrupts(void)
{
    irq_disable();
}

#endif /* ARDUINO_HPP */
/** @} */
<commit_msg>sys/arduino: millis() expected to have C linkage<commit_after>/*
 * Copyright (C) 2015 Freie Universität Berlin
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 */

/**
 * @defgroup    sys_arduino_api Arduino API
 * @ingroup     sys_arduino
 * @brief       Implementation of the Arduino API in RIOT
 * @{
 *
 * @file
 * @brief       Main interface definition of the Arduino API
 *
 * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
 */

#ifndef ARDUINO_HPP
#define ARDUINO_HPP

extern "C" {
#include <stdint.h>
#include "irq.h"
#include "periph/gpio.h"
#include "arduino_board.h"

/**
 * @brief   Returns the number of milliseconds since start
 *
 * @return value of milliseconds since start
 */
unsigned long millis();
}

#include "serialport.hpp"

/**
 * @brief    Arduino boolean data type definion
 */
typedef bool boolean;

/**
 * @brief    Arduino byte data type definion
 */
typedef uint8_t byte;

/**
 * @brief   Possible pin configurations
 */
enum {
    INPUT,              /**< configure pin as input */
    OUTPUT,             /**< configure pin as output */
    INPUT_PULLUP        /**< configure pin as input with pull-up resistor */
};

/**
 * @brief   Possible pin states
 */
enum {
    LOW = 0,            /**< pin is cleared */
    HIGH = 1            /**< pin is set */
};

#ifndef ARDUINO_UART_DEV
/**
 * @brief UART device to use for Arduino serial
 */
#define ARDUINO_UART_DEV        UART_DEV(0)
#endif

/**
 * @brief   Primary serial port (mapped to ARDUINO_UART_DEV)
 */
static SerialPort Serial(ARDUINO_UART_DEV);

/**
 * @brief   Configure a pin as either input or output
 *
 * @param[in] pin       pin to configure
 * @param[in] mode      mode to set the pin to
 */
void pinMode(int pin, int mode);

/**
 * @brief   Set the value for the given pin
 *
 * @param[in] pin       pin to set
 * @param[in] state     HIGH or LOW
 */
void digitalWrite(int pin, int state);

/**
 * @brief   Read the current state of the given pin
 *
 * @param[in] pin       pin to read
 *
 * @return  state of the given pin, HIGH or LOW
 */
int digitalRead(int pin);

/**
 * @brief   Sleep for a given amount of time [milliseconds]
 *
 * @param[in] msec      number of milliseconds to sleep
 */
void delay(unsigned long msec);

/**
 * @brief   Sleep for a given amount of time [microseconds]
 *
 * @param[in] usec      number of microseconds to sleep
 */
void delayMicroseconds(unsigned long usec);

/**
 * @brief   Returns the number of microseconds since start
 *
 * @return value of microseconds since start
 */
unsigned long micros();

#if MODULE_PERIPH_ADC || DOXYGEN
/**
 * @brief   Read the current value of the given analog pin
 *
 * @param[in] pin       pin to read
 *
 * @return a value between 0 to 1023 that is proportionnal
 * to the voltage applied to the pin
 */
int analogRead(int pin);
#endif

#if MODULE_PERIPH_PWM || DOXYGEN
/**
 * @brief   PWM default frequency
 *
 * Can be overridden at board level in arduino_board.h.
 *
 * See table from https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/
 * for reference values.
 */
#ifndef ARDUINO_PWM_FREQU
#define ARDUINO_PWM_FREQU           (1000U)
#endif

/**
 * @brief   PWM mode
 */
#define ARDUINO_PWM_MODE            PWM_LEFT

/**
 * @brief   PWM steps
 */
#define ARDUINO_PWM_STEPS           (256U)

/**
 * @brief   Write an analog value to a pin
 *
 * @param[in] pin       pin to write
 * @param[in] value     duty cycle value, between 0 and 255
 */
void analogWrite(int pin, int value);
#endif

/**
 * @brief   Enables interrupts
 */
static inline void interrupts(void)
{
    irq_enable();
}

/**
 * @brief   Disables interrupts
 */
static inline void noInterrupts(void)
{
    irq_disable();
}

#endif /* ARDUINO_HPP */
/** @} */
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
{
	if (label == run_from)
		active = true;
	if (label == run_to)
		active = false;
	return active;
}

struct SynthXilinxPass : public Pass {
	SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    synth_xilinx [options]\n");
		log("\n");
		log("This command runs synthesis for Xilinx FPGAs. This command does not operate on\n");
		log("partly selected designs.\n");
		log("\n");
		log("    -top <module>\n");
		log("        use the specified module as top module (default='top')\n");
		log("\n");
		log("    -arch <arch>\n");
		log("        select architecture. the following architectures are supported:\n");
		log("            spartan6 (default), artix7, kintex7, virtex7, zynq7000\n");
		log("            (this parameter is not used by the command at the moment)\n");
		log("\n");
		log("    -edif <file>\n");
		log("        write the design to the specified edif file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -run <from_label>:<to_label>\n");
		log("        only run the commands between the labels (see below). an empty\n");
		log("        from label is synonymous to 'begin', and empty to label is\n");
		log("        synonymous to the end of the command list.\n");
		log("\n");
		log("\n");
		log("The following commands are executed by this synthesis command:\n");
		log("\n");
		log("    begin:\n");
		log("        hierarchy -check -top <top>\n");
		log("\n");
		log("    coarse:\n");
		log("        synth -run coarse\n");
		log("        memory_bram -rules +/xilinx/brams.txt\n");
		log("        techmap -map +/xilinx/brams.v\n");
		log("\n");
		log("    fine:\n");
		log("        synth -run fine\n");
		log("\n");
		log("    map_luts:\n");
		log("        abc -lut 6\n");
		log("        clean\n");
		log("\n");
		log("    map_cells:\n");
		log("        techmap -map +/xilinx/cells.v\n");
		log("        clean\n");
		log("\n");
		log("    flatten:\n");
		log("        flatten\n");
		log("        opt -fast -full\n");
		log("\n");
		log("    clkbuf:\n");
		log("        select -set xilinx_clocks <top>/t:FDRE %%x:+FDRE[C] <top>/t:FDRE %%d\n");
		log("        iopadmap -bits -inpad BUFGP O:I @xilinx_clocks\n");
		log("\n");
		log("    iobuf:\n");
		log("        select -set xilinx_nonclocks <top>/w:* <top>/t:BUFGP %%x:+BUFGP[I] %%d\n");
		log("        iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I @xilinx_nonclocks\n");
		log("\n");
		log("    edif:\n");
		log("        write_edif synth.edif\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		std::string top_module = "top";
		std::string arch_name = "spartan6";
		std::string edif_file;
		std::string run_from, run_to;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-top" && argidx+1 < args.size()) {
				top_module = args[++argidx];
				continue;
			}
			if (args[argidx] == "-arch" && argidx+1 < args.size()) {
				arch_name = args[++argidx];
				continue;
			}
			if (args[argidx] == "-edif" && argidx+1 < args.size()) {
				edif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-run" && argidx+1 < args.size()) {
				size_t pos = args[argidx+1].find(':');
				if (pos == std::string::npos)
					break;
				run_from = args[++argidx].substr(0, pos);
				run_to = args[argidx].substr(pos+1);
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		if (!design->full_selection())
			log_cmd_error("This comannd only operates on fully selected designs!\n");

		if (arch_name == "spartan6") {
			/* set flags */
		} else
		if (arch_name == "artix7") {
			/* set flags */
		} else
		if (arch_name == "kintex7") {
			/* set flags */
		} else
		if (arch_name == "zynq7000") {
			/* set flags */
		} else
			log_cmd_error("Architecture '%s' is not supported!\n", arch_name.c_str());

		bool active = run_from.empty();

		log_header("Executing SYNTH_XILINX pass.\n");
		log_push();

		if (check_label(active, run_from, run_to, "begin"))
		{
			Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str()));
		}

		if (check_label(active, run_from, run_to, "coarse"))
		{
			Pass::call(design, "synth -run coarse");
			Pass::call(design, "memory_bram -rules +/xilinx/brams.txt");
			Pass::call(design, "techmap -map +/xilinx/brams.v");
		}

		if (check_label(active, run_from, run_to, "fine"))
		{
			Pass::call(design, "synth -run fine");
		}

		if (check_label(active, run_from, run_to, "map_luts"))
		{
			Pass::call(design, "abc -lut 6");
			Pass::call(design, "clean");
		}

		if (check_label(active, run_from, run_to, "map_cells"))
		{
			Pass::call(design, "techmap -map +/xilinx/cells.v");
			Pass::call(design, "clean");
		}

		if (check_label(active, run_from, run_to, "flatten"))
		{
			Pass::call(design, "flatten");
			Pass::call(design, "opt -fast -full");
		}

		if (check_label(active, run_from, run_to, "clkbuf"))
		{
			Pass::call(design, stringf("select -set xilinx_clocks %s/t:FDRE %%x:+FDRE[C] %s/t:FDRE %%d", top_module.c_str(), top_module.c_str()));
			Pass::call(design, "iopadmap -bits -inpad BUFGP O:I @xilinx_clocks");
		}

		if (check_label(active, run_from, run_to, "iobuf"))
		{
			Pass::call(design, stringf("select -set xilinx_nonclocks %s/w:* %s/t:BUFGP %%x:+BUFGP[I] %%d", top_module.c_str(), top_module.c_str()));
			Pass::call(design, "iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I @xilinx_nonclocks");
		}

		if (check_label(active, run_from, run_to, "edif"))
		{
			if (!edif_file.empty())
				Pass::call(design, stringf("write_edif %s", edif_file.c_str()));
		}

		log_pop();
	}
} SynthXilinxPass;

PRIVATE_NAMESPACE_END
<commit_msg>Various cleanups in synth_xilinx command<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
{
	if (label == run_from)
		active = true;
	if (label == run_to)
		active = false;
	return active;
}

struct SynthXilinxPass : public Pass {
	SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    synth_xilinx [options]\n");
		log("\n");
		log("This command runs synthesis for Xilinx FPGAs. This command does not operate on\n");
		log("partly selected designs. At the moment this command creates netlists that are\n");
		log("compatible with 7-series and 6-series Xilinx devices.\n");
		log("\n");
		log("    -top <module>\n");
		log("        use the specified module as top module (default='top')\n");
		log("\n");
		log("    -edif <file>\n");
		log("        write the design to the specified edif file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -run <from_label>:<to_label>\n");
		log("        only run the commands between the labels (see below). an empty\n");
		log("        from label is synonymous to 'begin', and empty to label is\n");
		log("        synonymous to the end of the command list.\n");
		log("\n");
		log("\n");
		log("The following commands are executed by this synthesis command:\n");
		log("\n");
		log("    begin:\n");
		log("        hierarchy -check -top <top>\n");
		log("\n");
		log("    coarse:\n");
		log("        synth -run coarse\n");
		log("\n");
		log("    bram:\n");
		log("        memory_bram -rules +/xilinx/brams.txt\n");
		log("        techmap -map +/xilinx/brams.v\n");
		log("\n");
		log("    fine:\n");
		log("        synth -run fine\n");
		log("\n");
		log("    map_luts:\n");
		log("        abc -lut 6\n");
		log("        clean\n");
		log("\n");
		log("    map_cells:\n");
		log("        techmap -map +/xilinx/cells.v\n");
		log("        clean\n");
		log("\n");
		log("    edif:\n");
		log("        write_edif synth.edif\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		std::string top_module = "top";
		std::string arch_name = "spartan6";
		std::string edif_file;
		std::string run_from, run_to;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-top" && argidx+1 < args.size()) {
				top_module = args[++argidx];
				continue;
			}
			if (args[argidx] == "-edif" && argidx+1 < args.size()) {
				edif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-run" && argidx+1 < args.size()) {
				size_t pos = args[argidx+1].find(':');
				if (pos == std::string::npos)
					break;
				run_from = args[++argidx].substr(0, pos);
				run_to = args[argidx].substr(pos+1);
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		if (!design->full_selection())
			log_cmd_error("This comannd only operates on fully selected designs!\n");

		bool active = run_from.empty();

		log_header("Executing SYNTH_XILINX pass.\n");
		log_push();

		if (check_label(active, run_from, run_to, "begin"))
		{
			Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str()));
		}

		if (check_label(active, run_from, run_to, "coarse"))
		{
			Pass::call(design, "synth -run coarse");
		}

		if (check_label(active, run_from, run_to, "bram"))
		{
			Pass::call(design, "memory_bram -rules +/xilinx/brams.txt");
			Pass::call(design, "techmap -map +/xilinx/brams.v");
		}

		if (check_label(active, run_from, run_to, "fine"))
		{
			Pass::call(design, "synth -run fine");
		}

		if (check_label(active, run_from, run_to, "map_luts"))
		{
			Pass::call(design, "abc -lut 6");
			Pass::call(design, "clean");
		}

		if (check_label(active, run_from, run_to, "map_cells"))
		{
			Pass::call(design, "techmap -map +/xilinx/cells.v");
			Pass::call(design, "clean");
		}

		if (check_label(active, run_from, run_to, "edif"))
		{
			if (!edif_file.empty())
				Pass::call(design, stringf("write_edif %s", edif_file.c_str()));
		}

		log_pop();
	}
} SynthXilinxPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>/*
 * error.cpp
 *
 *  Created on: Feb 20, 2011
 *      Author: Peter Goodman
 *     Version: $Id$
 *
 * Copyright 2011 Peter Goodman, all rights reserved.
 */

#include "grail/include/io/error.hpp"

namespace grail { namespace io {

    enum {
        APPROX_LINE_SPLIT_POINT = 75
    };

    static void send_string(
        FILE *fp,
        const char *str,
        const char *pad,
        size_t pad_size,
        size_t *col
    ) {

        if(0 == str || '\0' == *str) {
            return;
        }

        size_t i(*col);
        for(; *str != '\0'; ++str, ++i) {
            if(' ' == *str) {
                if(i >= APPROX_LINE_SPLIT_POINT) {
                    fprintf(fp, "\n%s", pad);
                    i = pad_size;
                } else {
                    fprintf(fp, " ");
                }
            } else if('\n' == *str) {
                fprintf(fp, "\\n");
                i += 2;
            } else if('\t' == *str) {
                fprintf(fp, "\\t");
                i += 2;
            } else if('\r' == *str) {
                fprintf(fp, "\\r");
                i += 2;
            } else if('\b' == *str) {
                fprintf(fp, "\\b");
                i += 2;
            } else if('\v' == *str) {
                fprintf(fp, "\\v");
                i += 2;
            } else if('\a' == *str) {
                fprintf(fp, "\\a");
                i += 2;
            } else if('\f' == *str) {
                fprintf(fp, "\\f");
                i += 2;
            } else {
                fprintf(fp, "%c", *str);
            }
        }
        *col = i;
    }

    static void message(
        FILE *fp,
        const char *color,
        const char *type,
        const char *str,
        va_list args,
        const size_t start_col
    ) {

        char pad[64];
        char buff[129];
        char *curr_buff(&(buff[0]));
        char *end_buff(curr_buff + 128);

        memset(pad, 0, 64 * sizeof(char));
        memset(buff, 0, 129 * sizeof(char));

        fprintf(fp,
            FLTL_F_DEF FLTL_F_BOLD "%s%s: " FLTL_F_DEF,
            color, type
        );

        size_t pad_size(strlen(type) + 2);
        size_t col(pad_size + start_col);

        memset(pad, ' ', pad_size * sizeof(char));

        for(; '\0' != *str; ) {
            for(; curr_buff < end_buff && '\0' != *str; ++str, ++curr_buff) {
                ++col;
                if('%' == *str) {
                    ++str;

                    if('%' == *str) {
                        *curr_buff = *str;

                    } else {

                        // flush the buffer
                        *curr_buff = '\0';
                        fprintf(fp, "%s", buff);
                        curr_buff = &(buff[0]) - 1;

                        // string argument
                        if('s' == *str) {
                            send_string(
                                fp,
                                va_arg(args, const char *),
                                pad,
                                pad_size,
                                &col
                            );

                        // integer argument
                        } else if('d' == *str) {
                            col += fprintf(fp, "%d", va_arg(args, int));

                        // unsigned integer argument
                        } else if('u' == *str) {
                            col += fprintf(fp, "%u", va_arg(args, unsigned));

                        // character
                        } else if('c' == *str) {
                            col += fprintf(fp, "%c", static_cast<char>(va_arg(args, char)));
                        }
                    }
                } else if('\n' == *str) {
                    *curr_buff = '\0';
                    fprintf(fp, "%s\n%s", buff, pad);
                    curr_buff = &(buff[0]) - 1;
                    col = pad_size;

                } else if(' ' == *str) {
                    if(col >= APPROX_LINE_SPLIT_POINT) {
                        *curr_buff = '\0';
                        fprintf(fp, "%s\n%s", buff, pad);
                        curr_buff = &(buff[0]) - 1;
                        col = pad_size;
                    } else {
                        *curr_buff = ' ';
                    }
                } else {
                    *curr_buff = *str;
                }
            }

            // flush the buffer when it's full
            *curr_buff = '\0';
            fprintf(fp, "%s", buff);
            curr_buff = &(buff[0]);
        }
        fprintf(fp, "\n\n%s", FLTL_F_DEF);
    }

    void error(
        const char * const file_name,
        const unsigned line,
        const unsigned col,
        const char *str,
        ...
    ) {
        if(0 == str) {
            return;
        }

        int num(fprintf(stderr,
            FLTL_F_DEF FLTL_F_BOLD "%s:%u:%u: " FLTL_F_DEF ,
            file_name, line, col
        ));

        if(num < 0) {
            return;
        }

        va_list args;
        va_start(args, str);
        message(
            stderr,
            FLTL_F_RED, "error",
            str,
            args,
            static_cast<size_t>(num) - strlen(FLTL_F_DEF FLTL_F_BOLD FLTL_F_DEF)
        );
        va_end(args);
    }

    void error(const char *str, ...) {
        if(0 == str) {
            return;
        }
        va_list args;
        va_start(args, str);
        message(stderr, FLTL_F_RED, "error", str, args, 0);
        va_end(args);
    }

}}

<commit_msg>little fix.<commit_after>/*
 * error.cpp
 *
 *  Created on: Feb 20, 2011
 *      Author: Peter Goodman
 *     Version: $Id$
 *
 * Copyright 2011 Peter Goodman, all rights reserved.
 */

#include "grail/include/io/error.hpp"

namespace grail { namespace io {

    enum {
        APPROX_LINE_SPLIT_POINT = 75
    };

    static void send_string(
        FILE *fp,
        const char *str,
        const char *pad,
        size_t pad_size,
        size_t *col
    ) {

        if(0 == str || '\0' == *str) {
            return;
        }

        size_t i(*col);
        for(; *str != '\0'; ++str, ++i) {
            if(' ' == *str) {
                if(i >= APPROX_LINE_SPLIT_POINT) {
                    fprintf(fp, "\n%s", pad);
                    i = pad_size;
                } else {
                    fprintf(fp, " ");
                }
            } else if('\n' == *str) {
                fprintf(fp, "\\n");
                i += 2;
            } else if('\t' == *str) {
                fprintf(fp, "\\t");
                i += 2;
            } else if('\r' == *str) {
                fprintf(fp, "\\r");
                i += 2;
            } else if('\b' == *str) {
                fprintf(fp, "\\b");
                i += 2;
            } else if('\v' == *str) {
                fprintf(fp, "\\v");
                i += 2;
            } else if('\a' == *str) {
                fprintf(fp, "\\a");
                i += 2;
            } else if('\f' == *str) {
                fprintf(fp, "\\f");
                i += 2;
            } else {
                fprintf(fp, "%c", *str);
            }
        }
        *col = i;
    }

    static void message(
        FILE *fp,
        const char *color,
        const char *type,
        const char *str,
        va_list args,
        const size_t start_col
    ) {

        char pad[64];
        char buff[129];
        char *curr_buff(&(buff[0]));
        char *end_buff(curr_buff + 128);

        memset(pad, 0, 64 * sizeof(char));
        memset(buff, 0, 129 * sizeof(char));

        fprintf(fp,
            FLTL_F_DEF FLTL_F_BOLD "%s%s: " FLTL_F_DEF,
            color, type
        );

        size_t pad_size(strlen(type) + 2);
        size_t col(pad_size + start_col);

        memset(pad, ' ', pad_size * sizeof(char));

        for(; '\0' != *str; ) {
            for(; curr_buff < end_buff && '\0' != *str; ++str, ++curr_buff) {
                ++col;
                if('%' == *str) {
                    ++str;

                    if('%' == *str) {
                        *curr_buff = *str;

                    } else {

                        // flush the buffer
                        *curr_buff = '\0';
                        fprintf(fp, "%s", buff);
                        curr_buff = &(buff[0]) - 1;

                        // string argument
                        if('s' == *str) {
                            send_string(
                                fp,
                                va_arg(args, const char *),
                                pad,
                                pad_size,
                                &col
                            );

                        // integer argument
                        } else if('d' == *str) {
                            col += fprintf(fp, "%d", va_arg(args, int));

                        // unsigned integer argument
                        } else if('u' == *str) {
                            col += fprintf(fp, "%u", va_arg(args, unsigned));

                        // character
                        } else if('c' == *str) {
                            col += fprintf(fp, "%c", static_cast<char>(va_arg(args, int)));
                        }
                    }
                } else if('\n' == *str) {
                    *curr_buff = '\0';
                    fprintf(fp, "%s\n%s", buff, pad);
                    curr_buff = &(buff[0]) - 1;
                    col = pad_size;

                } else if(' ' == *str) {
                    if(col >= APPROX_LINE_SPLIT_POINT) {
                        *curr_buff = '\0';
                        fprintf(fp, "%s\n%s", buff, pad);
                        curr_buff = &(buff[0]) - 1;
                        col = pad_size;
                    } else {
                        *curr_buff = ' ';
                    }
                } else {
                    *curr_buff = *str;
                }
            }

            // flush the buffer when it's full
            *curr_buff = '\0';
            fprintf(fp, "%s", buff);
            curr_buff = &(buff[0]);
        }
        fprintf(fp, "\n\n%s", FLTL_F_DEF);
    }

    void error(
        const char * const file_name,
        const unsigned line,
        const unsigned col,
        const char *str,
        ...
    ) {
        if(0 == str) {
            return;
        }

        int num(fprintf(stderr,
            FLTL_F_DEF FLTL_F_BOLD "%s:%u:%u: " FLTL_F_DEF ,
            file_name, line, col
        ));

        if(num < 0) {
            return;
        }

        va_list args;
        va_start(args, str);
        message(
            stderr,
            FLTL_F_RED, "error",
            str,
            args,
            static_cast<size_t>(num) - strlen(FLTL_F_DEF FLTL_F_BOLD FLTL_F_DEF)
        );
        va_end(args);
    }

    void error(const char *str, ...) {
        if(0 == str) {
            return;
        }
        va_list args;
        va_start(args, str);
        message(stderr, FLTL_F_RED, "error", str, args, 0);
        va_end(args);
    }

}}

<|endoftext|>


<commit_before>// Copyright 2004-present Facebook. All Rights Reserved.

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <limits>
#include "src/AllowanceSemaphore.h"

using namespace ::testing;
using namespace ::reactivesocket;

TEST(AllowanceSemaphoreTest, Finite) {
  AllowanceSemaphore sem;

  ASSERT_FALSE(sem.isInfinite());
  ASSERT_FALSE(sem.canAcquire());
  ASSERT_FALSE(sem.tryAcquire());

  ASSERT_EQ(0U, sem.release(1));
  ASSERT_FALSE(sem.isInfinite());
  ASSERT_FALSE(sem.canAcquire(2));
  ASSERT_TRUE(sem.canAcquire());
  ASSERT_TRUE(sem.tryAcquire());

  ASSERT_EQ(0U, sem.release(2));
  ASSERT_EQ(2U, sem.release(1));
  ASSERT_EQ(3U, sem.drain());
  ASSERT_EQ(0U, sem.drain());

  ASSERT_EQ(0U, sem.release(2));
  ASSERT_FALSE(sem.isInfinite());
  ASSERT_FALSE(sem.canAcquire(3));
  ASSERT_FALSE(sem.tryAcquire(3));
  ASSERT_TRUE(sem.canAcquire(2));
  ASSERT_TRUE(sem.tryAcquire(2));
  ASSERT_FALSE(sem.canAcquire());
}

TEST(AllowanceSemaphoreTest, Infinite) {
  AllowanceSemaphore sem;

  auto infty = decltype(sem)::max();
  auto overHalfOfInfty = infty / 2 + 1;
  ASSERT_EQ(0U, sem.release(overHalfOfInfty));
  ASSERT_FALSE(sem.isInfinite());
  ASSERT_EQ(overHalfOfInfty, sem.release(overHalfOfInfty));
  ASSERT_TRUE(sem.isInfinite());
  ASSERT_TRUE(sem.tryAcquire());
  ASSERT_TRUE(sem.isInfinite());
  ASSERT_TRUE(sem.tryAcquire(overHalfOfInfty));
  ASSERT_TRUE(sem.tryAcquire(overHalfOfInfty));
  ASSERT_TRUE(sem.tryAcquire(overHalfOfInfty));
  ASSERT_TRUE(sem.isInfinite());
  ASSERT_EQ(infty, sem.drain());
  ASSERT_TRUE(sem.isInfinite());
  sem.reset();
  ASSERT_FALSE(sem.tryAcquire());
}

TEST(AllowanceSemaphoreTest, DrainWithLimit) {
  AllowanceSemaphore sem;

  ASSERT_EQ(0U, sem.release(9));
  ASSERT_EQ(4U, sem.drainWithLimit(4));
  ASSERT_EQ(1U, sem.drainWithLimit(1));
  ASSERT_EQ(4U, sem.drainWithLimit(100));
}
<commit_msg>fixing test<commit_after>// Copyright 2004-present Facebook. All Rights Reserved.

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <limits>
#include "src/AllowanceSemaphore.h"

using namespace ::testing;
using namespace ::reactivesocket;

TEST(AllowanceSemaphoreTest, Finite) {
  AllowanceSemaphore sem;

  ASSERT_FALSE(sem.isInfinite());
  ASSERT_FALSE(sem.canAcquire());
  ASSERT_FALSE(sem.tryAcquire());

  ASSERT_EQ(0U, sem.release(1));
  ASSERT_FALSE(sem.isInfinite());
  ASSERT_FALSE(sem.canAcquire(2));
  ASSERT_TRUE(sem.canAcquire());
  ASSERT_TRUE(sem.tryAcquire());

  ASSERT_EQ(0U, sem.release(2));
  ASSERT_EQ(2U, sem.release(1));
  ASSERT_EQ(3U, sem.drain());
  ASSERT_EQ(0U, sem.drain());

  ASSERT_EQ(0U, sem.release(2));
  ASSERT_FALSE(sem.isInfinite());
  ASSERT_FALSE(sem.canAcquire(3));
  ASSERT_FALSE(sem.tryAcquire(3));
  ASSERT_TRUE(sem.canAcquire(2));
  ASSERT_TRUE(sem.tryAcquire(2));
  ASSERT_FALSE(sem.canAcquire());
}

TEST(AllowanceSemaphoreTest, Infinite) {
  AllowanceSemaphore sem;

  auto infty = decltype(sem)::max();
  auto overHalfOfInfty = infty / 2 + 1;
  ASSERT_EQ(0U, sem.release(overHalfOfInfty));
  ASSERT_FALSE(sem.isInfinite());
  ASSERT_EQ(overHalfOfInfty, sem.release(overHalfOfInfty));
  ASSERT_TRUE(sem.isInfinite());
  ASSERT_TRUE(sem.tryAcquire());
  ASSERT_TRUE(sem.isInfinite());
  ASSERT_TRUE(sem.tryAcquire(overHalfOfInfty));
  ASSERT_TRUE(sem.tryAcquire(overHalfOfInfty));
  ASSERT_TRUE(sem.tryAcquire(overHalfOfInfty));
  ASSERT_TRUE(sem.isInfinite());
  ASSERT_EQ(infty, sem.drain());
  ASSERT_TRUE(sem.isInfinite());
}

TEST(AllowanceSemaphoreTest, DrainWithLimit) {
  AllowanceSemaphore sem;

  ASSERT_EQ(0U, sem.release(9));
  ASSERT_EQ(4U, sem.drainWithLimit(4));
  ASSERT_EQ(1U, sem.drainWithLimit(1));
  ASSERT_EQ(4U, sem.drainWithLimit(100));
}
<|endoftext|>


<commit_before>/*-----------------------------------------------------------------------------------------------
The MIT License (MIT)

Copyright (c) 2014 Kim Kulling

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 "gtest/gtest.h"

#include <openddlparser/OpenDDLParser.h>

BEGIN_ODDLPARSER_NS

class OpenDDLIntegrationTest : public testing::Test {
};

TEST_F( OpenDDLIntegrationTest, parseMetricTest ) {
    char token[] = "Metric( key = \"distance\" ) { float{ 1 } }";
    bool result( false );
    OpenDDLParser theParser;
    theParser.setBuffer( token, strlen( token ), false );
    result = theParser.parse();
    EXPECT_TRUE( result );

    DDLNode *myNode = theParser.getRoot();
    ASSERT_NE( nullptr, myNode );

    DDLNode::DllNodeList myList = myNode->getChildNodeList();
    EXPECT_EQ(1, myList.size() );
    DDLNode *child = myList[ 0 ];
    ASSERT_NE( nullptr, child );
    EXPECT_EQ( "Metric", child->getType() );
    Property *prop = child->getProperties();
    ASSERT_NE( nullptr, prop );

    const char *data = ( const char *) prop->m_primData->m_data;
    const int res( ::strncmp( "distance", data, strlen( "distance " ) ) );

    EXPECT_EQ( ddl_string, prop->m_primData->m_type );
    EXPECT_EQ( 0, res );
}

TEST_F( OpenDDLIntegrationTest, parseEmbeddedStructureTest ) {
    char token[] =
        "GeometryNode $node1\n"
        "{\n"
        "    string\n"
        "    {\n"
        "        \"test\"\n"
        "    }\n"
        "}";

    bool result( false );
    OpenDDLParser theParser;
    theParser.setBuffer( token, strlen( token ), false );
    result = theParser.parse();
    EXPECT_TRUE( result );

    DDLNode *root( theParser.getRoot() );
    ASSERT_NE( nullptr, root );
}

TEST_F( OpenDDLIntegrationTest, parseOpenGEXTest ) {
    char token[] =
        "GeometryNode $node1\n"
        "{\n"
        "    Name{ string{ \"Box001\" } }\n"
        "    ObjectRef{ ref{ $geometry1 } }\n"
        "    MaterialRef{ ref{ $material1 } }\n"
        "\n"
        "    Transform\n"
        "    {\n"
        "        float[ 16 ]\n"
        "        {\n"
        "            {0x3F800000, 0x00000000, 0x00000000, 0x00000000,		// {1, 0, 0, 0\n"
        "                0x00000000, 0x3F800000, 0x00000000, 0x00000000,		//  0, 1, 0, 0\n"
        "                0x00000000, 0x00000000, 0x3F800000, 0x00000000,		//  0, 0, 1, 0\n"
        "                0xBEF33B00, 0x411804DE, 0x00000000, 0x3F800000}		//  -0.47506, 9.50119, 0, 1}\n"
        "        }\n"
        "    }\n"
        "}\n";
    bool result( false );
    OpenDDLParser theParser;
    theParser.setBuffer( token, strlen( token ), false );
    result = theParser.parse();
    EXPECT_TRUE( result );
}

END_ODDLPARSER_NS
<commit_msg>reformatting fixes.<commit_after>/*-----------------------------------------------------------------------------------------------
The MIT License (MIT)

Copyright (c) 2014 Kim Kulling

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 "gtest/gtest.h"

#include <openddlparser/OpenDDLParser.h>

BEGIN_ODDLPARSER_NS

class OpenDDLIntegrationTest : public testing::Test {
};

TEST_F( OpenDDLIntegrationTest, parseMetricTest ) {
    char token[] = "Metric( key = \"distance\" ) { float{ 1 } }";
    bool result( false );
    OpenDDLParser theParser;
    theParser.setBuffer( token, strlen( token ), false );
    result = theParser.parse();
    EXPECT_TRUE( result );

    DDLNode *myNode = theParser.getRoot();
    ASSERT_NE( nullptr, myNode );

    DDLNode::DllNodeList myList = myNode->getChildNodeList();
    EXPECT_EQ( 1, myList.size() );
    DDLNode *child = myList[ 0 ];
    ASSERT_NE( nullptr, child );
    EXPECT_EQ( "Metric", child->getType() );
    Property *prop = child->getProperties();
    ASSERT_NE( nullptr, prop );

    const char *data = ( const char *) prop->m_primData->m_data;
    const int res( ::strncmp( "distance", data, strlen( "distance" ) ) );

    EXPECT_EQ( ddl_string, prop->m_primData->m_type );
    EXPECT_EQ( 0, res );
}

TEST_F( OpenDDLIntegrationTest, parseEmbeddedStructureTest ) {
    char token[] =
        "GeometryNode $node1\n"
        "{\n"
        "    string\n"
        "    {\n"
        "        \"test\"\n"
        "    }\n"
        "}";

    bool result( false );
    OpenDDLParser theParser;
    theParser.setBuffer( token, strlen( token ), false );
    result = theParser.parse();
    EXPECT_TRUE( result );

    DDLNode *root( theParser.getRoot() );
    ASSERT_NE( nullptr, root );
}

TEST_F( OpenDDLIntegrationTest, parseOpenGEXTest ) {
    char token[] =
        "GeometryNode $node1\n"
        "{\n"
        "    Name{ string{ \"Box001\" } }\n"
        "    ObjectRef{ ref{ $geometry1 } }\n"
        "    MaterialRef{ ref{ $material1 } }\n"
        "\n"
        "    Transform\n"
        "    {\n"
        "        float[ 16 ]\n"
        "        {\n"
        "            {0x3F800000, 0x00000000, 0x00000000, 0x00000000,		// {1, 0, 0, 0\n"
        "             0x00000000, 0x3F800000, 0x00000000, 0x00000000,		//  0, 1, 0, 0\n"
        "             0x00000000, 0x00000000, 0x3F800000, 0x00000000,		//  0, 0, 1, 0\n"
        "             0xBEF33B00, 0x411804DE, 0x00000000, 0x3F800000}		//  -0.47506, 9.50119, 0, 1}\n"
        "        }\n"
        "    }\n"
        "}\n";
    bool result( false );
    OpenDDLParser theParser;
    theParser.setBuffer( token, strlen( token ), false );
    result = theParser.parse();
    EXPECT_TRUE( result );
}

END_ODDLPARSER_NS
<|endoftext|>