<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.9  2003/06/20 18:58:45  peiyongz
 * Stateless Grammar Pool :: Part I
 *
 * Revision 1.8  2003/05/18 14:02:06  knoaman
 * Memory manager implementation: pass per instance manager.
 *
 * Revision 1.7  2003/05/16 21:43:20  knoaman
 * Memory manager implementation: Modify constructors to pass in the memory manager.
 *
 * Revision 1.6  2003/05/15 18:48:27  knoaman
 * Partial implementation of the configurable memory manager.
 *
 * Revision 1.5  2002/11/04 14:54:58  tng
 * C++ Namespace Support.
 *
 * Revision 1.4  2002/09/24 19:48:39  tng
 * Performance: use XMLString::equals instead of XMLString::compareString
 *
 * Revision 1.3  2002/07/12 14:35:37  knoaman
 * Add an error message and use it in the scanner.
 *
 * Revision 1.2  2002/07/11 18:17:43  knoaman
 * Grammar caching/preparsing - initial implementation.
 *
 * Revision 1.1.1.1  2002/02/01 22:22:38  peiyongz
 * sane_include
 *
 * Revision 1.5  2001/08/28 19:20:54  tng
 * Schema: xsi:type support
 *
 * Revision 1.4  2001/07/24 18:33:13  knoaman
 * Added support for <group> + extra constraint checking for complexType
 *
 * Revision 1.3  2001/06/07 20:58:39  tng
 * Fix no newline at the end warning.  By Pei Yong Zhang.
 *
 * Revision 1.2  2001/05/11 13:27:19  tng
 * Copyright update.
 *
 * Revision 1.1  2001/03/21 21:56:28  tng
 * Schema: Add Schema Grammar, Schema Validator, and split the DTDValidator into DTDValidator, DTDScanner, and DTDGrammar.
 *
 */

#include <xercesc/validators/common/GrammarResolver.hpp>
#include <xercesc/validators/schema/SchemaSymbols.hpp>
#include <xercesc/validators/schema/SchemaGrammar.hpp>
#include <xercesc/validators/schema/XMLSchemaDescriptionImpl.hpp>
#include <xercesc/validators/DTD/XMLDTDDescriptionImpl.hpp>

#include <xercesc/internal/XMLGrammarPoolImpl.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  GrammarResolver: Constructor and Destructor
// ---------------------------------------------------------------------------
GrammarResolver::GrammarResolver(XMLGrammarPool* const gramPool
                               , MemoryManager*  const manager)
:fCacheGrammar(false)
,fUseCachedGrammar(false)
,fGrammarPoolFromExternalApplication(true)
,fStringPool(109, manager)
,fGrammarBucket(0)
,fDataTypeReg(0)
,fMemoryManager(manager)
,fGrammarPool(gramPool)
{

    fGrammarBucket = new (manager) RefHashTableOf<GrammarEntry>(29, true,  manager);

    if (!gramPool)
    {
        /***
         * We need to instantiate a default grammar pool object so that
         * all grammars and grammar components could be created through
         * the Factory methods
         */
        fGrammarPool = new (manager) XMLGrammarPoolImpl(manager);
        fGrammarPoolFromExternalApplication=false;
    }

}

GrammarResolver::~GrammarResolver()
{
    delete fGrammarBucket;

    if (fDataTypeReg)
      delete fDataTypeReg;

   /***
    *  delete the grammar pool iff it is created by this resolver
    */
   if (!fGrammarPoolFromExternalApplication)
       delete fGrammarPool;
}

// ---------------------------------------------------------------------------
//  GrammarResolver: Getter methods
// ---------------------------------------------------------------------------
DatatypeValidator*
GrammarResolver::getDatatypeValidator(const XMLCh* const uriStr,
                                      const XMLCh* const localPartStr) {

    DatatypeValidator* dv = 0;

    if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {

        if (!fDataTypeReg) {

            fDataTypeReg = new (fMemoryManager) DatatypeValidatorFactory(fMemoryManager);
            fDataTypeReg->expandRegistryToFullSchemaSet();
        }

        dv = fDataTypeReg->getDatatypeValidator(localPartStr);
    }
    else {

        Grammar* grammar = getGrammar(uriStr);

        if (grammar && grammar->getGrammarType() == Grammar::SchemaGrammarType) {

            XMLBuffer nameBuf(128, fMemoryManager);

            nameBuf.set(uriStr);
            nameBuf.append(chComma);
            nameBuf.append(localPartStr);

            dv = ((SchemaGrammar*) grammar)->getDatatypeRegistry()->getDatatypeValidator(nameBuf.getRawBuffer());
        }
    }

    return dv;
}

//Deprecated
Grammar* GrammarResolver::getGrammar(const XMLCh* const nameSpaceKey)
{
    if (!nameSpaceKey)
        return 0;

    // we don't care the leakage
    XMLGrammarDescription* gramDesc = getGrammarDescription(nameSpaceKey);
    return getGrammar(gramDesc);

}

Grammar* GrammarResolver::getGrammar( XMLGrammarDescription* const gramDesc)
{
    if (!gramDesc)
        return 0;

    GrammarEntry* gramEntry = fGrammarBucket->get(gramDesc->getGrammarKey());

    if (gramEntry)
        return gramEntry->getGrammar();

    /***
     * if not found locally, try grammarPool if necessary
     */
    if (fUseCachedGrammar)
        return fGrammarPool->retrieveGrammar(gramDesc);

    return 0;
}

RefHashTableOfEnumerator<GrammarEntry>
GrammarResolver::getGrammarEnumerator() const
{
    return RefHashTableOfEnumerator<GrammarEntry>(fGrammarBucket);
}

bool GrammarResolver::containsNameSpace( const XMLCh* const nameSpaceKey )
{
   return fGrammarBucket->containsKey( nameSpaceKey );
}

//Deprecated
void GrammarResolver::putGrammar( const XMLCh* const nameSpaceKey, Grammar* const grammarToAdopt )
{
    // we don't care the leakage
    XMLGrammarDescription* gramDesc = getGrammarDescription(nameSpaceKey);
    putGrammar(gramDesc, grammarToAdopt);
}

void GrammarResolver::putGrammar(XMLGrammarDescription* const gramDesc, Grammar* const grammarToAdopt)
{
    if (!gramDesc || !grammarToAdopt)
        return;

    /***
     * the grammar will be either in the grammarpool, or in the grammarbucket
     */
    if (fCacheGrammar)
       fGrammarPool->cacheGrammar(gramDesc, grammarToAdopt);
    else
    {
        /***
         * The grammarEntry in the GrammarBucket can use the parser's memory,
         * since itself won't go into the GrammarPool while its contained
         * GrammarDescription and Grammar will.
         */
        GrammarEntry *theEntry = new (fMemoryManager) GrammarEntry(gramDesc, grammarToAdopt);
        fGrammarBucket->put( (void*) gramDesc->getGrammarKey(), theEntry );
    }

}

// ---------------------------------------------------------------------------
//  GrammarResolver: methods
// ---------------------------------------------------------------------------
void GrammarResolver::reset() {
   fGrammarBucket->removeAll();
}

void GrammarResolver::resetCachedGrammar()
{
    fGrammarPool->clear();

}

void GrammarResolver::cacheGrammars()
{
    RefHashTableOfEnumerator<GrammarEntry> grammarEnum(fGrammarBucket);

    /***
     * It is up to the GrammarPool to handle duplicated grammar
     *
     * Destroy the grammarEntry but reuse the grammar and description
     * embedded.
     *
     */
    while (grammarEnum.hasMoreElements())
    {
        XMLCh* grammarKey = (XMLCh*) grammarEnum.nextElementKey();
        GrammarEntry* theEntry = fGrammarBucket->orphanKey(grammarKey);
        XMLGrammarDescription* description = theEntry->getDescription();
        Grammar*               grammar     = theEntry->getGrammar();
        theEntry->nullGrammar();
        theEntry->nullDescription();
        delete theEntry;

        fGrammarPool->cacheGrammar(description, grammar);
    }

}

// ---------------------------------------------------------------------------
//  GrammarResolver: Setter methods
// ---------------------------------------------------------------------------
void GrammarResolver::cacheGrammarFromParse(const bool aValue)
{

    fCacheGrammar = aValue;
    fGrammarBucket->removeAll();
    fGrammarBucket->setAdoptElements(!fCacheGrammar);
}

Grammar* GrammarResolver::orphanGrammar(const XMLCh* const nameSpaceKey)
{
    // we don't care the leakage
    XMLGrammarDescription* gramDesc = getGrammarDescription(nameSpaceKey);
    return orphanGrammar(gramDesc);
}

Grammar* GrammarResolver::orphanGrammar(XMLGrammarDescription* const gramDesc)
{
    if (!gramDesc)
        return 0;

    if (fCacheGrammar)
        return fGrammarPool->orphanGrammar(gramDesc);

    GrammarEntry* theEntry = fGrammarBucket->orphanKey(gramDesc->getGrammarKey());
    if (theEntry)
    {
        Grammar* aGrammar = theEntry->getGrammar();
        theEntry->nullGrammar();
        delete theEntry;
        return aGrammar;
    }

    return 0;
}

XMLGrammarDescription* GrammarResolver::getGrammarDescription(const XMLCh* const nameSpaceKey)
{
    if (XMLString::equals(XMLUni::fgDTDEntityString, nameSpaceKey))
        return (XMLGrammarDescription*) fGrammarPool->createDTDDescription(nameSpaceKey);
    else
        return (XMLGrammarDescription*) fGrammarPool->createSchemaDescription(nameSpaceKey);
}

XERCES_CPP_NAMESPACE_END
<commit_msg>clean up temporary XMLGrammarDescription to make MemoryTest happy<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.10  2003/06/23 15:53:50  peiyongz
 * clean up temporary XMLGrammarDescription to make MemoryTest happy
 *
 * Revision 1.9  2003/06/20 18:58:45  peiyongz
 * Stateless Grammar Pool :: Part I
 *
 * Revision 1.8  2003/05/18 14:02:06  knoaman
 * Memory manager implementation: pass per instance manager.
 *
 * Revision 1.7  2003/05/16 21:43:20  knoaman
 * Memory manager implementation: Modify constructors to pass in the memory manager.
 *
 * Revision 1.6  2003/05/15 18:48:27  knoaman
 * Partial implementation of the configurable memory manager.
 *
 * Revision 1.5  2002/11/04 14:54:58  tng
 * C++ Namespace Support.
 *
 * Revision 1.4  2002/09/24 19:48:39  tng
 * Performance: use XMLString::equals instead of XMLString::compareString
 *
 * Revision 1.3  2002/07/12 14:35:37  knoaman
 * Add an error message and use it in the scanner.
 *
 * Revision 1.2  2002/07/11 18:17:43  knoaman
 * Grammar caching/preparsing - initial implementation.
 *
 * Revision 1.1.1.1  2002/02/01 22:22:38  peiyongz
 * sane_include
 *
 * Revision 1.5  2001/08/28 19:20:54  tng
 * Schema: xsi:type support
 *
 * Revision 1.4  2001/07/24 18:33:13  knoaman
 * Added support for <group> + extra constraint checking for complexType
 *
 * Revision 1.3  2001/06/07 20:58:39  tng
 * Fix no newline at the end warning.  By Pei Yong Zhang.
 *
 * Revision 1.2  2001/05/11 13:27:19  tng
 * Copyright update.
 *
 * Revision 1.1  2001/03/21 21:56:28  tng
 * Schema: Add Schema Grammar, Schema Validator, and split the DTDValidator into DTDValidator, DTDScanner, and DTDGrammar.
 *
 */

#include <xercesc/validators/common/GrammarResolver.hpp>
#include <xercesc/validators/schema/SchemaSymbols.hpp>
#include <xercesc/validators/schema/SchemaGrammar.hpp>
#include <xercesc/validators/schema/XMLSchemaDescriptionImpl.hpp>
#include <xercesc/validators/DTD/XMLDTDDescriptionImpl.hpp>

#include <xercesc/internal/XMLGrammarPoolImpl.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  GrammarResolver: Constructor and Destructor
// ---------------------------------------------------------------------------
GrammarResolver::GrammarResolver(XMLGrammarPool* const gramPool
                               , MemoryManager*  const manager)
:fCacheGrammar(false)
,fUseCachedGrammar(false)
,fGrammarPoolFromExternalApplication(true)
,fStringPool(109, manager)
,fGrammarBucket(0)
,fDataTypeReg(0)
,fMemoryManager(manager)
,fGrammarPool(gramPool)
{

    fGrammarBucket = new (manager) RefHashTableOf<GrammarEntry>(29, true,  manager);

    if (!gramPool)
    {
        /***
         * We need to instantiate a default grammar pool object so that
         * all grammars and grammar components could be created through
         * the Factory methods
         */
        fGrammarPool = new (manager) XMLGrammarPoolImpl(manager);
        fGrammarPoolFromExternalApplication=false;
    }

}

GrammarResolver::~GrammarResolver()
{
    delete fGrammarBucket;

    if (fDataTypeReg)
      delete fDataTypeReg;

   /***
    *  delete the grammar pool iff it is created by this resolver
    */
   if (!fGrammarPoolFromExternalApplication)
       delete fGrammarPool;
}

// ---------------------------------------------------------------------------
//  GrammarResolver: Getter methods
// ---------------------------------------------------------------------------
DatatypeValidator*
GrammarResolver::getDatatypeValidator(const XMLCh* const uriStr,
                                      const XMLCh* const localPartStr) {

    DatatypeValidator* dv = 0;

    if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {

        if (!fDataTypeReg) {

            fDataTypeReg = new (fMemoryManager) DatatypeValidatorFactory(fMemoryManager);
            fDataTypeReg->expandRegistryToFullSchemaSet();
        }

        dv = fDataTypeReg->getDatatypeValidator(localPartStr);
    }
    else {

        Grammar* grammar = getGrammar(uriStr);

        if (grammar && grammar->getGrammarType() == Grammar::SchemaGrammarType) {

            XMLBuffer nameBuf(128, fMemoryManager);

            nameBuf.set(uriStr);
            nameBuf.append(chComma);
            nameBuf.append(localPartStr);

            dv = ((SchemaGrammar*) grammar)->getDatatypeRegistry()->getDatatypeValidator(nameBuf.getRawBuffer());
        }
    }

    return dv;
}

//Deprecated
Grammar* GrammarResolver::getGrammar(const XMLCh* const nameSpaceKey)
{
    if (!nameSpaceKey)
        return 0;

    XMLGrammarDescription* gramDesc = getGrammarDescription(nameSpaceKey);
    Janitor<XMLGrammarDescription> janName(gramDesc);
    return getGrammar(gramDesc);

}

Grammar* GrammarResolver::getGrammar( XMLGrammarDescription* const gramDesc)
{
    if (!gramDesc)
        return 0;

    GrammarEntry* gramEntry = fGrammarBucket->get(gramDesc->getGrammarKey());

    if (gramEntry)
        return gramEntry->getGrammar();

    /***
     * if not found locally, try grammarPool if necessary
     */
    if (fUseCachedGrammar)
        return fGrammarPool->retrieveGrammar(gramDesc);

    return 0;
}

RefHashTableOfEnumerator<GrammarEntry>
GrammarResolver::getGrammarEnumerator() const
{
    return RefHashTableOfEnumerator<GrammarEntry>(fGrammarBucket);
}

bool GrammarResolver::containsNameSpace( const XMLCh* const nameSpaceKey )
{
   return fGrammarBucket->containsKey( nameSpaceKey );
}

//Deprecated
void GrammarResolver::putGrammar( const XMLCh* const nameSpaceKey, Grammar* const grammarToAdopt )
{
    XMLGrammarDescription* gramDesc = getGrammarDescription(nameSpaceKey);
    putGrammar(gramDesc, grammarToAdopt);
}

void GrammarResolver::putGrammar(XMLGrammarDescription* const gramDesc, Grammar* const grammarToAdopt)
{
    if (!gramDesc || !grammarToAdopt)
        return;

    /***
     * the grammar will be either in the grammarpool, or in the grammarbucket
     */
    if (fCacheGrammar)
       fGrammarPool->cacheGrammar(gramDesc, grammarToAdopt);
    else
    {
        /***
         * The grammarEntry in the GrammarBucket can use the parser's memory,
         * since itself won't go into the GrammarPool while its contained
         * GrammarDescription and Grammar will.
         */
        GrammarEntry *theEntry = new (fMemoryManager) GrammarEntry(gramDesc, grammarToAdopt);
        fGrammarBucket->put( (void*) gramDesc->getGrammarKey(), theEntry );
    }

}

// ---------------------------------------------------------------------------
//  GrammarResolver: methods
// ---------------------------------------------------------------------------
void GrammarResolver::reset() {
   fGrammarBucket->removeAll();
}

void GrammarResolver::resetCachedGrammar()
{
    fGrammarPool->clear();

}

void GrammarResolver::cacheGrammars()
{
    RefHashTableOfEnumerator<GrammarEntry> grammarEnum(fGrammarBucket);

    /***
     * It is up to the GrammarPool to handle duplicated grammar
     *
     * Destroy the grammarEntry but reuse the grammar and description
     * embedded.
     *
     */
    while (grammarEnum.hasMoreElements())
    {
        XMLCh* grammarKey = (XMLCh*) grammarEnum.nextElementKey();
        GrammarEntry* theEntry = fGrammarBucket->orphanKey(grammarKey);
        XMLGrammarDescription* description = theEntry->getDescription();
        Grammar*               grammar     = theEntry->getGrammar();
        theEntry->nullGrammar();
        theEntry->nullDescription();
        delete theEntry;

        fGrammarPool->cacheGrammar(description, grammar);
    }

}

// ---------------------------------------------------------------------------
//  GrammarResolver: Setter methods
// ---------------------------------------------------------------------------
void GrammarResolver::cacheGrammarFromParse(const bool aValue)
{

    fCacheGrammar = aValue;
    fGrammarBucket->removeAll();
    fGrammarBucket->setAdoptElements(!fCacheGrammar);
}

Grammar* GrammarResolver::orphanGrammar(const XMLCh* const nameSpaceKey)
{
    XMLGrammarDescription* gramDesc = getGrammarDescription(nameSpaceKey);
    Janitor<XMLGrammarDescription> janName(gramDesc);
    return orphanGrammar(gramDesc);
}

Grammar* GrammarResolver::orphanGrammar(XMLGrammarDescription* const gramDesc)
{
    if (!gramDesc)
        return 0;

    if (fCacheGrammar)
        return fGrammarPool->orphanGrammar(gramDesc);

    GrammarEntry* theEntry = fGrammarBucket->orphanKey(gramDesc->getGrammarKey());
    if (theEntry)
    {
        Grammar* aGrammar = theEntry->getGrammar();
        theEntry->nullGrammar();
        delete theEntry;
        return aGrammar;
    }

    return 0;
}

XMLGrammarDescription* GrammarResolver::getGrammarDescription(const XMLCh* const nameSpaceKey)
{
    if (XMLString::equals(XMLUni::fgDTDEntityString, nameSpaceKey))
        return (XMLGrammarDescription*) fGrammarPool->createDTDDescription(nameSpaceKey);
    else
        return (XMLGrammarDescription*) fGrammarPool->createSchemaDescription(nameSpaceKey);
}

XERCES_CPP_NAMESPACE_END
<|endoftext|>


<commit_before>// Copyright (c) 2012-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <addrman.h>
#include <test/test_bitcoin.h>
#include <string>
#include <boost/test/unit_test.hpp>
#include <hash.h>
#include <serialize.h>
#include <streams.h>
#include <net.h>
#include <netbase.h>
#include <chainparams.h>
#include <util/system.h>

#include <memory>

class CAddrManSerializationMock : public CAddrMan
{
public:
    virtual void Serialize(CDataStream& s) const = 0;

    //! Ensure that bucket placement is always the same for testing purposes.
    void MakeDeterministic()
    {
        nKey.SetNull();
        insecure_rand = FastRandomContext(true);
    }
};

class CAddrManUncorrupted : public CAddrManSerializationMock
{
public:
    void Serialize(CDataStream& s) const override
    {
        CAddrMan::Serialize(s);
    }
};

class CAddrManCorrupted : public CAddrManSerializationMock
{
public:
    void Serialize(CDataStream& s) const override
    {
        // Produces corrupt output that claims addrman has 20 addrs when it only has one addr.
        unsigned char nVersion = 1;
        s << nVersion;
        s << ((unsigned char)32);
        s << nKey;
        s << 10; // nNew
        s << 10; // nTried

        int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
        s << nUBuckets;

        CService serv;
        Lookup("252.1.1.1", serv, 7777, false);
        CAddress addr = CAddress(serv, NODE_NONE);
        CNetAddr resolved;
        LookupHost("252.2.2.2", resolved, false);
        CAddrInfo info = CAddrInfo(addr, resolved);
        s << info;
    }
};

static CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman)
{
    CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
    ssPeersIn << Params().MessageStart();
    ssPeersIn << _addrman;
    std::string str = ssPeersIn.str();
    std::vector<unsigned char> vchData(str.begin(), str.end());
    return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
}

BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(cnode_listen_port)
{
    // test default
    unsigned short port = GetListenPort();
    BOOST_CHECK(port == Params().GetDefaultPort());
    // test set port
    unsigned short altPort = 12345;
    gArgs.SoftSetArg("-port", std::to_string(altPort));
    port = GetListenPort();
    BOOST_CHECK(port == altPort);
}

BOOST_AUTO_TEST_CASE(caddrdb_read)
{
    SetDataDir("caddrdb_read");
    CAddrManUncorrupted addrmanUncorrupted;
    addrmanUncorrupted.MakeDeterministic();

    CService addr1, addr2, addr3;
    Lookup("250.7.1.1", addr1, 8333, false);
    Lookup("250.7.2.2", addr2, 9999, false);
    Lookup("250.7.3.3", addr3, 9999, false);

    // Add three addresses to new table.
    CService source;
    Lookup("252.5.1.1", source, 8333, false);
    addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), source);
    addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), source);
    addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), source);

    // Test that the de-serialization does not throw an exception.
    CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
    bool exceptionThrown = false;
    CAddrMan addrman1;

    BOOST_CHECK(addrman1.size() == 0);
    try {
        unsigned char pchMsgTmp[4];
        ssPeers1 >> pchMsgTmp;
        ssPeers1 >> addrman1;
    } catch (const std::exception&) {
        exceptionThrown = true;
    }

    BOOST_CHECK(addrman1.size() == 3);
    BOOST_CHECK(exceptionThrown == false);

    // Test that CAddrDB::Read creates an addrman with the correct number of addrs.
    CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);

    CAddrMan addrman2;
    CAddrDB adb;
    BOOST_CHECK(addrman2.size() == 0);
    adb.Read(addrman2, ssPeers2);
    BOOST_CHECK(addrman2.size() == 3);
}

BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
{
    SetDataDir("caddrdb_read_corrupted");
    CAddrManCorrupted addrmanCorrupted;
    addrmanCorrupted.MakeDeterministic();

    // Test that the de-serialization of corrupted addrman throws an exception.
    CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
    bool exceptionThrown = false;
    CAddrMan addrman1;
    BOOST_CHECK(addrman1.size() == 0);
    try {
        unsigned char pchMsgTmp[4];
        ssPeers1 >> pchMsgTmp;
        ssPeers1 >> addrman1;
    } catch (const std::exception&) {
        exceptionThrown = true;
    }
    // Even through de-serialization failed addrman is not left in a clean state.
    BOOST_CHECK(addrman1.size() == 1);
    BOOST_CHECK(exceptionThrown);

    // Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails.
    CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);

    CAddrMan addrman2;
    CAddrDB adb;
    BOOST_CHECK(addrman2.size() == 0);
    adb.Read(addrman2, ssPeers2);
    BOOST_CHECK(addrman2.size() == 0);
}

BOOST_AUTO_TEST_CASE(cnode_simple_test)
{
    SOCKET hSocket = INVALID_SOCKET;
    NodeId id = 0;
    int height = 0;

    in_addr ipv4Addr;
    ipv4Addr.s_addr = 0xa0b0c001;

    CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
    std::string pszDest;
    bool fInboundIn = false;

    // Test that fFeeler is false by default.
    std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, fInboundIn);
    BOOST_CHECK(pnode1->fInbound == false);
    BOOST_CHECK(pnode1->fFeeler == false);

    fInboundIn = true;
    std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, fInboundIn);
    BOOST_CHECK(pnode2->fInbound == true);
    BOOST_CHECK(pnode2->fFeeler == false);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>add test demonstrating addrLocal UB<commit_after>// Copyright (c) 2012-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <addrman.h>
#include <test/test_bitcoin.h>
#include <string>
#include <boost/test/unit_test.hpp>
#include <hash.h>
#include <serialize.h>
#include <streams.h>
#include <net.h>
#include <netbase.h>
#include <chainparams.h>
#include <util/system.h>

#include <memory>

class CAddrManSerializationMock : public CAddrMan
{
public:
    virtual void Serialize(CDataStream& s) const = 0;

    //! Ensure that bucket placement is always the same for testing purposes.
    void MakeDeterministic()
    {
        nKey.SetNull();
        insecure_rand = FastRandomContext(true);
    }
};

class CAddrManUncorrupted : public CAddrManSerializationMock
{
public:
    void Serialize(CDataStream& s) const override
    {
        CAddrMan::Serialize(s);
    }
};

class CAddrManCorrupted : public CAddrManSerializationMock
{
public:
    void Serialize(CDataStream& s) const override
    {
        // Produces corrupt output that claims addrman has 20 addrs when it only has one addr.
        unsigned char nVersion = 1;
        s << nVersion;
        s << ((unsigned char)32);
        s << nKey;
        s << 10; // nNew
        s << 10; // nTried

        int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
        s << nUBuckets;

        CService serv;
        Lookup("252.1.1.1", serv, 7777, false);
        CAddress addr = CAddress(serv, NODE_NONE);
        CNetAddr resolved;
        LookupHost("252.2.2.2", resolved, false);
        CAddrInfo info = CAddrInfo(addr, resolved);
        s << info;
    }
};

static CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman)
{
    CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
    ssPeersIn << Params().MessageStart();
    ssPeersIn << _addrman;
    std::string str = ssPeersIn.str();
    std::vector<unsigned char> vchData(str.begin(), str.end());
    return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
}

BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(cnode_listen_port)
{
    // test default
    unsigned short port = GetListenPort();
    BOOST_CHECK(port == Params().GetDefaultPort());
    // test set port
    unsigned short altPort = 12345;
    gArgs.SoftSetArg("-port", std::to_string(altPort));
    port = GetListenPort();
    BOOST_CHECK(port == altPort);
}

BOOST_AUTO_TEST_CASE(caddrdb_read)
{
    SetDataDir("caddrdb_read");
    CAddrManUncorrupted addrmanUncorrupted;
    addrmanUncorrupted.MakeDeterministic();

    CService addr1, addr2, addr3;
    Lookup("250.7.1.1", addr1, 8333, false);
    Lookup("250.7.2.2", addr2, 9999, false);
    Lookup("250.7.3.3", addr3, 9999, false);

    // Add three addresses to new table.
    CService source;
    Lookup("252.5.1.1", source, 8333, false);
    addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), source);
    addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), source);
    addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), source);

    // Test that the de-serialization does not throw an exception.
    CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
    bool exceptionThrown = false;
    CAddrMan addrman1;

    BOOST_CHECK(addrman1.size() == 0);
    try {
        unsigned char pchMsgTmp[4];
        ssPeers1 >> pchMsgTmp;
        ssPeers1 >> addrman1;
    } catch (const std::exception&) {
        exceptionThrown = true;
    }

    BOOST_CHECK(addrman1.size() == 3);
    BOOST_CHECK(exceptionThrown == false);

    // Test that CAddrDB::Read creates an addrman with the correct number of addrs.
    CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);

    CAddrMan addrman2;
    CAddrDB adb;
    BOOST_CHECK(addrman2.size() == 0);
    adb.Read(addrman2, ssPeers2);
    BOOST_CHECK(addrman2.size() == 3);
}

BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
{
    SetDataDir("caddrdb_read_corrupted");
    CAddrManCorrupted addrmanCorrupted;
    addrmanCorrupted.MakeDeterministic();

    // Test that the de-serialization of corrupted addrman throws an exception.
    CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
    bool exceptionThrown = false;
    CAddrMan addrman1;
    BOOST_CHECK(addrman1.size() == 0);
    try {
        unsigned char pchMsgTmp[4];
        ssPeers1 >> pchMsgTmp;
        ssPeers1 >> addrman1;
    } catch (const std::exception&) {
        exceptionThrown = true;
    }
    // Even through de-serialization failed addrman is not left in a clean state.
    BOOST_CHECK(addrman1.size() == 1);
    BOOST_CHECK(exceptionThrown);

    // Test that CAddrDB::Read leaves addrman in a clean state if de-serialization fails.
    CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);

    CAddrMan addrman2;
    CAddrDB adb;
    BOOST_CHECK(addrman2.size() == 0);
    adb.Read(addrman2, ssPeers2);
    BOOST_CHECK(addrman2.size() == 0);
}

BOOST_AUTO_TEST_CASE(cnode_simple_test)
{
    SOCKET hSocket = INVALID_SOCKET;
    NodeId id = 0;
    int height = 0;

    in_addr ipv4Addr;
    ipv4Addr.s_addr = 0xa0b0c001;

    CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
    std::string pszDest;
    bool fInboundIn = false;

    // Test that fFeeler is false by default.
    std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, fInboundIn);
    BOOST_CHECK(pnode1->fInbound == false);
    BOOST_CHECK(pnode1->fFeeler == false);

    fInboundIn = true;
    std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, fInboundIn);
    BOOST_CHECK(pnode2->fInbound == true);
    BOOST_CHECK(pnode2->fFeeler == false);
}

// prior to PR #14728, this test triggers an undefined behavior
BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
{
    // set up local addresses; all that's necessary to reproduce the bug is
    // that a normal IPv4 address is among the entries, but if this address is
    // !IsRoutable the undefined behavior is easier to trigger deterministically
    {
        LOCK(cs_mapLocalHost);
        in_addr ipv4AddrLocal;
        ipv4AddrLocal.s_addr = 0x0100007f;
        CNetAddr addr = CNetAddr(ipv4AddrLocal);
        LocalServiceInfo lsi;
        lsi.nScore = 23;
        lsi.nPort = 42;
        mapLocalHost[addr] = lsi;
    }

    // create a peer with an IPv4 address
    in_addr ipv4AddrPeer;
    ipv4AddrPeer.s_addr = 0xa0b0c001;
    CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
    std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, false);
    pnode->fSuccessfullyConnected.store(true);

    // the peer claims to be reaching us via IPv6
    in6_addr ipv6AddrLocal;
    memset(ipv6AddrLocal.s6_addr, 0, 16);
    ipv6AddrLocal.s6_addr[0] = 0xcc;
    CAddress addrLocal = CAddress(CService(ipv6AddrLocal, 7777), NODE_NETWORK);
    pnode->SetAddrLocal(addrLocal);

    // before patch, this causes undefined behavior detectable with clang's -fsanitize=memory
    AdvertiseLocal(&*pnode);

    // suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer
    BOOST_CHECK(1);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexConf.cxx
 ** Lexer for Apache Configuration Files.
 **
 ** First working version contributed by Ahmad Zawawi <zeus_go64@hotmail.com> on October 28, 2000.
 ** i created this lexer because i needed something pretty when dealing
 ** when Apache Configuration files...
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static void ColouriseConfDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler)
{
	int state = SCE_CONF_DEFAULT;
	char chNext = styler[startPos];
	int lengthDoc = startPos + length;
	// create a buffer large enough to take the largest chunk...
	char *buffer = new char[length];
	int bufferCount = 0;

	// this assumes that we have 2 keyword list in conf.properties
	WordList &directives = *keywordLists[0];
	WordList &params = *keywordLists[1];

	// go through all provided text segment
	// using the hand-written state machine shown below
	styler.StartAt(startPos);
	styler.StartSegment(startPos);
	for (int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			i++;
			continue;
		}
		switch(state) {
			case SCE_CONF_DEFAULT:
				if( ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') {
					// whitespace is simply ignored here...
					styler.ColourTo(i,SCE_CONF_DEFAULT);
					break;
				} else if( ch == '#' ) {
					// signals the start of a comment...
					state = SCE_CONF_COMMENT;
					styler.ColourTo(i,SCE_CONF_COMMENT);
				} else if( ch == '.' /*|| ch == '/'*/) {
					// signals the start of a file...
					state = SCE_CONF_EXTENSION;
					styler.ColourTo(i,SCE_CONF_EXTENSION);
				} else if( ch == '"') {
					state = SCE_CONF_STRING;
					styler.ColourTo(i,SCE_CONF_STRING);
				} else if( ispunct(ch) ) {
					// signals an operator...
					// no state jump necessary for this
					// simple case...
					styler.ColourTo(i,SCE_CONF_OPERATOR);
				} else if( isalpha(ch) ) {
					// signals the start of an identifier
					bufferCount = 0;
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
					state = SCE_CONF_IDENTIFIER;
				} else if( isdigit(ch) ) {
					// signals the start of a number
					bufferCount = 0;
					buffer[bufferCount++] = ch;
					//styler.ColourTo(i,SCE_CONF_NUMBER);
					state = SCE_CONF_NUMBER;
				} else {
					// style it the default style..
					styler.ColourTo(i,SCE_CONF_DEFAULT);
				}
				break;

			case SCE_CONF_COMMENT:
				// if we find a newline here,
				// we simply go to default state
				// else continue to work on it...
				if( ch == '\n' || ch == '\r' ) {
					state = SCE_CONF_DEFAULT;
				} else {
					styler.ColourTo(i,SCE_CONF_COMMENT);
				}
				break;

			case SCE_CONF_EXTENSION:
				// if we find a non-alphanumeric char,
				// we simply go to default state
				// else we're still dealing with an extension...
				if( isalnum(ch) || (ch == '_') ||
					(ch == '-') || (ch == '$') ||
					(ch == '/') || (ch == '.') || (ch == '*') )
				{
					styler.ColourTo(i,SCE_CONF_EXTENSION);
				} else {
					state = SCE_CONF_DEFAULT;
					chNext = styler[i--];
				}
				break;

			case SCE_CONF_STRING:
				// if we find the end of a string char, we simply go to default state
				// else we're still dealing with an string...
				if( (ch == '"' && styler.SafeGetCharAt(i-1)!='\\') || (ch == '\n') || (ch == '\r') ) {
					state = SCE_CONF_DEFAULT;
				}
				styler.ColourTo(i,SCE_CONF_STRING);
				break;

			case SCE_CONF_IDENTIFIER:
				// stay  in CONF_IDENTIFIER state until we find a non-alphanumeric
				if( isalnum(ch) || (ch == '_') || (ch == '-') || (ch == '/') || (ch == '$') || (ch == '.') || (ch == '*')) {
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
				} else {
					state = SCE_CONF_DEFAULT;
					buffer[bufferCount] = '\0';

					// check if the buffer contains a keyword, and highlight it if it is a keyword...
					if(directives.InList(buffer)) {
						styler.ColourTo(i-1,SCE_CONF_DIRECTIVE );
					} else if(params.InList(buffer)) {
						styler.ColourTo(i-1,SCE_CONF_PARAMETER );
					} else if(strchr(buffer,'/') || strchr(buffer,'.')) {
						styler.ColourTo(i-1,SCE_CONF_EXTENSION);
					} else {
						styler.ColourTo(i-1,SCE_CONF_DEFAULT);
					}

					// push back the faulty character
					chNext = styler[i--];

				}
				break;

			case SCE_CONF_NUMBER:
				// stay  in CONF_NUMBER state until we find a non-numeric
				if( isdigit(ch) || ch == '.') {
					buffer[bufferCount++] = ch;
				} else {
					state = SCE_CONF_DEFAULT;
					buffer[bufferCount] = '\0';

					// Colourize here...
					if( strchr(buffer,'.') ) {
						// it is an IP address...
						styler.ColourTo(i-1,SCE_CONF_IP);
					} else {
						// normal number
						styler.ColourTo(i-1,SCE_CONF_NUMBER);
					}

					// push back a character
					chNext = styler[i--];
				}
				break;

		}
	}
}

LexerModule lmConf(SCLEX_CONF, ColouriseConfDoc, "conf");
<commit_msg>Fixed memory leak.<commit_after>// Scintilla source code edit control
/** @file LexConf.cxx
 ** Lexer for Apache Configuration Files.
 **
 ** First working version contributed by Ahmad Zawawi <zeus_go64@hotmail.com> on October 28, 2000.
 ** i created this lexer because i needed something pretty when dealing
 ** when Apache Configuration files...
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static void ColouriseConfDoc(unsigned int startPos, int length, int, WordList *keywordLists[], Accessor &styler)
{
	int state = SCE_CONF_DEFAULT;
	char chNext = styler[startPos];
	int lengthDoc = startPos + length;
	// create a buffer large enough to take the largest chunk...
	char *buffer = new char[length];
	int bufferCount = 0;

	// this assumes that we have 2 keyword list in conf.properties
	WordList &directives = *keywordLists[0];
	WordList &params = *keywordLists[1];

	// go through all provided text segment
	// using the hand-written state machine shown below
	styler.StartAt(startPos);
	styler.StartSegment(startPos);
	for (int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			i++;
			continue;
		}
		switch(state) {
			case SCE_CONF_DEFAULT:
				if( ch == '\n' || ch == '\r' || ch == '\t' || ch == ' ') {
					// whitespace is simply ignored here...
					styler.ColourTo(i,SCE_CONF_DEFAULT);
					break;
				} else if( ch == '#' ) {
					// signals the start of a comment...
					state = SCE_CONF_COMMENT;
					styler.ColourTo(i,SCE_CONF_COMMENT);
				} else if( ch == '.' /*|| ch == '/'*/) {
					// signals the start of a file...
					state = SCE_CONF_EXTENSION;
					styler.ColourTo(i,SCE_CONF_EXTENSION);
				} else if( ch == '"') {
					state = SCE_CONF_STRING;
					styler.ColourTo(i,SCE_CONF_STRING);
				} else if( ispunct(ch) ) {
					// signals an operator...
					// no state jump necessary for this
					// simple case...
					styler.ColourTo(i,SCE_CONF_OPERATOR);
				} else if( isalpha(ch) ) {
					// signals the start of an identifier
					bufferCount = 0;
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
					state = SCE_CONF_IDENTIFIER;
				} else if( isdigit(ch) ) {
					// signals the start of a number
					bufferCount = 0;
					buffer[bufferCount++] = ch;
					//styler.ColourTo(i,SCE_CONF_NUMBER);
					state = SCE_CONF_NUMBER;
				} else {
					// style it the default style..
					styler.ColourTo(i,SCE_CONF_DEFAULT);
				}
				break;

			case SCE_CONF_COMMENT:
				// if we find a newline here,
				// we simply go to default state
				// else continue to work on it...
				if( ch == '\n' || ch == '\r' ) {
					state = SCE_CONF_DEFAULT;
				} else {
					styler.ColourTo(i,SCE_CONF_COMMENT);
				}
				break;

			case SCE_CONF_EXTENSION:
				// if we find a non-alphanumeric char,
				// we simply go to default state
				// else we're still dealing with an extension...
				if( isalnum(ch) || (ch == '_') ||
					(ch == '-') || (ch == '$') ||
					(ch == '/') || (ch == '.') || (ch == '*') )
				{
					styler.ColourTo(i,SCE_CONF_EXTENSION);
				} else {
					state = SCE_CONF_DEFAULT;
					chNext = styler[i--];
				}
				break;

			case SCE_CONF_STRING:
				// if we find the end of a string char, we simply go to default state
				// else we're still dealing with an string...
				if( (ch == '"' && styler.SafeGetCharAt(i-1)!='\\') || (ch == '\n') || (ch == '\r') ) {
					state = SCE_CONF_DEFAULT;
				}
				styler.ColourTo(i,SCE_CONF_STRING);
				break;

			case SCE_CONF_IDENTIFIER:
				// stay  in CONF_IDENTIFIER state until we find a non-alphanumeric
				if( isalnum(ch) || (ch == '_') || (ch == '-') || (ch == '/') || (ch == '$') || (ch == '.') || (ch == '*')) {
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
				} else {
					state = SCE_CONF_DEFAULT;
					buffer[bufferCount] = '\0';

					// check if the buffer contains a keyword, and highlight it if it is a keyword...
					if(directives.InList(buffer)) {
						styler.ColourTo(i-1,SCE_CONF_DIRECTIVE );
					} else if(params.InList(buffer)) {
						styler.ColourTo(i-1,SCE_CONF_PARAMETER );
					} else if(strchr(buffer,'/') || strchr(buffer,'.')) {
						styler.ColourTo(i-1,SCE_CONF_EXTENSION);
					} else {
						styler.ColourTo(i-1,SCE_CONF_DEFAULT);
					}

					// push back the faulty character
					chNext = styler[i--];

				}
				break;

			case SCE_CONF_NUMBER:
				// stay  in CONF_NUMBER state until we find a non-numeric
				if( isdigit(ch) || ch == '.') {
					buffer[bufferCount++] = ch;
				} else {
					state = SCE_CONF_DEFAULT;
					buffer[bufferCount] = '\0';

					// Colourize here...
					if( strchr(buffer,'.') ) {
						// it is an IP address...
						styler.ColourTo(i-1,SCE_CONF_IP);
					} else {
						// normal number
						styler.ColourTo(i-1,SCE_CONF_NUMBER);
					}

					// push back a character
					chNext = styler[i--];
				}
				break;

		}
	}
	delete []buffer;
}

LexerModule lmConf(SCLEX_CONF, ColouriseConfDoc, "conf");
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
// SneezyMUD - All rights reserved, SneezyMUD Coding Team
//
//
//////////////////////////////////////////////////////////////////////////

#include "stdsneezy.h"
#include "cmd_trophy.h"
#include "database.h"

TTrophy::TTrophy(string n) :
  db(new TDatabase("sneezy")),
  parent(NULL),
  name(n)
{
}

TTrophy::TTrophy(TBeing *p) :
  db(new TDatabase("sneezy")),
  parent(p),
  name("")
{
}

string TTrophy::getMyName(){
  if(parent){
    return parent->getName();
  } else {
    // name should be "" if we're uninitialized, so just return it either way
    return name;
  }
}

void TTrophy::setName(string n){
  parent=NULL;
  name=n;
}

void TTrophy::addToCount(int vnum, double add){
  if(vnum==-1 || vnum==0 || getMyName()==""){ return; }

  db->query("select * from trophy where name='%s' and mobvnum=%i",
	    getMyName().c_str(), vnum);
  if(!db->fetchRow()){
    db->query("insert into trophy values ('%s', %i, %f)",
	      getMyName().c_str(), vnum, add);
  } else {
    db->query("update trophy set count=count+%f where name='%s' and mobvnum=%i",
	      add, getMyName().c_str(), vnum);
  }
}

float TTrophy::getCount(int vnum)
{
  db->query("select count from trophy where name='%s' and mobvnum=%i",
	   getMyName().c_str(), vnum);
  if(db->fetchRow())
    return convertTo<float>(db->getColumn(0));
  else
    return 0.0;
}

float TTrophy::getExpModVal(float count)
{
  float min_mod=0.3;
  float max_mod=1.0; // shouldn't ever be above 1.0
  float free_kills=8; // how many kills you get before trophy kicks in
  float step_mod=0.5; // mod per step
  float num_steps=14.0; // number of steps

  float t1, t2, t3, t4, t5;

  t1=(double)(count-free_kills);
  t2=step_mod / num_steps;
  t3=t1*t2;
  t4=max_mod-t3;
  t5=(double)(max(t4*100, min_mod*100)/100);
  t5=(double)(min(t5*100, max_mod*100)/100);

  //  vlogf(LOG_PEEL, "%f %f %f %f %f", t1, t2, t3, t4, t5);

  return t5;
}

const char *TTrophy::getExpModDescr(float count)
{
  float f=getExpModVal(count);

  return((f == 1.0) ? "<Y>full<1>" :
	 ((f >= 0.90) ? "<o>much<1>" :
	  ((f >= 0.80) ? "a fair amount of" :
	   ((f >= 0.70) ? "<w>some<1>" : "<k>little<1>"))));
}

// this function is a little messy, I apologize
void TBeing::doTrophy(const string arg)
{
  int mcount=0, vnum, header=0, zcount=0, bottom=0, zcountt=0;
  int zonesearch=0, processrow=1;
  bool summary=false;
  float count;
  string buf, sb, arg1, arg2;
  unsigned int zone;

  if(!isPc()){
    sendTo("Mobs can't use this command!\n\r");
    return;
  }

  TTrophy trophy(getName());

  argument_parser(arg, arg1, arg2);

  if(arg1=="zone"){
    if(!arg2.empty()){
      arg1=arg2;
      zonesearch=-1;
    } else {
      zonesearch=roomp->getZoneNum();
    }
  } else if(arg1=="summary"){
    summary=true;
  }

  TDatabase db("sneezy");
  db.query("select mobvnum, count from trophy where name='%s' order by mobvnum", getName());

  for (zone = 0; zone < zone_table.size(); zone++) {
    zoneData &zd = zone_table[zone];

    while(1){
      if(processrow){
	if(!db.fetchRow()){
	  break;
	}
      }

      // sometimes we get an entry of 0 for med mobs I think
      vnum=convertTo<int>(db.getColumn(0));
      if(vnum==0){
	continue;
      }

      // this mob doesn't belong to this zone, so break out to the zone loop
      if(vnum>zd.top){
	processrow=0; // don't get the next row yet
	break;
      } else {
	processrow=1;
      }

      int rnum = real_mobile(convertTo<int>(db.getColumn(0)));
      if (rnum < 0) {
	vlogf(LOG_BUG, "DoTrophy detected bad mobvnum=%d for name='%s'",
	      convertTo<int>(db.getColumn(0)), getName());
	continue;
      }

      if(zonesearch==-1){
	if(!isname(arg1, zd.name))
	  continue;
      } else if(zonesearch>0){
	if(zonesearch!=zd.zone_nr)
	  continue;
      } else if(!summary){
	if(!isname(arg1, mob_index[rnum].name))
	  continue;
      }

      // print the zone header if we haven't already
      // we do it here, so we can prevent printing headers for empty zones
      if(!header){
	ssprintf(buf, "\n--%s\n", zd.name);
	sb += buf;
	header=1;
      }

      count=convertTo<float>(db.getColumn(1));

      if(!summary){
	ssprintf(buf, "You will gain %s experience when fighting %s.\n\r",
		trophy.getExpModDescr(count),
		mob_index[rnum].short_desc);
	sb += buf;
      }

      ++mcount;
      ++zcount;

      processrow=1; // ok to get the next row
    }

    // we have some mobs for this zone, so do some tallies
    if(header){
      ssprintf(buf, "Total mobs: %i\n\r", zcount);
      sb += buf;

      unsigned int objnx;
      for (objnx = 0; objnx < mob_index.size(); objnx++) {
	if(mob_index[objnx].virt >= bottom &&
	   mob_index[objnx].virt <= zd.top){
	  ++zcountt;
	}
      }

      ssprintf(buf, "You have killed %1.2f%% of mobs in this zone.\n\r",((float)((float)zcount/(float)zcountt)*100.0));
      sb += buf;
    }

    header=zcount=zcountt=0;
    bottom=zd.top+1;
  }

  int activemobcount=0;
  for (unsigned int mobnum = 0; mobnum < mob_index.size(); mobnum++) {
    for (unsigned int zone = 0; zone < zone_table.size(); zone++) {
      if(mob_index[mobnum].virt <= zone_table[zone].top){
	if(zone_table[zone].enabled)
	  activemobcount++;
	break;
      }
    }
  }

  ssprintf(buf, "\n--\nTotal mobs: %i\n\r", mcount);
  sb += buf;
  if(mcount>0){
    ssprintf(buf, "You have killed %1.2f%% of all mobs.\n\r",((float)((float)mcount/(float)activemobcount)*100.0));
    sb += buf;
  }

  if (desc)
    desc->page_string(sb, SHOWNOW_NO, ALLOWREP_YES);

  return;
}

void TTrophy::wipe(){
  db->query("delete from trophy where upper(name)=upper('%s')", getMyName().c_str());
}
<commit_msg>fixed a bug with trophy wasn't checking that arg existed when doing mob search<commit_after>//////////////////////////////////////////////////////////////////////////
//
// SneezyMUD - All rights reserved, SneezyMUD Coding Team
//
//
//////////////////////////////////////////////////////////////////////////

#include "stdsneezy.h"
#include "cmd_trophy.h"
#include "database.h"

TTrophy::TTrophy(string n) :
  db(new TDatabase("sneezy")),
  parent(NULL),
  name(n)
{
}

TTrophy::TTrophy(TBeing *p) :
  db(new TDatabase("sneezy")),
  parent(p),
  name("")
{
}

string TTrophy::getMyName(){
  if(parent){
    return parent->getName();
  } else {
    // name should be "" if we're uninitialized, so just return it either way
    return name;
  }
}

void TTrophy::setName(string n){
  parent=NULL;
  name=n;
}

void TTrophy::addToCount(int vnum, double add){
  if(vnum==-1 || vnum==0 || getMyName()==""){ return; }

  db->query("select * from trophy where name='%s' and mobvnum=%i",
	    getMyName().c_str(), vnum);
  if(!db->fetchRow()){
    db->query("insert into trophy values ('%s', %i, %f)",
	      getMyName().c_str(), vnum, add);
  } else {
    db->query("update trophy set count=count+%f where name='%s' and mobvnum=%i",
	      add, getMyName().c_str(), vnum);
  }
}

float TTrophy::getCount(int vnum)
{
  db->query("select count from trophy where name='%s' and mobvnum=%i",
	   getMyName().c_str(), vnum);
  if(db->fetchRow())
    return convertTo<float>(db->getColumn(0));
  else
    return 0.0;
}

float TTrophy::getExpModVal(float count)
{
  float min_mod=0.3;
  float max_mod=1.0; // shouldn't ever be above 1.0
  float free_kills=8; // how many kills you get before trophy kicks in
  float step_mod=0.5; // mod per step
  float num_steps=14.0; // number of steps

  float t1, t2, t3, t4, t5;

  t1=(double)(count-free_kills);
  t2=step_mod / num_steps;
  t3=t1*t2;
  t4=max_mod-t3;
  t5=(double)(max(t4*100, min_mod*100)/100);
  t5=(double)(min(t5*100, max_mod*100)/100);

  //  vlogf(LOG_PEEL, "%f %f %f %f %f", t1, t2, t3, t4, t5);

  return t5;
}

const char *TTrophy::getExpModDescr(float count)
{
  float f=getExpModVal(count);

  return((f == 1.0) ? "<Y>full<1>" :
	 ((f >= 0.90) ? "<o>much<1>" :
	  ((f >= 0.80) ? "a fair amount of" :
	   ((f >= 0.70) ? "<w>some<1>" : "<k>little<1>"))));
}

// this function is a little messy, I apologize
void TBeing::doTrophy(const string arg)
{
  int mcount=0, vnum, header=0, zcount=0, bottom=0, zcountt=0;
  int zonesearch=0, processrow=1;
  bool summary=false;
  float count;
  string buf, sb, arg1, arg2;
  unsigned int zone;

  if(!isPc()){
    sendTo("Mobs can't use this command!\n\r");
    return;
  }

  TTrophy trophy(getName());

  argument_parser(arg, arg1, arg2);

  if(arg1=="zone"){
    if(!arg2.empty()){
      arg1=arg2;
      zonesearch=-1;
    } else {
      zonesearch=roomp->getZoneNum();
    }
  } else if(arg1=="summary"){
    summary=true;
  }

  TDatabase db("sneezy");
  db.query("select mobvnum, count from trophy where name='%s' order by mobvnum", getName());

  for (zone = 0; zone < zone_table.size(); zone++) {
    zoneData &zd = zone_table[zone];

    while(1){
      if(processrow){
	if(!db.fetchRow()){
	  break;
	}
      }

      // sometimes we get an entry of 0 for med mobs I think
      vnum=convertTo<int>(db.getColumn(0));
      if(vnum==0){
	continue;
      }

      // this mob doesn't belong to this zone, so break out to the zone loop
      if(vnum>zd.top){
	processrow=0; // don't get the next row yet
	break;
      } else {
	processrow=1;
      }

      int rnum = real_mobile(convertTo<int>(db.getColumn(0)));
      if (rnum < 0) {
	vlogf(LOG_BUG, "DoTrophy detected bad mobvnum=%d for name='%s'",
	      convertTo<int>(db.getColumn(0)), getName());
	continue;
      }

      if(zonesearch==-1){
	if(!isname(arg1, zd.name))
	  continue;
      } else if(zonesearch>0){
	if(zonesearch!=zd.zone_nr)
	  continue;
      } else if(!summary){
	if(!arg1.empty() && !isname(arg1, mob_index[rnum].name))
	  continue;
      }

      // print the zone header if we haven't already
      // we do it here, so we can prevent printing headers for empty zones
      if(!header){
	ssprintf(buf, "\n--%s\n", zd.name);
	sb += buf;
	header=1;
      }

      count=convertTo<float>(db.getColumn(1));

      if(!summary){
	ssprintf(buf, "You will gain %s experience when fighting %s.\n\r",
		trophy.getExpModDescr(count),
		mob_index[rnum].short_desc);
	sb += buf;
      }

      ++mcount;
      ++zcount;

      processrow=1; // ok to get the next row
    }

    // we have some mobs for this zone, so do some tallies
    if(header){
      ssprintf(buf, "Total mobs: %i\n\r", zcount);
      sb += buf;

      unsigned int objnx;
      for (objnx = 0; objnx < mob_index.size(); objnx++) {
	if(mob_index[objnx].virt >= bottom &&
	   mob_index[objnx].virt <= zd.top){
	  ++zcountt;
	}
      }

      ssprintf(buf, "You have killed %1.2f%% of mobs in this zone.\n\r",((float)((float)zcount/(float)zcountt)*100.0));
      sb += buf;
    }

    header=zcount=zcountt=0;
    bottom=zd.top+1;
  }

  int activemobcount=0;
  for (unsigned int mobnum = 0; mobnum < mob_index.size(); mobnum++) {
    for (unsigned int zone = 0; zone < zone_table.size(); zone++) {
      if(mob_index[mobnum].virt <= zone_table[zone].top){
	if(zone_table[zone].enabled)
	  activemobcount++;
	break;
      }
    }
  }

  ssprintf(buf, "\n--\nTotal mobs: %i\n\r", mcount);
  sb += buf;
  if(mcount>0){
    ssprintf(buf, "You have killed %1.2f%% of all mobs.\n\r",((float)((float)mcount/(float)activemobcount)*100.0));
    sb += buf;
  }

  if (desc)
    desc->page_string(sb, SHOWNOW_NO, ALLOWREP_YES);

  return;
}

void TTrophy::wipe(){
  db->query("delete from trophy where upper(name)=upper('%s')", getMyName().c_str());
}
<|endoftext|>


<commit_before>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#include "ork/ork.hpp"
#include "ork/string_utils.hpp"

#define CATCH_CONFIG_MAIN 1
#include "ork/test/catch_include.hpp"

ORK_GLOBAL_LOG(ORK("../Logs"))

using namespace ork;

TEST_CASE("Strings are encoded", "[string]")
{
    const bstring test_1{BORK("Encode this 1!")};
    const bstring result_1{BORK("RW5jb2RlIHRoaXMgMSE=")};
    REQUIRE(
        encode(
            reinterpret_cast<const unsigned char*>(test_1.data()),
            test_1.size(),
            encoding::base_64) == result_1);
    REQUIRE(decode(result_1, encoding::base_64) == test_1);
}

// We to avoid a second project to generate code
TEST_CASE("Macro Generation", "[pp_meta]")
{
    static const size_t macro_max = 64;
    ORK_FILE_WRITE_B(ORK("generated.cpp"));

    LOOPI(macro_max)
    {
        fout << BORK("#define ORK_ARG_")
             << i << BORK("_(");
        LOOPJ(i + 1)
        {
            fout << BORK('A') << j << BORK(", ");
        }
        fout << BORK("...) A") << i << BORK('\n');
    }

    fout << BORK("\n");
    fout << BORK("#define ORK_ARG_N_(");
    LOOPI(macro_max + 1)
    {
        fout << BORK('A') << i + 1 << BORK(", ");
    }
    fout << BORK("...) A") << macro_max + 1 << BORK('\n');

    fout << BORK("\n");
    fout << BORK("#define ORK_DESCENDING_N_ ");
    LOOPRI(macro_max + 1)
    {
        fout << i << (i > 0 ? BORK(", ") : BORK(""));
    }

    fout << BORK("\n\n");
    LOOPI(macro_max)
    {
        fout << BORK("#define ORK_INC_") << i << BORK(" ") << i + 1 << BORK('\n');
    }

    fout << BORK("\n");
    LOOPI(macro_max)
    {
        fout << BORK("#define ORK_DEC_") << i + 1 << BORK(" ") << i << BORK('\n');
    }
}

TEST_CASE("MAP Macro Test", "[pp_meta]")
{
    REQUIRE(ORK_IF_(1)(4, 5) == 4);
    REQUIRE(ORK_IF_(0)(4, 5) == 5);
#define T() 1
#define F() 0
    REQUIRE(ORK_IF_(T())(4, 5) == 4);
    REQUIRE(ORK_IF_(F())(4, 5) == 5);

    REQUIRE(ORK_CHECK_1_() == 0);
    REQUIRE(ORK_CHECK_1_(1) == 0);
    REQUIRE(ORK_CHECK_1_(1, 2) == 2);
    REQUIRE(ORK_CHECK_1_(1, 2, 3) == 2);
#define A1() 1
#define A2() 1, 2
#define A3() 1, 2, 3
    REQUIRE(ORK_CHECK_1_(A1()) == 0);
    REQUIRE(ORK_CHECK_1_(A2()) == 2);
    REQUIRE(ORK_CHECK_1_(A3()) == 2);

    REQUIRE(ORK_CHECK_1_(ORK_APPEND_1_(1)) == 1);
    REQUIRE(ORK_CHECK_1_(ORK_APPEND_1_(1, 2)) == 2);
    REQUIRE(ORK_CHECK_1_(ORK_APPEND_1_(A1())) == 1);
    REQUIRE(ORK_CHECK_1_(ORK_APPEND_1_(A2())) == 2);

    REQUIRE(ORK_IS_PAREN(()) == 1);
    REQUIRE(ORK_IS_PAREN(~) == 0);
#define P() ()
#define NP() ~
    REQUIRE(ORK_IS_PAREN(P()) == 1);
    REQUIRE(ORK_IS_PAREN(NP()) == 0);

    REQUIRE(ORK_NOT(0) == 1);
    REQUIRE(ORK_NOT(1) == 0);
    REQUIRE(ORK_NOT(F()) == 1);
    REQUIRE(ORK_NOT(T()) == 0);

    REQUIRE(ORK_BOOL(0) == 0);
    REQUIRE(ORK_BOOL(1) == 1);
    REQUIRE(ORK_BOOL(a) == 1);
    static const char a = 'a';
    static const char b = 'b';
#define A() a
#define B() b
    REQUIRE(ORK_BOOL(F()) == 0);
    REQUIRE(ORK_BOOL(T()) == 1);
    REQUIRE(ORK_BOOL(A()) == 1);

    REQUIRE(ORK_IF(0)(a, b) == b);
    REQUIRE(ORK_IF(1)(a, b) == a);
    REQUIRE(ORK_IF(a)(a, b) == a);
    REQUIRE(ORK_IF(B())(a, b) == a);

    REQUIRE(1 ORK_WHEN(0)(+1) == 1);
    REQUIRE(1 ORK_WHEN(1)(+1) == 2);

    // clang-format off
#define ORK_SQUARE(DATA, I, A) A*A
#define ORK_ADD(DATA, I, A, B) A + B
    // clang-format on

    const ork::bstring square_list{ORK_STR(ORK_MAP(ORK_SQUARE, ORK_ADD, data, 1, 2))};
    REQUIRE(square_list == BORK("1*1 + 2*2"));
    int val = ORK_MAP(ORK_SQUARE, ORK_ADD, data, 1, 2);
    REQUIRE(val == 5);

    // clang-format off
#define CALL(DATA, I, ARG) DATA--ARG--I
#define STITCH(DATA, I, X, Y) (X *DATA-I* Y)
    // clang-format on
    const ork::bstring assoc_list{ORK_STR(ORK_MAP(CALL, STITCH, my, a, b, c))};
    REQUIRE(assoc_list == BORK("(my--a--0 *my-0* (my--b--1 *my-1* my--c--2))"));
}

TEST_CASE("Macro Test", "[pp_meta]") {
	const int arg_1 = ORK_NUM_ARG(a);
	REQUIRE(arg_1 == 1);

	const int arg_3 = ORK_NUM_ARG(a, b, c);
	REQUIRE(arg_3 == 3);
}
<commit_msg>Corrected arg generation<commit_after>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#include "ork/ork.hpp"
#include "ork/string_utils.hpp"

#define CATCH_CONFIG_MAIN 1
#include "ork/test/catch_include.hpp"

ORK_GLOBAL_LOG(ORK("../Logs"))

using namespace ork;

TEST_CASE("Strings are encoded", "[string]")
{
    const bstring test_1{BORK("Encode this 1!")};
    const bstring result_1{BORK("RW5jb2RlIHRoaXMgMSE=")};
    REQUIRE(
        encode(
            reinterpret_cast<const unsigned char*>(test_1.data()),
            test_1.size(),
            encoding::base_64) == result_1);
    REQUIRE(decode(result_1, encoding::base_64) == test_1);
}

// We to avoid a second project to generate code
TEST_CASE("Macro Generation", "[pp_meta]")
{
    static const size_t macro_max = 64;
    ORK_FILE_WRITE_B(ORK("generated.cpp"));

    LOOPI(macro_max)
    {
        fout << BORK("#define ORK_ARG_") << i << BORK("(");
        LOOPJ(i + 1)
        {
            fout << BORK('A') << j << BORK(", ");
        }
        fout << BORK("...) A") << i << BORK('\n');
    }

    fout << BORK("\n");
    fout << BORK("#define ORK_ARG_N_(");
    LOOPI(macro_max + 1)
    {
        fout << BORK('A') << i + 1 << BORK(", ");
    }
    fout << BORK("...) A") << macro_max + 1 << BORK('\n');

    fout << BORK("\n");
    fout << BORK("#define ORK_DESCENDING_N_ ");
    LOOPRI(macro_max + 1)
    {
        fout << i << (i > 0 ? BORK(", ") : BORK(""));
    }

    fout << BORK("\n\n");
    LOOPI(macro_max)
    {
        fout << BORK("#define ORK_INC_") << i << BORK(" ") << i + 1 << BORK('\n');
    }

    fout << BORK("\n");
    LOOPI(macro_max)
    {
        fout << BORK("#define ORK_DEC_") << i + 1 << BORK(" ") << i << BORK('\n');
    }
}

TEST_CASE("MAP Macro Test", "[pp_meta]")
{
    REQUIRE(ORK_IF_(1)(4, 5) == 4);
    REQUIRE(ORK_IF_(0)(4, 5) == 5);
#define T() 1
#define F() 0
    REQUIRE(ORK_IF_(T())(4, 5) == 4);
    REQUIRE(ORK_IF_(F())(4, 5) == 5);

    REQUIRE(ORK_CHECK_1_() == 0);
    REQUIRE(ORK_CHECK_1_(1) == 0);
    REQUIRE(ORK_CHECK_1_(1, 2) == 2);
    REQUIRE(ORK_CHECK_1_(1, 2, 3) == 2);
#define A1() 1
#define A2() 1, 2
#define A3() 1, 2, 3
    REQUIRE(ORK_CHECK_1_(A1()) == 0);
    REQUIRE(ORK_CHECK_1_(A2()) == 2);
    REQUIRE(ORK_CHECK_1_(A3()) == 2);

    REQUIRE(ORK_CHECK_1_(ORK_APPEND_1_(1)) == 1);
    REQUIRE(ORK_CHECK_1_(ORK_APPEND_1_(1, 2)) == 2);
    REQUIRE(ORK_CHECK_1_(ORK_APPEND_1_(A1())) == 1);
    REQUIRE(ORK_CHECK_1_(ORK_APPEND_1_(A2())) == 2);

    REQUIRE(ORK_IS_PAREN(()) == 1);
    REQUIRE(ORK_IS_PAREN(~) == 0);
#define P() ()
#define NP() ~
    REQUIRE(ORK_IS_PAREN(P()) == 1);
    REQUIRE(ORK_IS_PAREN(NP()) == 0);

    REQUIRE(ORK_NOT(0) == 1);
    REQUIRE(ORK_NOT(1) == 0);
    REQUIRE(ORK_NOT(F()) == 1);
    REQUIRE(ORK_NOT(T()) == 0);

    REQUIRE(ORK_BOOL(0) == 0);
    REQUIRE(ORK_BOOL(1) == 1);
    REQUIRE(ORK_BOOL(a) == 1);
    static const char a = 'a';
    static const char b = 'b';
#define A() a
#define B() b
    REQUIRE(ORK_BOOL(F()) == 0);
    REQUIRE(ORK_BOOL(T()) == 1);
    REQUIRE(ORK_BOOL(A()) == 1);

    REQUIRE(ORK_IF(0)(a, b) == b);
    REQUIRE(ORK_IF(1)(a, b) == a);
    REQUIRE(ORK_IF(a)(a, b) == a);
    REQUIRE(ORK_IF(B())(a, b) == a);

    REQUIRE(1 ORK_WHEN(0)(+1) == 1);
    REQUIRE(1 ORK_WHEN(1)(+1) == 2);

    // clang-format off
#define ORK_SQUARE(DATA, I, A) A*A
#define ORK_ADD(DATA, I, A, B) A + B
    // clang-format on

    const ork::bstring square_list{ORK_STR(ORK_MAP(ORK_SQUARE, ORK_ADD, data, 1, 2))};
    REQUIRE(square_list == BORK("1*1 + 2*2"));
    int val = ORK_MAP(ORK_SQUARE, ORK_ADD, data, 1, 2);
    REQUIRE(val == 5);

    // clang-format off
#define CALL(DATA, I, ARG) DATA--ARG--I
#define STITCH(DATA, I, X, Y) (X *DATA-I* Y)
    // clang-format on
    const ork::bstring assoc_list{ORK_STR(ORK_MAP(CALL, STITCH, my, a, b, c))};
    REQUIRE(assoc_list == BORK("(my--a--0 *my-0* (my--b--1 *my-1* my--c--2))"));
}

TEST_CASE("Macro Test", "[pp_meta]")
{
    const int arg_1 = ORK_NUM_ARG(a);
    REQUIRE(arg_1 == 1);

    const int arg_3 = ORK_NUM_ARG(a, b, c);
    REQUIRE(arg_3 == 3);
}
<|endoftext|>


<commit_before>/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    stubgeneratorfactory.cpp
 * @date    11/19/2014
 * @author  Peter Spiess-Knafl <peter.knafl@gmail.com>
 * @license See attached LICENSE.txt
 ************************************************************************/

#include "stubgeneratorfactory.h"
#include <jsonrpccpp/common/specificationparser.h>
#include <jsonrpccpp/version.h>
#include <iostream>
#include <argtable2.h>
#include "helper/cpphelper.h"
#include "client/cppclientstubgenerator.h"
#include "client/jsclientstubgenerator.h"
#include "client/python_client_stub_generator.h"
#include "server/cppserverstubgenerator.h"

using namespace jsonrpc;
using namespace std;

bool StubGeneratorFactory::createStubGenerators(int argc, char **argv, vector<Procedure> &procedures, vector<StubGenerator*> &stubgenerators, FILE *stdout, FILE *stderr)
{
    struct arg_file *inputfile      = arg_file0(NULL, NULL, "<specfile>", "path of input specification file");
    struct arg_lit *help            = arg_lit0("h","help", "print this help and exit");
    struct arg_lit *version         = arg_lit0(NULL,"version", "print version and exit");
    struct arg_lit *verbose         = arg_lit0("v","verbose", "print more information about what is happening");
    struct arg_str *cppserver       = arg_str0(NULL, "cpp-server", "<namespace::classname>", "name of the C++ server stub class");
    struct arg_str *cppserverfile   = arg_str0(NULL, "cpp-server-file", "<filename.h>", "name of the C++ server stub file");
    struct arg_str *cppclient       = arg_str0(NULL, "cpp-client", "<namespace::classname>", "name of the C++ client stub class");
    struct arg_str *cppclientfile   = arg_str0(NULL, "cpp-client-file", "<filename.h>", "name of the C++ client stub file");
    struct arg_str *jsclient        = arg_str0(NULL, "js-client", "<classname>", "name of the JavaScript client stub class");
    struct arg_str *jsclientfile    = arg_str0(NULL, "js-client-file", "<filename.js>", "name of the JavaScript client stub file");
    struct arg_str *pyclient        = arg_str0(NULL, "python-client", "<classname>", "name of the Python client stub class");
    struct arg_str *pyclientfile    = arg_str0(NULL, "python-client-file", "<filename.python>", "name of the Python client stub file");

    struct arg_end *end         = arg_end(20);
    void* argtable[] = {inputfile, help, version, verbose, cppserver, cppserverfile, cppclient, cppclientfile, jsclient, jsclientfile, pyclient, pyclientfile, end};

    if (arg_parse(argc,argv,argtable) > 0)
    {
        arg_print_errors(stderr, end, argv[0]);
        arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
        return false;
    }

    if (help->count > 0)
    {
        fprintf(stdout, "Usage: %s ", argv[0]);
        arg_print_syntax(stdout,argtable,"\n"); cout << endl;
        arg_print_glossary_gnu(stdout, argtable);
        arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
        return true;
    }

    if (version->count > 0)
    {
        fprintf(stdout, "jsonrpcstub version %d.%d.%d\n", JSONRPC_CPP_MAJOR_VERSION, JSONRPC_CPP_MINOR_VERSION, JSONRPC_CPP_PATCH_VERSION);
        arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
        return true;
    }

    if (inputfile->count == 0) {
        fprintf(stderr, "Invalid arguments: specfile must be provided.\n");
        arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
        return false;
    }

    try {
        procedures = SpecificationParser::GetProceduresFromFile(inputfile->filename[0]);
        if (verbose->count > 0)
        {
            fprintf(stdout, "Found %zu procedures in %s\n", procedures.size(), inputfile->filename[0]);
            for (unsigned int i = 0; i < procedures.size(); ++i) {
                if (procedures.at(i).GetProcedureType() == RPC_METHOD)
                {
                    fprintf(stdout, "\t[Method]         ");
                }
                else
                {
                    fprintf(stdout, "\t[Notification]   ");
                }
                fprintf(stdout, "%s\n", procedures.at(i).GetProcedureName().c_str());
            }
            fprintf(stdout, "\n");
        }

        if (cppserver->count > 0)
        {
            string filename;
            if (cppserverfile->count > 0)
                filename = cppserverfile->sval[0];
            else
                filename = CPPHelper::class2Filename(cppserver->sval[0]);
            if (verbose->count > 0)
                fprintf(stdout, "Generating C++ Serverstub to: %s\n", filename.c_str());
            stubgenerators.push_back(new CPPServerStubGenerator(cppserver->sval[0], procedures, filename));
        }

        if (cppclient->count > 0)
        {
            string filename;
            if (cppclientfile->count > 0)
                filename = cppclientfile->sval[0];
            else
                filename = CPPHelper::class2Filename(cppclient->sval[0]);
            if (verbose->count > 0)
                fprintf(stdout, "Generating C++ Clientstub to: %s\n", filename.c_str());
            stubgenerators.push_back(new CPPClientStubGenerator(cppclient->sval[0], procedures, filename));
        }

        if (jsclient->count > 0)
        {
            string filename;
            if (jsclientfile->count > 0)
                filename = jsclientfile->sval[0];
            else
                filename = JSClientStubGenerator::class2Filename(jsclient->sval[0]);

            if (verbose->count > 0)
                fprintf(stdout, "Generating JavaScript Clientstub to: %s\n", filename.c_str());
            stubgenerators.push_back(new JSClientStubGenerator(jsclient->sval[0], procedures, filename));
        }

        if (pyclient->count > 0)
        {
            string filename;
            if (pyclientfile->count > 0)
                filename = pyclientfile->sval[0];
            else
                filename = PythonClientStubGenerator::class2Filename(pyclient->sval[0]);

            if (verbose->count > 0)
                fprintf(stdout, "Generating Python Clientstub to: %s\n", filename.c_str());
            stubgenerators.push_back(new PythonClientStubGenerator(pyclient->sval[0], procedures, filename));
        }
    }
    catch (const JsonRpcException &ex)
    {
        fprintf(stderr, "%s\n", ex.what());
        arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
        return false;
    }
    arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
    return true;
}

void StubGeneratorFactory::deleteStubGenerators(std::vector<StubGenerator *> &stubgenerators)
{
    for (unsigned int i=0; i < stubgenerators.size(); ++i)
    {
        delete stubgenerators[i];
    }
}
<commit_msg>fixed pyclient include name<commit_after>/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    stubgeneratorfactory.cpp
 * @date    11/19/2014
 * @author  Peter Spiess-Knafl <peter.knafl@gmail.com>
 * @license See attached LICENSE.txt
 ************************************************************************/

#include "stubgeneratorfactory.h"
#include <jsonrpccpp/common/specificationparser.h>
#include <jsonrpccpp/version.h>
#include <iostream>
#include <argtable2.h>
#include "helper/cpphelper.h"
#include "client/cppclientstubgenerator.h"
#include "client/jsclientstubgenerator.h"
#include "client/pyclientstubgenerator.h"
#include "server/cppserverstubgenerator.h"

using namespace jsonrpc;
using namespace std;

bool StubGeneratorFactory::createStubGenerators(int argc, char **argv, vector<Procedure> &procedures, vector<StubGenerator*> &stubgenerators, FILE *stdout, FILE *stderr)
{
    struct arg_file *inputfile      = arg_file0(NULL, NULL, "<specfile>", "path of input specification file");
    struct arg_lit *help            = arg_lit0("h","help", "print this help and exit");
    struct arg_lit *version         = arg_lit0(NULL,"version", "print version and exit");
    struct arg_lit *verbose         = arg_lit0("v","verbose", "print more information about what is happening");
    struct arg_str *cppserver       = arg_str0(NULL, "cpp-server", "<namespace::classname>", "name of the C++ server stub class");
    struct arg_str *cppserverfile   = arg_str0(NULL, "cpp-server-file", "<filename.h>", "name of the C++ server stub file");
    struct arg_str *cppclient       = arg_str0(NULL, "cpp-client", "<namespace::classname>", "name of the C++ client stub class");
    struct arg_str *cppclientfile   = arg_str0(NULL, "cpp-client-file", "<filename.h>", "name of the C++ client stub file");
    struct arg_str *jsclient        = arg_str0(NULL, "js-client", "<classname>", "name of the JavaScript client stub class");
    struct arg_str *jsclientfile    = arg_str0(NULL, "js-client-file", "<filename.js>", "name of the JavaScript client stub file");
    struct arg_str *pyclient        = arg_str0(NULL, "python-client", "<classname>", "name of the Python client stub class");
    struct arg_str *pyclientfile    = arg_str0(NULL, "python-client-file", "<filename.py>", "name of the Python client stub file");

    struct arg_end *end         = arg_end(20);
    void* argtable[] = {inputfile, help, version, verbose, cppserver, cppserverfile, cppclient, cppclientfile, jsclient, jsclientfile, pyclient, pyclientfile, end};

    if (arg_parse(argc,argv,argtable) > 0)
    {
        arg_print_errors(stderr, end, argv[0]);
        arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
        return false;
    }

    if (help->count > 0)
    {
        fprintf(stdout, "Usage: %s ", argv[0]);
        arg_print_syntax(stdout,argtable,"\n"); cout << endl;
        arg_print_glossary_gnu(stdout, argtable);
        arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
        return true;
    }

    if (version->count > 0)
    {
        fprintf(stdout, "jsonrpcstub version %d.%d.%d\n", JSONRPC_CPP_MAJOR_VERSION, JSONRPC_CPP_MINOR_VERSION, JSONRPC_CPP_PATCH_VERSION);
        arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
        return true;
    }

    if (inputfile->count == 0) {
        fprintf(stderr, "Invalid arguments: specfile must be provided.\n");
        arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
        return false;
    }

    try {
        procedures = SpecificationParser::GetProceduresFromFile(inputfile->filename[0]);
        if (verbose->count > 0)
        {
            fprintf(stdout, "Found %zu procedures in %s\n", procedures.size(), inputfile->filename[0]);
            for (unsigned int i = 0; i < procedures.size(); ++i) {
                if (procedures.at(i).GetProcedureType() == RPC_METHOD)
                {
                    fprintf(stdout, "\t[Method]         ");
                }
                else
                {
                    fprintf(stdout, "\t[Notification]   ");
                }
                fprintf(stdout, "%s\n", procedures.at(i).GetProcedureName().c_str());
            }
            fprintf(stdout, "\n");
        }

        if (cppserver->count > 0)
        {
            string filename;
            if (cppserverfile->count > 0)
                filename = cppserverfile->sval[0];
            else
                filename = CPPHelper::class2Filename(cppserver->sval[0]);
            if (verbose->count > 0)
                fprintf(stdout, "Generating C++ Serverstub to: %s\n", filename.c_str());
            stubgenerators.push_back(new CPPServerStubGenerator(cppserver->sval[0], procedures, filename));
        }

        if (cppclient->count > 0)
        {
            string filename;
            if (cppclientfile->count > 0)
                filename = cppclientfile->sval[0];
            else
                filename = CPPHelper::class2Filename(cppclient->sval[0]);
            if (verbose->count > 0)
                fprintf(stdout, "Generating C++ Clientstub to: %s\n", filename.c_str());
            stubgenerators.push_back(new CPPClientStubGenerator(cppclient->sval[0], procedures, filename));
        }

        if (jsclient->count > 0)
        {
            string filename;
            if (jsclientfile->count > 0)
                filename = jsclientfile->sval[0];
            else
                filename = JSClientStubGenerator::class2Filename(jsclient->sval[0]);

            if (verbose->count > 0)
                fprintf(stdout, "Generating JavaScript Clientstub to: %s\n", filename.c_str());
            stubgenerators.push_back(new JSClientStubGenerator(jsclient->sval[0], procedures, filename));
        }

        if (pyclient->count > 0)
        {
            string filename;
            if (pyclientfile->count > 0)
                filename = pyclientfile->sval[0];
            else
                filename = PythonClientStubGenerator::class2Filename(pyclient->sval[0]);

            if (verbose->count > 0)
                fprintf(stdout, "Generating Python Clientstub to: %s\n", filename.c_str());
            stubgenerators.push_back(new PythonClientStubGenerator(pyclient->sval[0], procedures, filename));
        }
    }
    catch (const JsonRpcException &ex)
    {
        fprintf(stderr, "%s\n", ex.what());
        arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
        return false;
    }
    arg_freetable(argtable,sizeof(argtable)/sizeof(argtable[0]));
    return true;
}

void StubGeneratorFactory::deleteStubGenerators(std::vector<StubGenerator *> &stubgenerators)
{
    for (unsigned int i=0; i < stubgenerators.size(); ++i)
    {
        delete stubgenerators[i];
    }
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <string>
#include <vector>
#include "link.h"
#include "util/fde.h"
#include "util/log.h"
#include "version.h"

struct Data
{
	std::string key;
	std::string val;
	std::string num;
};

std::vector<Data *> *ds;
Fdevents *fdes;
std::vector<Link *> *free_links;
std::vector<Link *> *busy_links;

void welcome(){
	printf("ssdb-bench - SSDB benchmark tool, %s\n", SSDB_VERSION);
	printf("Copyright (c) 2013-2014 ssdb.io\n");
	printf("\n");
}

void usage(int argc, char **argv){
	printf("Usage:\n");
	printf("    %s [ip] [port] [requests] [clients]\n", argv[0]);
	printf("\n");
	printf("Options:\n");
	printf("    ip          server ip (default 127.0.0.1)\n");
	printf("    port        server port (default 8888)\n");
	printf("    requests    Total number of requests (default 10000)\n");
	printf("    clients     Number of parallel connections (default 50)\n");
	printf("\n");
}

void init_data(int num){
	srand(time(NULL));
	ds = new std::vector<Data *>();
	for(int i=0; i<num; i++){
		Data *d = new Data();
		char buf[1024];

		int n = rand();
		snprintf(buf, sizeof(buf), "%d", n);
		d->num = buf;
		snprintf(buf, sizeof(buf), "k%010d", n);
		d->key = buf;
		snprintf(buf, sizeof(buf), "v%0100d", n);
		d->val = buf;
		ds->push_back(d);
	}
}

void init_links(int num, const char *ip, int port){
	fdes = new Fdevents();
	free_links = new std::vector<Link *>();
	busy_links = new std::vector<Link *>();

	for(int i=0; i<num; i++){
		Link *link = Link::connect(ip, port);
		if(!link){
			printf("connect error! %s\n", strerror(errno));
			exit(0);
		}
		fdes->set(link->fd(), FDEVENT_IN, 0, link);
		free_links->push_back(link);
	}
}

void bench(std::string cmd){
	int total = ds->size();
	int finished = 0;
	int num_sent = 0;

	printf("========== %s ==========\n", cmd.c_str());

	double stime = millitime();
	while(1){
		while(!free_links->empty() && num_sent < ds->size()){
			Link *link = free_links->back();
			free_links->pop_back();

			Data *d = ds->at(num_sent);
			num_sent ++;

			if(cmd == "set"){
				link->send(cmd, d->key, d->val);
			}else if(cmd == "get"){
				link->send(cmd, d->key);
			}else if(cmd == "del"){
				link->send(cmd, d->key);
			}else if(cmd == "hset"){
				link->send(cmd, "h", d->key, d->val);
			}else if(cmd == "hget"){
				link->send(cmd, "h", d->key);
			}else if(cmd == "hdel"){
				link->send(cmd, "h", d->key);
			}else if(cmd == "zset"){
				link->send(cmd, "z", d->key, d->num);
			}else if(cmd == "zget"){
				link->send(cmd, "z", d->key);
			}else if(cmd == "zdel"){
				link->send(cmd, "z", d->key);
			}else if(cmd == "qpush"){
				link->send(cmd, "h", d->key, d->val);
			}else if(cmd == "qpop"){
				link->send(cmd, "h", d->key);
			}else{
				printf("bad command!\n");
				exit(0);
			}
			link->flush();
		}

		const Fdevents::events_t *events;
		events = fdes->wait(50);
		if(events == NULL){
			log_fatal("events.wait error: %s", strerror(errno));
			break;
		}

		for(int i=0; i<(int)events->size(); i++){
			const Fdevent *fde = events->at(i);
			Link *link = (Link *)fde->data.ptr;

			int len = link->read();
			if(len <= 0){
				log_fatal("fd: %d, read: %d, delete link", link->fd(), len);
				exit(0);
			}

			const std::vector<Bytes> *resp = link->recv();
			if(resp == NULL){
				printf("error\n");
				break;
			}else if(resp->empty()){
				if(link->read() <= 0){
					printf("read end\n");
					break;
				}
				continue;
			}else{
				if(resp->at(0) != "ok"){
					log_error("bad response: %s", resp->at(0).String().c_str());
					exit(0);
				}
				free_links->push_back(link);
				finished ++;
				if(finished == total){
					double etime = millitime();
					double ts = (stime == etime)? 1 : (etime - stime);
					double speed = total / ts;
					printf("qps: %d, time: %.3f s\n", (int)speed, ts);
					return;
				}
			}
		}
	}
}

int main(int argc, char **argv){
	const char *ip = "127.0.0.1";
	int port = 8888;
	int requests = 10000;
	int clients = 50;

	welcome();
	for(int i=1; i<argc; i++){
		if(strcmp("-v", argv[i]) == 0){
			usage(argc, argv);
			exit(0);
		}
	}
	if(argc > 1){
		ip = argv[1];
	}
	if(argc > 2){
		port = atoi(argv[2]);
	}
	if(argc > 3){
		requests = atoi(argv[3]);
	}
	if(argc > 4){
		clients = atoi(argv[4]);
	}

	//printf("preparing data...\n");
	init_data(requests);
	//printf("preparing links...\n");
	init_links(clients, ip, port);

	bench("set");
	bench("get");
	bench("del");

	bench("hset");
	bench("hget");
	bench("hdel");

	bench("zset");
	bench("zget");
	bench("zdel");

	bench("qpush");
	bench("qpop");

	printf("\n");

	return 0;
}

<commit_msg>update ssdb-bench<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <string>
#include <vector>
#include "link.h"
#include "util/fde.h"
#include "util/log.h"
#include "version.h"

struct Data
{
	std::string key;
	std::string val;
	std::string num;
};

std::vector<Data *> *ds;
Fdevents *fdes;
std::vector<Link *> *free_links;
std::vector<Link *> *busy_links;

void welcome(){
	printf("ssdb-bench - SSDB benchmark tool, %s\n", SSDB_VERSION);
	printf("Copyright (c) 2013-2014 ssdb.io\n");
	printf("\n");
}

void usage(int argc, char **argv){
	printf("Usage:\n");
	printf("    %s [ip] [port] [requests] [clients]\n", argv[0]);
	printf("\n");
	printf("Options:\n");
	printf("    ip          server ip (default 127.0.0.1)\n");
	printf("    port        server port (default 8888)\n");
	printf("    requests    Total number of requests (default 10000)\n");
	printf("    clients     Number of parallel connections (default 50)\n");
	printf("\n");
}

void init_data(int num){
	srand(time(NULL));
	ds = new std::vector<Data *>();
	for(int i=0; i<num; i++){
		Data *d = new Data();
		char buf[1024];

		int n = rand();
		snprintf(buf, sizeof(buf), "%d", n);
		d->num = buf;
		snprintf(buf, sizeof(buf), "k%010d", n);
		d->key = buf;
		snprintf(buf, sizeof(buf), "v%0100d", n);
		d->val = buf;
		ds->push_back(d);
	}
}

void init_links(int num, const char *ip, int port){
	fdes = new Fdevents();
	free_links = new std::vector<Link *>();
	busy_links = new std::vector<Link *>();

	for(int i=0; i<num; i++){
		Link *link = Link::connect(ip, port);
		if(!link){
			printf("connect error! %s\n", strerror(errno));
			exit(0);
		}
		fdes->set(link->fd(), FDEVENT_IN, 0, link);
		free_links->push_back(link);
	}
}

void bench(std::string cmd){
	int total = ds->size();
	int finished = 0;
	int num_sent = 0;

	printf("========== %s ==========\n", cmd.c_str());

	double stime = millitime();
	while(1){
		while(!free_links->empty() && num_sent < ds->size()){
			Link *link = free_links->back();
			free_links->pop_back();

			Data *d = ds->at(num_sent);
			num_sent ++;

			if(cmd == "set"){
				link->send(cmd, d->key, d->val);
			}else if(cmd == "get"){
				link->send(cmd, d->key);
			}else if(cmd == "del"){
				link->send(cmd, d->key);
			}else if(cmd == "hset"){
				link->send(cmd, "h", d->key, d->val);
			}else if(cmd == "hget"){
				link->send(cmd, "h", d->key);
			}else if(cmd == "hdel"){
				link->send(cmd, "h", d->key);
			}else if(cmd == "zset"){
				link->send(cmd, "z", d->key, d->num);
			}else if(cmd == "zget"){
				link->send(cmd, "z", d->key);
			}else if(cmd == "zdel"){
				link->send(cmd, "z", d->key);
			}else if(cmd == "qpush"){
				link->send(cmd, "h", d->key, d->val);
			}else if(cmd == "qpop"){
				link->send(cmd, "h", d->key);
			}else{
				printf("bad command!\n");
				exit(0);
			}
			link->flush();
		}

		const Fdevents::events_t *events;
		events = fdes->wait(50);
		if(events == NULL){
			log_fatal("events.wait error: %s", strerror(errno));
			break;
		}

		for(int i=0; i<(int)events->size(); i++){
			const Fdevent *fde = events->at(i);
			Link *link = (Link *)fde->data.ptr;

			int len = link->read();
			if(len <= 0){
				log_fatal("fd: %d, read: %d, delete link", link->fd(), len);
				exit(0);
			}

			const std::vector<Bytes> *resp = link->recv();
			if(resp == NULL){
				printf("error\n");
				break;
			}else if(resp->empty()){
				if(link->read() <= 0){
					printf("read end\n");
					break;
				}
				continue;
			}else{
				if(resp->at(0) != "ok"){
					log_error("bad response: %s", resp->at(0).String().c_str());
					exit(0);
				}
				free_links->push_back(link);
				finished ++;
				if(finished == total){
					double etime = millitime();
					double ts = (stime == etime)? 1 : (etime - stime);
					double speed = total / ts;
					printf("qps: %d, time: %.3f s\n", (int)speed, ts);
					return;
				}
			}
		}
	}
}

int main(int argc, char **argv){
	const char *ip = "127.0.0.1";
	int port = 8888;
	int requests = 10000;
	int clients = 50;

	welcome();
	usage(argc, argv);
	for(int i=1; i<argc; i++){
		if(strcmp("-v", argv[i]) == 0){
			exit(0);
		}
	}
	if(argc > 1){
		ip = argv[1];
	}
	if(argc > 2){
		port = atoi(argv[2]);
	}
	if(argc > 3){
		requests = atoi(argv[3]);
	}
	if(argc > 4){
		clients = atoi(argv[4]);
	}

	//printf("preparing data...\n");
	init_data(requests);
	//printf("preparing links...\n");
	init_links(clients, ip, port);

	bench("set");
	bench("get");
	bench("del");

	bench("hset");
	bench("hget");
	bench("hdel");

	bench("zset");
	bench("zget");
	bench("zdel");

	bench("qpush");
	bench("qpop");

	printf("\n");

	return 0;
}

<|endoftext|>


<commit_before>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/browser.h"

#include <string>

#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "base/message_loop/message_loop.h"

namespace atom {

Browser::Browser()
    : is_quiting_(false),
      is_ready_(false),
      is_shutdown_(false) {
  WindowList::AddObserver(this);
}

Browser::~Browser() {
  WindowList::RemoveObserver(this);
}

// static
Browser* Browser::Get() {
  return AtomBrowserMainParts::Get()->browser();
}

void Browser::Quit() {
  if (is_quiting_)
    return;

  is_quiting_ = HandleBeforeQuit();
  if (!is_quiting_)
    return;

  atom::WindowList* window_list = atom::WindowList::GetInstance();
  if (window_list->size() == 0)
    NotifyAndShutdown();

  window_list->CloseAllWindows();
}

void Browser::Exit(int code) {
  if (!AtomBrowserMainParts::Get()->SetExitCode(code)) {
    // Message loop is not ready, quit directly.
    exit(code);
  } else {
    // Prepare to quit when all windows have been closed..
    is_quiting_ = true;

    // Must destroy windows before quitting, otherwise bad things can happen.
    atom::WindowList* window_list = atom::WindowList::GetInstance();
    if (window_list->size() == 0) {
      NotifyAndShutdown();
    } else {
      // Unlike Quit(), we do not ask to close window, but destroy the window
      // without asking.
      for (NativeWindow* window : *window_list)
        window->CloseContents(nullptr);  // e.g. Destroy()
    }
  }
}

void Browser::Shutdown() {
  if (is_shutdown_)
    return;

  is_shutdown_ = true;
  is_quiting_ = true;

  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());

  if (base::MessageLoop::current()) {
    base::MessageLoop::current()->PostTask(
        FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
  } else {
    // There is no message loop available so we are in early stage.
    exit(0);
  }
}

std::string Browser::GetVersion() const {
  if (version_override_.empty()) {
    std::string version = GetExecutableFileVersion();
    if (!version.empty())
      return version;
  }

  return version_override_;
}

void Browser::SetVersion(const std::string& version) {
  version_override_ = version;
}

std::string Browser::GetName() const {
  if (name_override_.empty()) {
    std::string name = GetExecutableFileProductName();
    if (!name.empty())
      return name;
  }

  return name_override_;
}

void Browser::SetName(const std::string& name) {
  name_override_ = name;
}

bool Browser::OpenFile(const std::string& file_path) {
  bool prevent_default = false;
  FOR_EACH_OBSERVER(BrowserObserver,
                    observers_,
                    OnOpenFile(&prevent_default, file_path));

  return prevent_default;
}

void Browser::OpenURL(const std::string& url) {
  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnOpenURL(url));
}

void Browser::Activate(bool has_visible_windows) {
  FOR_EACH_OBSERVER(BrowserObserver,
                    observers_,
                    OnActivate(has_visible_windows));
}

void Browser::WillFinishLaunching() {
  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillFinishLaunching());
}

void Browser::DidFinishLaunching() {
  is_ready_ = true;
  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching());
}

void Browser::RequestLogin(LoginHandler* login_handler) {
  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnLogin(login_handler));
}

void Browser::NotifyAndShutdown() {
  if (is_shutdown_)
    return;

  bool prevent_default = false;
  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default));

  if (prevent_default) {
    is_quiting_ = false;
    return;
  }

  Shutdown();
}

bool Browser::HandleBeforeQuit() {
  bool prevent_default = false;
  FOR_EACH_OBSERVER(BrowserObserver,
                    observers_,
                    OnBeforeQuit(&prevent_default));

  return !prevent_default;
}

void Browser::OnWindowCloseCancelled(NativeWindow* window) {
  if (is_quiting_)
    // Once a beforeunload handler has prevented the closing, we think the quit
    // is cancelled too.
    is_quiting_ = false;
}

void Browser::OnWindowAllClosed() {
  if (is_quiting_)
    NotifyAndShutdown();
  else
    FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWindowAllClosed());
}

}  // namespace atom
<commit_msg>Don't emit `will-quit` event when calling app.exit<commit_after>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/browser.h"

#include <string>

#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "base/message_loop/message_loop.h"

namespace atom {

Browser::Browser()
    : is_quiting_(false),
      is_ready_(false),
      is_shutdown_(false) {
  WindowList::AddObserver(this);
}

Browser::~Browser() {
  WindowList::RemoveObserver(this);
}

// static
Browser* Browser::Get() {
  return AtomBrowserMainParts::Get()->browser();
}

void Browser::Quit() {
  if (is_quiting_)
    return;

  is_quiting_ = HandleBeforeQuit();
  if (!is_quiting_)
    return;

  atom::WindowList* window_list = atom::WindowList::GetInstance();
  if (window_list->size() == 0)
    NotifyAndShutdown();

  window_list->CloseAllWindows();
}

void Browser::Exit(int code) {
  if (!AtomBrowserMainParts::Get()->SetExitCode(code)) {
    // Message loop is not ready, quit directly.
    exit(code);
  } else {
    // Prepare to quit when all windows have been closed..
    is_quiting_ = true;

    // Must destroy windows before quitting, otherwise bad things can happen.
    atom::WindowList* window_list = atom::WindowList::GetInstance();
    if (window_list->size() == 0) {
      Shutdown();
    } else {
      // Unlike Quit(), we do not ask to close window, but destroy the window
      // without asking.
      for (NativeWindow* window : *window_list)
        window->CloseContents(nullptr);  // e.g. Destroy()
    }
  }
}

void Browser::Shutdown() {
  if (is_shutdown_)
    return;

  is_shutdown_ = true;
  is_quiting_ = true;

  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());

  if (base::MessageLoop::current()) {
    base::MessageLoop::current()->PostTask(
        FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
  } else {
    // There is no message loop available so we are in early stage.
    exit(0);
  }
}

std::string Browser::GetVersion() const {
  if (version_override_.empty()) {
    std::string version = GetExecutableFileVersion();
    if (!version.empty())
      return version;
  }

  return version_override_;
}

void Browser::SetVersion(const std::string& version) {
  version_override_ = version;
}

std::string Browser::GetName() const {
  if (name_override_.empty()) {
    std::string name = GetExecutableFileProductName();
    if (!name.empty())
      return name;
  }

  return name_override_;
}

void Browser::SetName(const std::string& name) {
  name_override_ = name;
}

bool Browser::OpenFile(const std::string& file_path) {
  bool prevent_default = false;
  FOR_EACH_OBSERVER(BrowserObserver,
                    observers_,
                    OnOpenFile(&prevent_default, file_path));

  return prevent_default;
}

void Browser::OpenURL(const std::string& url) {
  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnOpenURL(url));
}

void Browser::Activate(bool has_visible_windows) {
  FOR_EACH_OBSERVER(BrowserObserver,
                    observers_,
                    OnActivate(has_visible_windows));
}

void Browser::WillFinishLaunching() {
  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillFinishLaunching());
}

void Browser::DidFinishLaunching() {
  is_ready_ = true;
  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching());
}

void Browser::RequestLogin(LoginHandler* login_handler) {
  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnLogin(login_handler));
}

void Browser::NotifyAndShutdown() {
  if (is_shutdown_)
    return;

  bool prevent_default = false;
  FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default));

  if (prevent_default) {
    is_quiting_ = false;
    return;
  }

  Shutdown();
}

bool Browser::HandleBeforeQuit() {
  bool prevent_default = false;
  FOR_EACH_OBSERVER(BrowserObserver,
                    observers_,
                    OnBeforeQuit(&prevent_default));

  return !prevent_default;
}

void Browser::OnWindowCloseCancelled(NativeWindow* window) {
  if (is_quiting_)
    // Once a beforeunload handler has prevented the closing, we think the quit
    // is cancelled too.
    is_quiting_ = false;
}

void Browser::OnWindowAllClosed() {
  if (is_quiting_)
    NotifyAndShutdown();
  else
    FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWindowAllClosed());
}

}  // namespace atom
<|endoftext|>