<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cmtreemodel.cxx,v $
 *
 *  $Revision: 1.22 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 15:20:35 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_configmgr.hxx"

#include <stdio.h>

#include "valuenode.hxx"
#include "change.hxx"

#ifndef CONFIGMGR_CONFIGEXCEPT_HXX_
#include "configexcept.hxx"
#endif
#include "strdecl.hxx"

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef INCLUDED_ALGORITHM
#define INCLUDED_ALGORITHM
#include <algorithm>
#endif

//..........................................................................
namespace configmgr
{
//==========================================================================

bool isLocalizedValueSet(ISubtree const& _aSubtree)
{
    if ( !_aSubtree.isSetNode())    return false;
    if ( !_aSubtree.isLocalized())  return false;
    if ( !_aSubtree.getElementTemplateModule().equals(TEMPLATE_MODULE_LOCALIZED_VALUE) )    return false;
    return true;
}
// -----------------------------------------------------------------------------

bool isLocalizedValueSet(SubtreeChange const& _aSubtree)
{
    if ( !_aSubtree.isSetNodeChange())  return false;
    if ( !_aSubtree.isLocalizedContainer()) return false;
    if ( !_aSubtree.getElementTemplateModule().equals(TEMPLATE_MODULE_LOCALIZED_VALUE) )    return false;
    return true;
}

// -----------------------------------------------------------------------------

bool isValueSet(ISubtree const& _aSubtree)
{
    if ( !_aSubtree.isSetNode())    return false;
    if ( !_aSubtree.getElementTemplateModule().equals(TEMPLATE_MODULE_NATIVE_VALUE) )   return false;
    return true;
}
// -----------------------------------------------------------------------------

bool isValueSet(SubtreeChange const& _aSubtree)
{
    if ( !_aSubtree.isSetNodeChange())  return false;
    if ( !_aSubtree.getElementTemplateModule().equals(TEMPLATE_MODULE_NATIVE_VALUE) )   return false;
    return true;
}
//==========================================================================

//==========================================================================
//= Change
//==========================================================================
void Change::swap(Change& aOther)
{
    std::swap(m_aName, aOther.m_aName);
    std::swap(m_bIsToDefault, aOther.m_bIsToDefault);
}

//==========================================================================
//= SubtreeChange
//==========================================================================
//--------------------------------------------------------------------------
void SubtreeChange::swap(SubtreeChange& aOther)
{
    Change::swap(aOther);
    m_aChanges.swap(aOther.m_aChanges);
    std::swap(m_sTemplateName, aOther.m_sTemplateName);
    std::swap(m_sTemplateModule, aOther.m_sTemplateModule);
    std::swap(m_aAttributes, aOther.m_aAttributes);
}

//--------------------------------------------------------------------------
SubtreeChange::~SubtreeChange()
{
    for(Children::iterator aIter = m_aChanges.begin();
        aIter != m_aChanges.end();
        ++aIter)
    {
        // Change* pChange = aIter->second;
        delete aIter->second;
    }
}

// -----------------------------------------------------------------------------
SubtreeChange::SubtreeChange(const SubtreeChange& _aObj, DeepChildCopy)
        :Change(_aObj),
         m_sTemplateName(_aObj.m_sTemplateName),
         m_sTemplateModule(_aObj.m_sTemplateModule),
         m_aAttributes(_aObj.m_aAttributes)
{
    for(Children::const_iterator aIter = _aObj.m_aChanges.begin();
        aIter != _aObj.m_aChanges.end();
        ++aIter)
    {
        OSL_ASSERT(aIter->second);
        Children::value_type aCopy(aIter->first, aIter->second->clone().release());
        m_aChanges.insert(m_aChanges.end(), aCopy);
    }
}

// -----------------------------------------------------------------------------
std::auto_ptr<Change> SubtreeChange::clone() const
{
    return std::auto_ptr<Change>(new SubtreeChange(*this, DeepChildCopy()));
}
//--------------------------------------------------------------------------
void SubtreeChange::addChange(std::auto_ptr<Change> aChange)
{
    OUString aNodeName(aChange->getNodeName());
    m_aChanges.find(aNodeName);
    OSL_ENSURE(m_aChanges.end() == m_aChanges.find(aNodeName),
        "SubtreeChange::addChange : overwriting an existent change !");
    delete m_aChanges[aNodeName];
    m_aChanges[aNodeName] = aChange.release();
}

//--------------------------------------------------------------------------
::std::auto_ptr<Change> SubtreeChange::removeChange(OUString const& _rName)
{
    Children::iterator aIter = m_aChanges.find(_rName);

    ::std::auto_ptr<Change> aReturn;
    if (m_aChanges.end() != aIter)
    {
        aReturn = ::std::auto_ptr<Change>(aIter->second);
        m_aChanges.erase(aIter);
    }
    return aReturn;
}

//--------------------------------------------------------------------------
Change* SubtreeChange::getChange(OUString const& _rName)
{
    return doGetChild(_rName);
}

//--------------------------------------------------------------------------
Change const* SubtreeChange::getChange(OUString const& _rName) const
{
    return doGetChild(_rName);
}

//--------------------------------------------------------------------------
void SubtreeChange::dispatch(ChangeTreeAction& _anAction) const
{
    _anAction.handle(*this);
}

//--------------------------------------------------------------------------
void SubtreeChange::dispatch(ChangeTreeModification& _anAction)
{
    _anAction.handle(*this);
}

//--------------------------------------------------------------------------
void SubtreeChange::forEachChange(ChangeTreeAction& _anAction) const
{
    ::std::map< ::rtl::OUString,Change* >::const_iterator aIter = m_aChanges.begin();
    while (aIter != m_aChanges.end())
    {
        (aIter++)->second->dispatch(_anAction);
    }
}

//--------------------------------------------------------------------------
void SubtreeChange::forEachChange(ChangeTreeModification& _anAction)
{
    ::std::map< ::rtl::OUString,Change* >::const_iterator aIter = m_aChanges.begin();
    while (aIter != m_aChanges.end())
    {
        (aIter++)->second->dispatch(_anAction);
    }
}

//--------------------------------------------------------------------------
Change* SubtreeChange::doGetChild(OUString const& _rName) const
{
    Children::const_iterator aIter = m_aChanges.find(_rName);
    return (aIter != m_aChanges.end()) ? aIter->second : NULL;
}

//--------------------------------------------------------------------------
uno::Sequence< OUString > SubtreeChange::elementNames() const
{
    uno::Sequence< OUString > aReturn(size());
    OUString* pReturn = aReturn.getArray();

    for (   Children::const_iterator aCollector = m_aChanges.begin();
            aCollector != m_aChanges.end();
            ++aCollector, ++pReturn
        )
    {
        *pReturn = aCollector->first;
    }

    return aReturn;
}

//--------------------------------------------------------------------------
SubtreeChange::MutatingChildIterator SubtreeChange::begin_changes() throw()
{
    return MutatingChildIterator(m_aChanges.begin());
}

//--------------------------------------------------------------------------
SubtreeChange::MutatingChildIterator SubtreeChange::end_changes() throw()
{
    return MutatingChildIterator(m_aChanges.end());
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator SubtreeChange::begin() const throw()
{
    return ChildIterator(this);
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator SubtreeChange::end() const throw()
{
    return ChildIterator(this, ChildIterator::EndPos());
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator::ChildIterator(const SubtreeChange* _pTree)
    :m_aNames(_pTree->elementNames())
    ,m_pTree(_pTree)
    ,m_nPos(0)
{
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator::ChildIterator(const SubtreeChange* _pTree, struct EndPos)
    :m_aNames(_pTree->elementNames())
    ,m_pTree(_pTree)
    ,m_nPos(_pTree->size())
{
}

//--------------------------------------------------------------------------
Change const & SubtreeChange::ChildIterator::operator*() const
{
    OSL_ENSURE(isValid(), "SubtreeChange::ChildIterator::operator* : invalid iterator !");

    if (!isValid())
        throw configuration::Exception("INTERNAL ERROR: Invalid SubtreeChange::ChildIterator dereferenced");

    return *m_pTree->getChange(m_aNames[m_nPos]);
}

//--------------------------------------------------------------------------
Change const * SubtreeChange::ChildIterator::operator->() const
{
    if (isValid())
        return m_pTree->getChange(m_aNames[m_nPos]);
    OSL_ENSURE(sal_False, "SubtreeChange::ChildIterator::operator-> : invalid iterator !");
    return NULL;
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator& SubtreeChange::ChildIterator::operator++()
{
    OSL_ENSURE(m_nPos < m_aNames.getLength(), "SubtreeChange::ChildIterator : can't increment the end iterator !");
    if (m_nPos < m_aNames.getLength())
        ++m_nPos;
    return *this;
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator& SubtreeChange::ChildIterator::operator--()
{
    OSL_ENSURE(m_nPos > 0, "SubtreeChange::ChildIterator : can't decrement the begin iterator !");
    if (m_nPos > 0)
        --m_nPos;
    return *this;
}

//--------------------------------------------------------------------------
bool operator==(SubtreeChange::ChildIterator const& lhs, SubtreeChange::ChildIterator const& rhs)
{
    return (lhs.m_pTree == rhs.m_pTree) && (lhs.m_nPos == rhs.m_nPos);
}

//==========================================================================
//= SubtreeChangeReferrer
//==========================================================================
//--------------------------------------------------------------------------
SubtreeChangeReferrer::SubtreeChangeReferrer(const SubtreeChange& _rSource)
    :SubtreeChange(_rSource, SubtreeChange::NoChildCopy())
{
    ChildIterator aSourceChildren = _rSource.begin();
    while (aSourceChildren != _rSource.end())
    {
        const Change* pChange = &*aSourceChildren;
        OSL_ENSURE(pChange, "SubtreeChangeReferrer::SubtreeChangeReferrer : invalid change !");
        if  (   pChange->isA(ValueChange::getStaticType())
            ||  pChange->isA(RemoveNode::getStaticType())
            ||  pChange->isA(AddNode::getStaticType())
            )
            SubtreeChange::addChange(::std::auto_ptr<Change>(const_cast<Change*>(pChange)));
        else if (   pChange->isA(SubtreeChange::getStaticType())
                ||  pChange->isA(SubtreeChangeReferrer::getStaticType())
                )
        {
            SubtreeChange::addChange(::std::auto_ptr<Change>(new SubtreeChangeReferrer(*static_cast<const SubtreeChange*>(pChange))));
        }
        else
            OSL_ENSURE(sal_False, "SubtreeChangeReferrer::SubtreeChangeReferrer : unknown changes type !");

        ++aSourceChildren;
    }
}

//--------------------------------------------------------------------------
SubtreeChangeReferrer::~SubtreeChangeReferrer()
{
    for (   Children::iterator aChildren = m_aChanges.begin();
            aChildren != m_aChanges.end();

        )
    {
        const Change* pChange = aChildren->second;
        Children::iterator aCurrent = aChildren++;

        if  (   pChange->isA(ValueChange::getStaticType())
            ||  pChange->isA(RemoveNode::getStaticType())
            ||  pChange->isA(AddNode::getStaticType())
            )
        {
            // we just hold references to the non-SubtreeChange-objects, so don't delete them
            m_aChanges.erase(aCurrent);
        }
        else if (   pChange->isA(SubtreeChange::getStaticType())
                ||  pChange->isA(SubtreeChangeReferrer::getStaticType())
                )
        {
            // nothing to do
        }
        else
            OSL_ENSURE(sal_False, "SubtreeChangeReferrer::~SubtreeChangeReferrer : unknown changes type !");
    }

    // the base class will remove the remaining SubtreeChanges, which are SubtreeChangeReferrer's in real
}

//..........................................................................
}   // namespace configmgr
//..........................................................................

<commit_msg>INTEGRATION: CWS changefileheader (1.22.72); FILE MERGED 2008/04/01 15:06:53 thb 1.22.72.3: #i85898# Stripping all external header guards 2008/04/01 12:27:32 thb 1.22.72.2: #i85898# Stripping all external header guards 2008/03/31 12:22:52 rt 1.22.72.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: cmtreemodel.cxx,v $
 * $Revision: 1.23 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_configmgr.hxx"

#include <stdio.h>

#include "valuenode.hxx"
#include "change.hxx"
#include "configexcept.hxx"
#include "strdecl.hxx"
#include <osl/diagnose.h>

#ifndef INCLUDED_ALGORITHM
#define INCLUDED_ALGORITHM
#include <algorithm>
#endif

//..........................................................................
namespace configmgr
{
//==========================================================================

bool isLocalizedValueSet(ISubtree const& _aSubtree)
{
    if ( !_aSubtree.isSetNode())    return false;
    if ( !_aSubtree.isLocalized())  return false;
    if ( !_aSubtree.getElementTemplateModule().equals(TEMPLATE_MODULE_LOCALIZED_VALUE) )    return false;
    return true;
}
// -----------------------------------------------------------------------------

bool isLocalizedValueSet(SubtreeChange const& _aSubtree)
{
    if ( !_aSubtree.isSetNodeChange())  return false;
    if ( !_aSubtree.isLocalizedContainer()) return false;
    if ( !_aSubtree.getElementTemplateModule().equals(TEMPLATE_MODULE_LOCALIZED_VALUE) )    return false;
    return true;
}

// -----------------------------------------------------------------------------

bool isValueSet(ISubtree const& _aSubtree)
{
    if ( !_aSubtree.isSetNode())    return false;
    if ( !_aSubtree.getElementTemplateModule().equals(TEMPLATE_MODULE_NATIVE_VALUE) )   return false;
    return true;
}
// -----------------------------------------------------------------------------

bool isValueSet(SubtreeChange const& _aSubtree)
{
    if ( !_aSubtree.isSetNodeChange())  return false;
    if ( !_aSubtree.getElementTemplateModule().equals(TEMPLATE_MODULE_NATIVE_VALUE) )   return false;
    return true;
}
//==========================================================================

//==========================================================================
//= Change
//==========================================================================
void Change::swap(Change& aOther)
{
    std::swap(m_aName, aOther.m_aName);
    std::swap(m_bIsToDefault, aOther.m_bIsToDefault);
}

//==========================================================================
//= SubtreeChange
//==========================================================================
//--------------------------------------------------------------------------
void SubtreeChange::swap(SubtreeChange& aOther)
{
    Change::swap(aOther);
    m_aChanges.swap(aOther.m_aChanges);
    std::swap(m_sTemplateName, aOther.m_sTemplateName);
    std::swap(m_sTemplateModule, aOther.m_sTemplateModule);
    std::swap(m_aAttributes, aOther.m_aAttributes);
}

//--------------------------------------------------------------------------
SubtreeChange::~SubtreeChange()
{
    for(Children::iterator aIter = m_aChanges.begin();
        aIter != m_aChanges.end();
        ++aIter)
    {
        // Change* pChange = aIter->second;
        delete aIter->second;
    }
}

// -----------------------------------------------------------------------------
SubtreeChange::SubtreeChange(const SubtreeChange& _aObj, DeepChildCopy)
        :Change(_aObj),
         m_sTemplateName(_aObj.m_sTemplateName),
         m_sTemplateModule(_aObj.m_sTemplateModule),
         m_aAttributes(_aObj.m_aAttributes)
{
    for(Children::const_iterator aIter = _aObj.m_aChanges.begin();
        aIter != _aObj.m_aChanges.end();
        ++aIter)
    {
        OSL_ASSERT(aIter->second);
        Children::value_type aCopy(aIter->first, aIter->second->clone().release());
        m_aChanges.insert(m_aChanges.end(), aCopy);
    }
}

// -----------------------------------------------------------------------------
std::auto_ptr<Change> SubtreeChange::clone() const
{
    return std::auto_ptr<Change>(new SubtreeChange(*this, DeepChildCopy()));
}
//--------------------------------------------------------------------------
void SubtreeChange::addChange(std::auto_ptr<Change> aChange)
{
    OUString aNodeName(aChange->getNodeName());
    m_aChanges.find(aNodeName);
    OSL_ENSURE(m_aChanges.end() == m_aChanges.find(aNodeName),
        "SubtreeChange::addChange : overwriting an existent change !");
    delete m_aChanges[aNodeName];
    m_aChanges[aNodeName] = aChange.release();
}

//--------------------------------------------------------------------------
::std::auto_ptr<Change> SubtreeChange::removeChange(OUString const& _rName)
{
    Children::iterator aIter = m_aChanges.find(_rName);

    ::std::auto_ptr<Change> aReturn;
    if (m_aChanges.end() != aIter)
    {
        aReturn = ::std::auto_ptr<Change>(aIter->second);
        m_aChanges.erase(aIter);
    }
    return aReturn;
}

//--------------------------------------------------------------------------
Change* SubtreeChange::getChange(OUString const& _rName)
{
    return doGetChild(_rName);
}

//--------------------------------------------------------------------------
Change const* SubtreeChange::getChange(OUString const& _rName) const
{
    return doGetChild(_rName);
}

//--------------------------------------------------------------------------
void SubtreeChange::dispatch(ChangeTreeAction& _anAction) const
{
    _anAction.handle(*this);
}

//--------------------------------------------------------------------------
void SubtreeChange::dispatch(ChangeTreeModification& _anAction)
{
    _anAction.handle(*this);
}

//--------------------------------------------------------------------------
void SubtreeChange::forEachChange(ChangeTreeAction& _anAction) const
{
    ::std::map< ::rtl::OUString,Change* >::const_iterator aIter = m_aChanges.begin();
    while (aIter != m_aChanges.end())
    {
        (aIter++)->second->dispatch(_anAction);
    }
}

//--------------------------------------------------------------------------
void SubtreeChange::forEachChange(ChangeTreeModification& _anAction)
{
    ::std::map< ::rtl::OUString,Change* >::const_iterator aIter = m_aChanges.begin();
    while (aIter != m_aChanges.end())
    {
        (aIter++)->second->dispatch(_anAction);
    }
}

//--------------------------------------------------------------------------
Change* SubtreeChange::doGetChild(OUString const& _rName) const
{
    Children::const_iterator aIter = m_aChanges.find(_rName);
    return (aIter != m_aChanges.end()) ? aIter->second : NULL;
}

//--------------------------------------------------------------------------
uno::Sequence< OUString > SubtreeChange::elementNames() const
{
    uno::Sequence< OUString > aReturn(size());
    OUString* pReturn = aReturn.getArray();

    for (   Children::const_iterator aCollector = m_aChanges.begin();
            aCollector != m_aChanges.end();
            ++aCollector, ++pReturn
        )
    {
        *pReturn = aCollector->first;
    }

    return aReturn;
}

//--------------------------------------------------------------------------
SubtreeChange::MutatingChildIterator SubtreeChange::begin_changes() throw()
{
    return MutatingChildIterator(m_aChanges.begin());
}

//--------------------------------------------------------------------------
SubtreeChange::MutatingChildIterator SubtreeChange::end_changes() throw()
{
    return MutatingChildIterator(m_aChanges.end());
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator SubtreeChange::begin() const throw()
{
    return ChildIterator(this);
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator SubtreeChange::end() const throw()
{
    return ChildIterator(this, ChildIterator::EndPos());
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator::ChildIterator(const SubtreeChange* _pTree)
    :m_aNames(_pTree->elementNames())
    ,m_pTree(_pTree)
    ,m_nPos(0)
{
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator::ChildIterator(const SubtreeChange* _pTree, struct EndPos)
    :m_aNames(_pTree->elementNames())
    ,m_pTree(_pTree)
    ,m_nPos(_pTree->size())
{
}

//--------------------------------------------------------------------------
Change const & SubtreeChange::ChildIterator::operator*() const
{
    OSL_ENSURE(isValid(), "SubtreeChange::ChildIterator::operator* : invalid iterator !");

    if (!isValid())
        throw configuration::Exception("INTERNAL ERROR: Invalid SubtreeChange::ChildIterator dereferenced");

    return *m_pTree->getChange(m_aNames[m_nPos]);
}

//--------------------------------------------------------------------------
Change const * SubtreeChange::ChildIterator::operator->() const
{
    if (isValid())
        return m_pTree->getChange(m_aNames[m_nPos]);
    OSL_ENSURE(sal_False, "SubtreeChange::ChildIterator::operator-> : invalid iterator !");
    return NULL;
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator& SubtreeChange::ChildIterator::operator++()
{
    OSL_ENSURE(m_nPos < m_aNames.getLength(), "SubtreeChange::ChildIterator : can't increment the end iterator !");
    if (m_nPos < m_aNames.getLength())
        ++m_nPos;
    return *this;
}

//--------------------------------------------------------------------------
SubtreeChange::ChildIterator& SubtreeChange::ChildIterator::operator--()
{
    OSL_ENSURE(m_nPos > 0, "SubtreeChange::ChildIterator : can't decrement the begin iterator !");
    if (m_nPos > 0)
        --m_nPos;
    return *this;
}

//--------------------------------------------------------------------------
bool operator==(SubtreeChange::ChildIterator const& lhs, SubtreeChange::ChildIterator const& rhs)
{
    return (lhs.m_pTree == rhs.m_pTree) && (lhs.m_nPos == rhs.m_nPos);
}

//==========================================================================
//= SubtreeChangeReferrer
//==========================================================================
//--------------------------------------------------------------------------
SubtreeChangeReferrer::SubtreeChangeReferrer(const SubtreeChange& _rSource)
    :SubtreeChange(_rSource, SubtreeChange::NoChildCopy())
{
    ChildIterator aSourceChildren = _rSource.begin();
    while (aSourceChildren != _rSource.end())
    {
        const Change* pChange = &*aSourceChildren;
        OSL_ENSURE(pChange, "SubtreeChangeReferrer::SubtreeChangeReferrer : invalid change !");
        if  (   pChange->isA(ValueChange::getStaticType())
            ||  pChange->isA(RemoveNode::getStaticType())
            ||  pChange->isA(AddNode::getStaticType())
            )
            SubtreeChange::addChange(::std::auto_ptr<Change>(const_cast<Change*>(pChange)));
        else if (   pChange->isA(SubtreeChange::getStaticType())
                ||  pChange->isA(SubtreeChangeReferrer::getStaticType())
                )
        {
            SubtreeChange::addChange(::std::auto_ptr<Change>(new SubtreeChangeReferrer(*static_cast<const SubtreeChange*>(pChange))));
        }
        else
            OSL_ENSURE(sal_False, "SubtreeChangeReferrer::SubtreeChangeReferrer : unknown changes type !");

        ++aSourceChildren;
    }
}

//--------------------------------------------------------------------------
SubtreeChangeReferrer::~SubtreeChangeReferrer()
{
    for (   Children::iterator aChildren = m_aChanges.begin();
            aChildren != m_aChanges.end();

        )
    {
        const Change* pChange = aChildren->second;
        Children::iterator aCurrent = aChildren++;

        if  (   pChange->isA(ValueChange::getStaticType())
            ||  pChange->isA(RemoveNode::getStaticType())
            ||  pChange->isA(AddNode::getStaticType())
            )
        {
            // we just hold references to the non-SubtreeChange-objects, so don't delete them
            m_aChanges.erase(aCurrent);
        }
        else if (   pChange->isA(SubtreeChange::getStaticType())
                ||  pChange->isA(SubtreeChangeReferrer::getStaticType())
                )
        {
            // nothing to do
        }
        else
            OSL_ENSURE(sal_False, "SubtreeChangeReferrer::~SubtreeChangeReferrer : unknown changes type !");
    }

    // the base class will remove the remaining SubtreeChanges, which are SubtreeChangeReferrer's in real
}

//..........................................................................
}   // namespace configmgr
//..........................................................................

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: OTypeInfo.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: oj $ $Date: 2002-07-15 12:08:31 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_OTYPEINFO_HXX_
#define _CONNECTIVITY_OTYPEINFO_HXX_

#ifndef _COM_SUN_STAR_SDBC_COLUMNSEARCH_HPP_
#include <com/sun/star/sdbc/ColumnSearch.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_DATATYPE_HPP_
#include <com/sun/star/sdbc/DataType.hpp>
#endif

namespace connectivity
{
    struct OTypeInfo
    {
        ::rtl::OUString aTypeName;      // Name des Types in der Datenbank
        ::rtl::OUString aLiteralPrefix; // Prefix zum Quoten
        ::rtl::OUString aLiteralSuffix; // Suffix zum Quoten
        ::rtl::OUString aCreateParams;  // Parameter zum Erstellen
        ::rtl::OUString aLocalTypeName;

        sal_Int32       nPrecision;     // Laenge des Types

        sal_Int16       nMaximumScale;  // Nachkommastellen
        sal_Int16       nMinimumScale;  // Min Nachkommastellen

        sal_Int16       nType;          // Datenbanktyp
        sal_Int16       nSearchType;    // kann nach dem Typen gesucht werden
        sal_Int16       nNumPrecRadix;  // indicating the radix, which is usually 2 or 10

        sal_Bool        bCurrency       : 1,    // Waehrung
                        bAutoIncrement  : 1,    // Ist es ein automatisch incrementierendes Feld
                        bNullable       : 1,    // Kann das Feld NULL annehmen
                        bCaseSensitive  : 1,    // Ist der Type Casesensitive
                        bUnsigned       : 1,    // Ist der Type Unsigned
                        bEmpty_1        : 1,    // for later use
                        bEmpty_2        : 1;

        OTypeInfo()
                :bCurrency(sal_False)
                ,bAutoIncrement(sal_False)
                ,bNullable(sal_True)
                ,bCaseSensitive(sal_False)
                ,bUnsigned(sal_False)
                ,nMaximumScale(0)
                ,nMinimumScale(0)
                ,nType( ::com::sun::star::sdbc::DataType::OTHER)
                ,nPrecision(0)
                ,nSearchType( ::com::sun::star::sdbc::ColumnSearch::FULL)
        {}

        inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () )
            { return ::rtl_allocateMemory( nSize ); }
        inline static void * SAL_CALL operator new( size_t nSize,void* _pHint ) SAL_THROW( () )
            { return _pHint; }
        inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () )
            { ::rtl_freeMemory( pMem ); }
        inline static void SAL_CALL operator delete( void * pMem,void* _pHint ) SAL_THROW( () )
            {  }

        sal_Bool operator == (const OTypeInfo& lh) const { return lh.nType == nType; }
        sal_Bool operator != (const OTypeInfo& lh) const { return lh.nType != nType; }

        inline ::rtl::OUString getDBName() const { return aTypeName; }
    };
}
#endif // _CONNECTIVITY_OTYPEINFO_HXX_

<commit_msg>INTEGRATION: CWS ooo19126 (1.4.326); FILE MERGED 2005/09/05 17:24:48 rt 1.4.326.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: OTypeInfo.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 06:38:14 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CONNECTIVITY_OTYPEINFO_HXX_
#define _CONNECTIVITY_OTYPEINFO_HXX_

#ifndef _COM_SUN_STAR_SDBC_COLUMNSEARCH_HPP_
#include <com/sun/star/sdbc/ColumnSearch.hpp>
#endif
#ifndef _COM_SUN_STAR_SDBC_DATATYPE_HPP_
#include <com/sun/star/sdbc/DataType.hpp>
#endif

namespace connectivity
{
    struct OTypeInfo
    {
        ::rtl::OUString aTypeName;      // Name des Types in der Datenbank
        ::rtl::OUString aLiteralPrefix; // Prefix zum Quoten
        ::rtl::OUString aLiteralSuffix; // Suffix zum Quoten
        ::rtl::OUString aCreateParams;  // Parameter zum Erstellen
        ::rtl::OUString aLocalTypeName;

        sal_Int32       nPrecision;     // Laenge des Types

        sal_Int16       nMaximumScale;  // Nachkommastellen
        sal_Int16       nMinimumScale;  // Min Nachkommastellen

        sal_Int16       nType;          // Datenbanktyp
        sal_Int16       nSearchType;    // kann nach dem Typen gesucht werden
        sal_Int16       nNumPrecRadix;  // indicating the radix, which is usually 2 or 10

        sal_Bool        bCurrency       : 1,    // Waehrung
                        bAutoIncrement  : 1,    // Ist es ein automatisch incrementierendes Feld
                        bNullable       : 1,    // Kann das Feld NULL annehmen
                        bCaseSensitive  : 1,    // Ist der Type Casesensitive
                        bUnsigned       : 1,    // Ist der Type Unsigned
                        bEmpty_1        : 1,    // for later use
                        bEmpty_2        : 1;

        OTypeInfo()
                :bCurrency(sal_False)
                ,bAutoIncrement(sal_False)
                ,bNullable(sal_True)
                ,bCaseSensitive(sal_False)
                ,bUnsigned(sal_False)
                ,nMaximumScale(0)
                ,nMinimumScale(0)
                ,nType( ::com::sun::star::sdbc::DataType::OTHER)
                ,nPrecision(0)
                ,nSearchType( ::com::sun::star::sdbc::ColumnSearch::FULL)
        {}

        inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () )
            { return ::rtl_allocateMemory( nSize ); }
        inline static void * SAL_CALL operator new( size_t nSize,void* _pHint ) SAL_THROW( () )
            { return _pHint; }
        inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () )
            { ::rtl_freeMemory( pMem ); }
        inline static void SAL_CALL operator delete( void * pMem,void* _pHint ) SAL_THROW( () )
            {  }

        sal_Bool operator == (const OTypeInfo& lh) const { return lh.nType == nType; }
        sal_Bool operator != (const OTypeInfo& lh) const { return lh.nType != nType; }

        inline ::rtl::OUString getDBName() const { return aTypeName; }
    };
}
#endif // _CONNECTIVITY_OTYPEINFO_HXX_

<|endoftext|>


<commit_before>///
/// @file   cmdoptions.cpp
/// @brief  Parse command-line options for the primesieve console
///         (terminal) application.
///
/// Copyright (C) 2022 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include "cmdoptions.hpp"

#include <primesieve/calculator.hpp>
#include <primesieve/CpuInfo.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/primesieve_error.hpp>

#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <map>
#include <stdint.h>
#include <string>
#include <utility>

void help(int exitCode);
void test();
void version();

using std::size_t;
using namespace primesieve;

namespace {

enum OptionID
{
  OPTION_COUNT,
  OPTION_CPU_INFO,
  OPTION_HELP,
  OPTION_NTH_PRIME,
  OPTION_NO_STATUS,
  OPTION_NUMBER,
  OPTION_DISTANCE,
  OPTION_PRINT,
  OPTION_QUIET,
  OPTION_SIZE,
  OPTION_TEST,
  OPTION_THREADS,
  OPTION_TIME,
  OPTION_VERSION
};

/// Some command-line options require an additional parameter.
/// Examples: --threads THREADS, -a ALPHA, ...
enum IsParam
{
  NO_PARAM,
  REQUIRED_PARAM,
  OPTIONAL_PARAM
};

/// Command-line options
std::map<std::string, std::pair<OptionID, IsParam>> optionMap =
{
  { "-c",          std::make_pair(OPTION_COUNT, OPTIONAL_PARAM) },
  { "--count",     std::make_pair(OPTION_COUNT, OPTIONAL_PARAM) },
  { "--cpu-info",  std::make_pair(OPTION_CPU_INFO, NO_PARAM) },
  { "-h",          std::make_pair(OPTION_HELP, NO_PARAM) },
  { "--help",      std::make_pair(OPTION_HELP, NO_PARAM) },
  { "-n",          std::make_pair(OPTION_NTH_PRIME, NO_PARAM) },
  { "--nthprime",  std::make_pair(OPTION_NTH_PRIME, NO_PARAM) },
  { "--nth-prime", std::make_pair(OPTION_NTH_PRIME, NO_PARAM) },
  { "--no-status", std::make_pair(OPTION_NO_STATUS, NO_PARAM) },
  { "--number",    std::make_pair(OPTION_NUMBER, REQUIRED_PARAM) },
  { "-d",          std::make_pair(OPTION_DISTANCE, REQUIRED_PARAM) },
  { "--dist",      std::make_pair(OPTION_DISTANCE, REQUIRED_PARAM) },
  { "-p",          std::make_pair(OPTION_PRINT, OPTIONAL_PARAM) },
  { "--print",     std::make_pair(OPTION_PRINT, OPTIONAL_PARAM) },
  { "-q",          std::make_pair(OPTION_QUIET, NO_PARAM) },
  { "--quiet",     std::make_pair(OPTION_QUIET, NO_PARAM) },
  { "-s",          std::make_pair(OPTION_SIZE, REQUIRED_PARAM) },
  { "--size",      std::make_pair(OPTION_SIZE, REQUIRED_PARAM) },
  { "--test",      std::make_pair(OPTION_TEST, NO_PARAM) },
  { "-t",          std::make_pair(OPTION_THREADS, REQUIRED_PARAM) },
  { "--threads",   std::make_pair(OPTION_THREADS, REQUIRED_PARAM) },
  { "--time",      std::make_pair(OPTION_TIME, NO_PARAM) },
  { "-v",          std::make_pair(OPTION_VERSION, NO_PARAM) },
  { "--version",   std::make_pair(OPTION_VERSION, NO_PARAM) }
};

/// Command-line option
struct Option
{
  // Example:
  // str = "--threads=32"
  // opt = "--threads"
  // val = "32"
  std::string str;
  std::string opt;
  std::string val;

  template <typename T>
  T getValue() const
  {
    try {
      return calculator::eval<T>(val);
    }
    catch (std::exception&) {
      throw primesieve_error("invalid option '" + opt + "=" + val + "'");
    }
  }
};

/// Options start with "-" or "--", then
/// follows a Latin ASCII character.
///
bool isOption(const std::string& str)
{
  // Option of type: -o...
  if (str.size() >= 2 &&
      str[0] == '-' &&
      ((str[1] >= 'a' && str[1] <= 'z') ||
       (str[1] >= 'A' && str[1] <= 'Z')))
    return true;

  // Option of type: --o...
  if (str.size() >= 3 &&
      str[0] == '-' &&
      str[1] == '-' &&
      ((str[2] >= 'a' && str[2] <= 'z') ||
       (str[2] >= 'A' && str[2] <= 'Z')))
    return true;

  return false;
}

/// Parse the next command-line option.
/// e.g. "--threads=32"
/// -> opt.str = "--threads=32"
/// -> opt.opt = "--threads"
/// -> opt.val = "8"
///
Option parseOption(int argc, char* argv[], int& i)
{
  Option opt;
  opt.str = argv[i];

  if (opt.str.empty())
    throw primesieve_error("unrecognized option ''");

  // Check if the option has the format:
  // --opt or -o (but not --opt=N)
  if (optionMap.count(opt.str))
  {
    opt.opt = opt.str;
    IsParam isParam = optionMap[opt.str].second;

    if (isParam == REQUIRED_PARAM)
    {
      i += 1;

      if (i < argc)
        opt.val = argv[i];

      // Prevent --threads --other-option
      if (opt.val.empty() || isOption(opt.val))
        throw primesieve_error("missing value for option '" + opt.opt + "'");
    }

    // If the option takes an optional argument we
    // assume the next value is an optional argument
    // if the value is not a vaild option.
    if (isParam == OPTIONAL_PARAM &&
        i + 1 < argc &&
        !std::string(argv[i + 1]).empty() &&
        !isOption(argv[i + 1]))
    {
      i += 1;
      opt.val = argv[i];
    }
  }
  else
  {
    // Here the option is either:
    // 1) An option of type: --opt[=N]
    // 2) An option of type: --opt[N]
    // 3) A number (e.g. the start number)

    if (isOption(opt.str))
    {
      size_t pos = opt.str.find("=");

      // Option of type: --opt=N
      if (pos != std::string::npos)
      {
        opt.opt = opt.str.substr(0, pos);
        opt.val = opt.str.substr(pos + 1);

        // Print partial option: --opt (without =N)
        if (!optionMap.count(opt.opt))
          throw primesieve_error("unrecognized option '" + opt.opt + "'");
      }
      else
      {
        // Option of type: --opt[N]
        pos = opt.str.find_first_of("0123456789");

        if (pos == std::string::npos)
          opt.opt = opt.str;
        else
        {
          opt.opt = opt.str.substr(0, pos);
          opt.val = opt.str.substr(pos);
        }

        // Print full option e.g.: --opt123
        if (!optionMap.count(opt.opt))
          throw primesieve_error("unrecognized option '" + opt.str + "'");
      }

      // Prevent '--option='
      if (opt.val.empty() &&
          optionMap[opt.opt].second == REQUIRED_PARAM)
        throw primesieve_error("missing value for option '" + opt.opt + "'");
    }
    else
    {
      // Here the option is actually a number or
      // an integer arithmetic expression.
      opt.opt = "--number";
      opt.val = opt.str;

      // This is not a valid number
      if (opt.str.find_first_of("0123456789") == std::string::npos)
        throw primesieve_error("unrecognized option '" + opt.str + "'");

      // Prevent negative numbers as there are
      // no negative prime numbers.
      if (opt.str.at(0) == '-')
        throw primesieve_error("unrecognized option '" + opt.str + "'");
    }
  }

  return opt;
}

void optionPrint(Option& opt,
                 CmdOptions& opts)
{
  opts.quiet = true;

  // by default print primes
  if (opt.val.empty())
    opt.val = "1";

  switch (opt.getValue<int>())
  {
    case 1: opts.flags |= PRINT_PRIMES; break;
    case 2: opts.flags |= PRINT_TWINS; break;
    case 3: opts.flags |= PRINT_TRIPLETS; break;
    case 4: opts.flags |= PRINT_QUADRUPLETS; break;
    case 5: opts.flags |= PRINT_QUINTUPLETS; break;
    case 6: opts.flags |= PRINT_SEXTUPLETS; break;
    default: throw primesieve_error("invalid option '" + opt.str + "'");
  }
}

void optionCount(Option& opt,
                 CmdOptions& opts)
{
  // by default count primes
  if (opt.val.empty())
    opt.val = "1";

  int n = opt.getValue<int>();

  for (; n > 0; n /= 10)
  {
    switch (n % 10)
    {
      case 1: opts.flags |= COUNT_PRIMES; break;
      case 2: opts.flags |= COUNT_TWINS; break;
      case 3: opts.flags |= COUNT_TRIPLETS; break;
      case 4: opts.flags |= COUNT_QUADRUPLETS; break;
      case 5: opts.flags |= COUNT_QUINTUPLETS; break;
      case 6: opts.flags |= COUNT_SEXTUPLETS; break;
      default: throw primesieve_error("invalid option '" + opt.str + "'");
    }
  }
}

void optionDistance(Option& opt,
                    CmdOptions& opts)
{
  uint64_t start = 0;
  uint64_t val = opt.getValue<uint64_t>();
  auto& numbers = opts.numbers;

  if (!numbers.empty())
    start = numbers[0];

  numbers.push_back(start + val);
}

void optionCpuInfo()
{
  const CpuInfo cpu;

  if (cpu.hasCpuName())
    std::cout << cpu.cpuName() << std::endl;
  else
    std::cout << "CPU name: unknown" << std::endl;

  if (cpu.hasLogicalCpuCores())
    std::cout << "Logical CPU cores: " << cpu.logicalCpuCores() << std::endl;
  else
    std::cout << "Logical CPU cores: unknown" << std::endl;

  // We only show AVX512 info if libprimesieve has been compiled
  // with AVX512 support. If "AVX512: yes" then primesieve::iterator
  // uses the AVX512 version of PrimeGenerator::fillNextPrimes().
  #if defined(MULTIARCH_AVX512)
    if (cpu.hasAVX512())
      std::cout << "Has AVX512: yes" << std::endl;
    else
      std::cout << "Has AVX512: no" << std::endl;
  #endif

  if (cpu.hasL1Cache())
    std::cout << "L1 cache size: " << (cpu.l1CacheBytes() >> 10) << " KiB" << std::endl;

  if (cpu.hasL2Cache())
    std::cout << "L2 cache size: " << (cpu.l2CacheBytes() >> 10) << " KiB" << std::endl;

  if (cpu.hasL3Cache())
    std::cout << "L3 cache size: " << (cpu.l3CacheBytes() >> 20) << " MiB" << std::endl;

  if (cpu.hasL1Cache())
  {
    if (!cpu.hasL1Sharing())
      std::cout << "L1 cache sharing: unknown" << std::endl;
    else
      std::cout << "L1 cache sharing: " << cpu.l1Sharing()
                << ((cpu.l1Sharing() > 1) ? " threads" : " thread") << std::endl;
  }

  if (cpu.hasL2Cache())
  {
    if (!cpu.hasL2Sharing())
      std::cout << "L2 cache sharing: unknown" << std::endl;
    else
      std::cout << "L2 cache sharing: " << cpu.l2Sharing()
                << ((cpu.l2Sharing() > 1) ? " threads" : " thread") << std::endl;
  }

  if (cpu.hasL3Cache())
  {
    if (!cpu.hasL3Sharing())
      std::cout << "L3 cache sharing: unknown" << std::endl;
    else
      std::cout << "L3 cache sharing: " << cpu.l3Sharing()
                << ((cpu.l3Sharing() > 1) ? " threads" : " thread") << std::endl;
  }

  if (!cpu.hasL1Cache() &&
      !cpu.hasL2Cache() &&
      !cpu.hasL3Cache())
  {
    std::cout << "L1 cache size: unknown" << std::endl;
    std::cout << "L2 cache size: unknown" << std::endl;
    std::cout << "L3 cache size: unknown" << std::endl;
    std::cout << "L1 cache sharing: unknown" << std::endl;
    std::cout << "L2 cache sharing: unknown" << std::endl;
    std::cout << "L3 cache sharing: unknown" << std::endl;
  }

  std::exit(0);
}

} // namespace

CmdOptions parseOptions(int argc, char* argv[])
{
  CmdOptions opts;

  // No command-line options provided
  if (argc <= 1)
    help(/* exitCode */ 1);

  for (int i = 1; i < argc; i++)
  {
    Option opt = parseOption(argc, argv, i);
    OptionID optionID = optionMap[opt.opt].first;

    switch (optionID)
    {
      case OPTION_COUNT:     optionCount(opt, opts); break;
      case OPTION_CPU_INFO:  optionCpuInfo(); break;
      case OPTION_DISTANCE:  optionDistance(opt, opts); break;
      case OPTION_PRINT:     optionPrint(opt, opts); break;
      case OPTION_SIZE:      opts.sieveSize = opt.getValue<int>(); break;
      case OPTION_THREADS:   opts.threads = opt.getValue<int>(); break;
      case OPTION_QUIET:     opts.quiet = true; break;
      case OPTION_NTH_PRIME: opts.nthPrime = true; break;
      case OPTION_NO_STATUS: opts.status = false; break;
      case OPTION_TIME:      opts.time = true; break;
      case OPTION_NUMBER:    opts.numbers.push_back(opt.getValue<uint64_t>()); break;
      case OPTION_HELP:      help(/* exitCode */ 0); break;
      case OPTION_TEST:      test(); break;
      case OPTION_VERSION:   version(); break;
    }
  }

  if (opts.numbers.empty())
    throw primesieve_error("missing STOP number");

  if (opts.quiet)
    opts.status = false;
  else
    opts.time = true;

  return opts;
}
<commit_msg>Get rid of global std::map<commit_after>///
/// @file   cmdoptions.cpp
/// @brief  Parse command-line options for the primesieve console
///         (terminal) application.
///
/// Copyright (C) 2022 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include "cmdoptions.hpp"

#include <primesieve/calculator.hpp>
#include <primesieve/CpuInfo.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/primesieve_error.hpp>

#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <map>
#include <stdint.h>
#include <string>
#include <utility>

void help(int exitCode);
void test();
void version();

using std::size_t;
using namespace primesieve;

namespace {

enum OptionID
{
  OPTION_COUNT,
  OPTION_CPU_INFO,
  OPTION_HELP,
  OPTION_NTH_PRIME,
  OPTION_NO_STATUS,
  OPTION_NUMBER,
  OPTION_DISTANCE,
  OPTION_PRINT,
  OPTION_QUIET,
  OPTION_SIZE,
  OPTION_TEST,
  OPTION_THREADS,
  OPTION_TIME,
  OPTION_VERSION
};

/// Some command-line options require an additional parameter.
/// Examples: --threads THREADS, -a ALPHA, ...
enum IsParam
{
  NO_PARAM,
  REQUIRED_PARAM,
  OPTIONAL_PARAM
};

/// Command-line option
struct Option
{
  // Example:
  // str = "--threads=32"
  // opt = "--threads"
  // val = "32"
  std::string str;
  std::string opt;
  std::string val;

  template <typename T>
  T getValue() const
  {
    try {
      return calculator::eval<T>(val);
    }
    catch (std::exception&) {
      throw primesieve_error("invalid option '" + opt + "=" + val + "'");
    }
  }
};

/// Options start with "-" or "--", then
/// follows a Latin ASCII character.
///
bool isOption(const std::string& str)
{
  // Option of type: -o...
  if (str.size() >= 2 &&
      str[0] == '-' &&
      ((str[1] >= 'a' && str[1] <= 'z') ||
       (str[1] >= 'A' && str[1] <= 'Z')))
    return true;

  // Option of type: --o...
  if (str.size() >= 3 &&
      str[0] == '-' &&
      str[1] == '-' &&
      ((str[2] >= 'a' && str[2] <= 'z') ||
       (str[2] >= 'A' && str[2] <= 'Z')))
    return true;

  return false;
}

/// Parse the next command-line option.
/// e.g. "--threads=32"
/// -> opt.str = "--threads=32"
/// -> opt.opt = "--threads"
/// -> opt.val = "8"
///
template <typename T>
Option parseOption(int argc,
                   char* argv[],
                   int& i,
                   const T& optionMap)
{
  Option opt;
  opt.str = argv[i];

  if (opt.str.empty())
    throw primesieve_error("unrecognized option ''");

  // Check if the option has the format:
  // --opt or -o (but not --opt=N)
  if (optionMap.count(opt.str))
  {
    opt.opt = opt.str;
    IsParam isParam = optionMap.at(opt.str).second;

    if (isParam == REQUIRED_PARAM)
    {
      i += 1;

      if (i < argc)
        opt.val = argv[i];

      // Prevent --threads --other-option
      if (opt.val.empty() || isOption(opt.val))
        throw primesieve_error("missing value for option '" + opt.opt + "'");
    }

    // If the option takes an optional argument we
    // assume the next value is an optional argument
    // if the value is not a vaild option.
    if (isParam == OPTIONAL_PARAM &&
        i + 1 < argc &&
        !std::string(argv[i + 1]).empty() &&
        !isOption(argv[i + 1]))
    {
      i += 1;
      opt.val = argv[i];
    }
  }
  else
  {
    // Here the option is either:
    // 1) An option of type: --opt[=N]
    // 2) An option of type: --opt[N]
    // 3) A number (e.g. the start number)

    if (isOption(opt.str))
    {
      size_t pos = opt.str.find("=");

      // Option of type: --opt=N
      if (pos != std::string::npos)
      {
        opt.opt = opt.str.substr(0, pos);
        opt.val = opt.str.substr(pos + 1);

        // Print partial option: --opt (without =N)
        if (!optionMap.count(opt.opt))
          throw primesieve_error("unrecognized option '" + opt.opt + "'");
      }
      else
      {
        // Option of type: --opt[N]
        pos = opt.str.find_first_of("0123456789");

        if (pos == std::string::npos)
          opt.opt = opt.str;
        else
        {
          opt.opt = opt.str.substr(0, pos);
          opt.val = opt.str.substr(pos);
        }

        // Print full option e.g.: --opt123
        if (!optionMap.count(opt.opt))
          throw primesieve_error("unrecognized option '" + opt.str + "'");
      }

      // Prevent '--option='
      if (opt.val.empty() &&
          optionMap.at(opt.opt).second == REQUIRED_PARAM)
        throw primesieve_error("missing value for option '" + opt.opt + "'");
    }
    else
    {
      // Here the option is actually a number or
      // an integer arithmetic expression.
      opt.opt = "--number";
      opt.val = opt.str;

      // This is not a valid number
      if (opt.str.find_first_of("0123456789") == std::string::npos)
        throw primesieve_error("unrecognized option '" + opt.str + "'");

      // Prevent negative numbers as there are
      // no negative prime numbers.
      if (opt.str.at(0) == '-')
        throw primesieve_error("unrecognized option '" + opt.str + "'");
    }
  }

  return opt;
}

void optionPrint(Option& opt,
                 CmdOptions& opts)
{
  opts.quiet = true;

  // by default print primes
  if (opt.val.empty())
    opt.val = "1";

  switch (opt.getValue<int>())
  {
    case 1: opts.flags |= PRINT_PRIMES; break;
    case 2: opts.flags |= PRINT_TWINS; break;
    case 3: opts.flags |= PRINT_TRIPLETS; break;
    case 4: opts.flags |= PRINT_QUADRUPLETS; break;
    case 5: opts.flags |= PRINT_QUINTUPLETS; break;
    case 6: opts.flags |= PRINT_SEXTUPLETS; break;
    default: throw primesieve_error("invalid option '" + opt.str + "'");
  }
}

void optionCount(Option& opt,
                 CmdOptions& opts)
{
  // by default count primes
  if (opt.val.empty())
    opt.val = "1";

  int n = opt.getValue<int>();

  for (; n > 0; n /= 10)
  {
    switch (n % 10)
    {
      case 1: opts.flags |= COUNT_PRIMES; break;
      case 2: opts.flags |= COUNT_TWINS; break;
      case 3: opts.flags |= COUNT_TRIPLETS; break;
      case 4: opts.flags |= COUNT_QUADRUPLETS; break;
      case 5: opts.flags |= COUNT_QUINTUPLETS; break;
      case 6: opts.flags |= COUNT_SEXTUPLETS; break;
      default: throw primesieve_error("invalid option '" + opt.str + "'");
    }
  }
}

void optionDistance(Option& opt,
                    CmdOptions& opts)
{
  uint64_t start = 0;
  uint64_t val = opt.getValue<uint64_t>();
  auto& numbers = opts.numbers;

  if (!numbers.empty())
    start = numbers[0];

  numbers.push_back(start + val);
}

void optionCpuInfo()
{
  const CpuInfo cpu;

  if (cpu.hasCpuName())
    std::cout << cpu.cpuName() << std::endl;
  else
    std::cout << "CPU name: unknown" << std::endl;

  if (cpu.hasLogicalCpuCores())
    std::cout << "Logical CPU cores: " << cpu.logicalCpuCores() << std::endl;
  else
    std::cout << "Logical CPU cores: unknown" << std::endl;

  // We only show AVX512 info if libprimesieve has been compiled
  // with AVX512 support. If "AVX512: yes" then primesieve::iterator
  // uses the AVX512 version of PrimeGenerator::fillNextPrimes().
  #if defined(MULTIARCH_AVX512)
    if (cpu.hasAVX512())
      std::cout << "Has AVX512: yes" << std::endl;
    else
      std::cout << "Has AVX512: no" << std::endl;
  #endif

  if (cpu.hasL1Cache())
    std::cout << "L1 cache size: " << (cpu.l1CacheBytes() >> 10) << " KiB" << std::endl;

  if (cpu.hasL2Cache())
    std::cout << "L2 cache size: " << (cpu.l2CacheBytes() >> 10) << " KiB" << std::endl;

  if (cpu.hasL3Cache())
    std::cout << "L3 cache size: " << (cpu.l3CacheBytes() >> 20) << " MiB" << std::endl;

  if (cpu.hasL1Cache())
  {
    if (!cpu.hasL1Sharing())
      std::cout << "L1 cache sharing: unknown" << std::endl;
    else
      std::cout << "L1 cache sharing: " << cpu.l1Sharing()
                << ((cpu.l1Sharing() > 1) ? " threads" : " thread") << std::endl;
  }

  if (cpu.hasL2Cache())
  {
    if (!cpu.hasL2Sharing())
      std::cout << "L2 cache sharing: unknown" << std::endl;
    else
      std::cout << "L2 cache sharing: " << cpu.l2Sharing()
                << ((cpu.l2Sharing() > 1) ? " threads" : " thread") << std::endl;
  }

  if (cpu.hasL3Cache())
  {
    if (!cpu.hasL3Sharing())
      std::cout << "L3 cache sharing: unknown" << std::endl;
    else
      std::cout << "L3 cache sharing: " << cpu.l3Sharing()
                << ((cpu.l3Sharing() > 1) ? " threads" : " thread") << std::endl;
  }

  if (!cpu.hasL1Cache() &&
      !cpu.hasL2Cache() &&
      !cpu.hasL3Cache())
  {
    std::cout << "L1 cache size: unknown" << std::endl;
    std::cout << "L2 cache size: unknown" << std::endl;
    std::cout << "L3 cache size: unknown" << std::endl;
    std::cout << "L1 cache sharing: unknown" << std::endl;
    std::cout << "L2 cache sharing: unknown" << std::endl;
    std::cout << "L3 cache sharing: unknown" << std::endl;
  }

  std::exit(0);
}

} // namespace

CmdOptions parseOptions(int argc, char* argv[])
{
  // No command-line options provided
  if (argc <= 1)
    help(/* exitCode */ 1);

  /// primesieve command-line options
  const std::map<std::string, std::pair<OptionID, IsParam>> optionMap =
  {
    { "-c",          std::make_pair(OPTION_COUNT, OPTIONAL_PARAM) },
    { "--count",     std::make_pair(OPTION_COUNT, OPTIONAL_PARAM) },
    { "--cpu-info",  std::make_pair(OPTION_CPU_INFO, NO_PARAM) },
    { "-h",          std::make_pair(OPTION_HELP, NO_PARAM) },
    { "--help",      std::make_pair(OPTION_HELP, NO_PARAM) },
    { "-n",          std::make_pair(OPTION_NTH_PRIME, NO_PARAM) },
    { "--nthprime",  std::make_pair(OPTION_NTH_PRIME, NO_PARAM) },
    { "--nth-prime", std::make_pair(OPTION_NTH_PRIME, NO_PARAM) },
    { "--no-status", std::make_pair(OPTION_NO_STATUS, NO_PARAM) },
    { "--number",    std::make_pair(OPTION_NUMBER, REQUIRED_PARAM) },
    { "-d",          std::make_pair(OPTION_DISTANCE, REQUIRED_PARAM) },
    { "--dist",      std::make_pair(OPTION_DISTANCE, REQUIRED_PARAM) },
    { "-p",          std::make_pair(OPTION_PRINT, OPTIONAL_PARAM) },
    { "--print",     std::make_pair(OPTION_PRINT, OPTIONAL_PARAM) },
    { "-q",          std::make_pair(OPTION_QUIET, NO_PARAM) },
    { "--quiet",     std::make_pair(OPTION_QUIET, NO_PARAM) },
    { "-s",          std::make_pair(OPTION_SIZE, REQUIRED_PARAM) },
    { "--size",      std::make_pair(OPTION_SIZE, REQUIRED_PARAM) },
    { "--test",      std::make_pair(OPTION_TEST, NO_PARAM) },
    { "-t",          std::make_pair(OPTION_THREADS, REQUIRED_PARAM) },
    { "--threads",   std::make_pair(OPTION_THREADS, REQUIRED_PARAM) },
    { "--time",      std::make_pair(OPTION_TIME, NO_PARAM) },
    { "-v",          std::make_pair(OPTION_VERSION, NO_PARAM) },
    { "--version",   std::make_pair(OPTION_VERSION, NO_PARAM) }
  };

  CmdOptions opts;

  for (int i = 1; i < argc; i++)
  {
    Option opt = parseOption(argc, argv, i, optionMap);
    OptionID optionID = optionMap.at(opt.opt).first;

    switch (optionID)
    {
      case OPTION_COUNT:     optionCount(opt, opts); break;
      case OPTION_CPU_INFO:  optionCpuInfo(); break;
      case OPTION_DISTANCE:  optionDistance(opt, opts); break;
      case OPTION_PRINT:     optionPrint(opt, opts); break;
      case OPTION_SIZE:      opts.sieveSize = opt.getValue<int>(); break;
      case OPTION_THREADS:   opts.threads = opt.getValue<int>(); break;
      case OPTION_QUIET:     opts.quiet = true; break;
      case OPTION_NTH_PRIME: opts.nthPrime = true; break;
      case OPTION_NO_STATUS: opts.status = false; break;
      case OPTION_TIME:      opts.time = true; break;
      case OPTION_NUMBER:    opts.numbers.push_back(opt.getValue<uint64_t>()); break;
      case OPTION_HELP:      help(/* exitCode */ 0); break;
      case OPTION_TEST:      test(); break;
      case OPTION_VERSION:   version(); break;
    }
  }

  if (opts.numbers.empty())
    throw primesieve_error("missing STOP number");

  if (opts.quiet)
    opts.status = false;
  else
    opts.time = true;

  return opts;
}
<|endoftext|>


<commit_before>//===-- sanitizer_win.cc --------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements windows-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS

#define WIN32_LEAN_AND_MEAN
#define NOGDI
#include <stdlib.h>
#include <io.h>
#include <windows.h>

#include "sanitizer_common.h"
#include "sanitizer_libc.h"
#include "sanitizer_mutex.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_stacktrace.h"

namespace __sanitizer {

#include "sanitizer_syscall_generic.inc"

// --------------------- sanitizer_common.h
uptr GetPageSize() {
  return 1U << 14;  // FIXME: is this configurable?
}

uptr GetMmapGranularity() {
  return 1U << 16;  // FIXME: is this configurable?
}

uptr GetMaxVirtualAddress() {
  SYSTEM_INFO si;
  GetSystemInfo(&si);
  return (uptr)si.lpMaximumApplicationAddress;
}

bool FileExists(const char *filename) {
  UNIMPLEMENTED();
}

uptr internal_getpid() {
  return GetProcessId(GetCurrentProcess());
}

// In contrast to POSIX, on Windows GetCurrentThreadId()
// returns a system-unique identifier.
uptr GetTid() {
  return GetCurrentThreadId();
}

uptr GetThreadSelf() {
  return GetTid();
}

void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                uptr *stack_bottom) {
  CHECK(stack_top);
  CHECK(stack_bottom);
  MEMORY_BASIC_INFORMATION mbi;
  CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
  // FIXME: is it possible for the stack to not be a single allocation?
  // Are these values what ASan expects to get (reserved, not committed;
  // including stack guard page) ?
  *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
  *stack_bottom = (uptr)mbi.AllocationBase;
}

void *MmapOrDie(uptr size, const char *mem_type) {
  void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  if (rv == 0) {
    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n",
           size, size, mem_type);
    CHECK("unable to mmap" && 0);
  }
  return rv;
}

void UnmapOrDie(void *addr, uptr size) {
  if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
    Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
           size, size, addr);
    CHECK("unable to unmap" && 0);
  }
}

void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
  // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
  // but on Win64 it does.
  void *p = VirtualAlloc((LPVOID)fixed_addr, size,
      MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  if (p == 0)
    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at %p (%d)\n",
           size, size, fixed_addr, GetLastError());
  return p;
}

void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
  return MmapFixedNoReserve(fixed_addr, size);
}

void *Mprotect(uptr fixed_addr, uptr size) {
  return VirtualAlloc((LPVOID)fixed_addr, size,
                      MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
}

void FlushUnneededShadowMemory(uptr addr, uptr size) {
  // This is almost useless on 32-bits.
  // FIXME: add madvice-analog when we move to 64-bits.
}

bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
  // FIXME: shall we do anything here on Windows?
  return true;
}

void *MapFileToMemory(const char *file_name, uptr *buff_size) {
  UNIMPLEMENTED();
}

static const int kMaxEnvNameLength = 128;
static const DWORD kMaxEnvValueLength = 32767;

namespace {

struct EnvVariable {
  char name[kMaxEnvNameLength];
  char value[kMaxEnvValueLength];
};

}  // namespace

static const int kEnvVariables = 5;
static EnvVariable env_vars[kEnvVariables];
static int num_env_vars;

const char *GetEnv(const char *name) {
  // Note: this implementation caches the values of the environment variables
  // and limits their quantity.
  for (int i = 0; i < num_env_vars; i++) {
    if (0 == internal_strcmp(name, env_vars[i].name))
      return env_vars[i].value;
  }
  CHECK_LT(num_env_vars, kEnvVariables);
  DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value,
                                     kMaxEnvValueLength);
  if (rv > 0 && rv < kMaxEnvValueLength) {
    CHECK_LT(internal_strlen(name), kMaxEnvNameLength);
    internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength);
    num_env_vars++;
    return env_vars[num_env_vars - 1].value;
  }
  return 0;
}

const char *GetPwd() {
  UNIMPLEMENTED();
}

u32 GetUid() {
  UNIMPLEMENTED();
}

void DumpProcessMap() {
  UNIMPLEMENTED();
}

void DisableCoreDumper() {
  UNIMPLEMENTED();
}

void ReExec() {
  UNIMPLEMENTED();
}

void PrepareForSandboxing() {
  // Nothing here for now.
}

bool StackSizeIsUnlimited() {
  UNIMPLEMENTED();
}

void SetStackSizeLimitInBytes(uptr limit) {
  UNIMPLEMENTED();
}

char *FindPathToBinary(const char *name) {
  // Nothing here for now.
  return 0;
}

void SleepForSeconds(int seconds) {
  Sleep(seconds * 1000);
}

void SleepForMillis(int millis) {
  Sleep(millis);
}

u64 NanoTime() {
  return 0;
}

void Abort() {
  abort();
  _exit(-1);  // abort is not NORETURN on Windows.
}

uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                      string_predicate_t filter) {
  UNIMPLEMENTED();
};

#ifndef SANITIZER_GO
int Atexit(void (*function)(void)) {
  return atexit(function);
}
#endif

// ------------------ sanitizer_libc.h
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
                   int fd, u64 offset) {
  UNIMPLEMENTED();
}

uptr internal_munmap(void *addr, uptr length) {
  UNIMPLEMENTED();
}

uptr internal_close(fd_t fd) {
  UNIMPLEMENTED();
}

int internal_isatty(fd_t fd) {
  return _isatty(fd);
}

uptr internal_open(const char *filename, int flags) {
  UNIMPLEMENTED();
}

uptr internal_open(const char *filename, int flags, u32 mode) {
  UNIMPLEMENTED();
}

uptr OpenFile(const char *filename, bool write) {
  UNIMPLEMENTED();
}

uptr internal_read(fd_t fd, void *buf, uptr count) {
  UNIMPLEMENTED();
}

uptr internal_write(fd_t fd, const void *buf, uptr count) {
  if (fd != kStderrFd)
    UNIMPLEMENTED();
  HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
  if (err == 0)
    return 0;  // FIXME: this might not work on some apps.
  DWORD ret;
  if (!WriteFile(err, buf, count, &ret, 0))
    return 0;
  return ret;
}

uptr internal_stat(const char *path, void *buf) {
  UNIMPLEMENTED();
}

uptr internal_lstat(const char *path, void *buf) {
  UNIMPLEMENTED();
}

uptr internal_fstat(fd_t fd, void *buf) {
  UNIMPLEMENTED();
}

uptr internal_filesize(fd_t fd) {
  UNIMPLEMENTED();
}

uptr internal_dup2(int oldfd, int newfd) {
  UNIMPLEMENTED();
}

uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
  UNIMPLEMENTED();
}

uptr internal_sched_yield() {
  Sleep(0);
  return 0;
}

void internal__exit(int exitcode) {
  _exit(exitcode);
}

// ---------------------- BlockingMutex ---------------- {{{1
const uptr LOCK_UNINITIALIZED = 0;
const uptr LOCK_READY = (uptr)-1;

BlockingMutex::BlockingMutex(LinkerInitialized li) {
  // FIXME: see comments in BlockingMutex::Lock() for the details.
  CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);

  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
  owner_ = LOCK_READY;
}

BlockingMutex::BlockingMutex() {
  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
  owner_ = LOCK_READY;
}

void BlockingMutex::Lock() {
  if (owner_ == LOCK_UNINITIALIZED) {
    // FIXME: hm, global BlockingMutex objects are not initialized?!?
    // This might be a side effect of the clang+cl+link Frankenbuild...
    new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));

    // FIXME: If it turns out the linker doesn't invoke our
    // constructors, we should probably manually Lock/Unlock all the global
    // locks while we're starting in one thread to avoid double-init races.
  }
  EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
  CHECK_EQ(owner_, LOCK_READY);
  owner_ = GetThreadSelf();
}

void BlockingMutex::Unlock() {
  CHECK_EQ(owner_, GetThreadSelf());
  owner_ = LOCK_READY;
  LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
}

void BlockingMutex::CheckLocked() {
  CHECK_EQ(owner_, GetThreadSelf());
}

uptr GetTlsSize() {
  return 0;
}

void InitTlsSize() {
}

void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
                          uptr *tls_addr, uptr *tls_size) {
#ifdef SANITIZER_GO
  *stk_addr = 0;
  *stk_size = 0;
  *tls_addr = 0;
  *tls_size = 0;
#else
  uptr stack_top, stack_bottom;
  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
  *stk_addr = stack_bottom;
  *stk_size = stack_top - stack_bottom;
  *tls_addr = 0;
  *tls_size = 0;
#endif
}

void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
  // FIXME: CaptureStackBackTrace might be too slow for us.
  // FIXME: Compare with StackWalk64.
  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
  size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
                               (void**)trace, 0);
  // Skip the RTL frames by searching for the PC in the stacktrace.
  uptr pc_location = LocatePcInTrace(pc);
  PopStackFrames(pc_location);
}

void MaybeOpenReportFile() {
  // Windows doesn't have native fork, and we don't support Cygwin or other
  // environments that try to fake it, so the initial report_fd will always be
  // correct.
}

void RawWrite(const char *buffer) {
  static const char *kRawWriteError =
      "RawWrite can't output requested buffer!\n";
  uptr length = (uptr)internal_strlen(buffer);
  if (length != internal_write(report_fd, buffer, length)) {
    // stderr may be closed, but we may be able to print to the debugger
    // instead.  This is the case when launching a program from Visual Studio,
    // and the following routine should write to its console.
    OutputDebugStringA(buffer);
  }
}

}  // namespace __sanitizer

#endif  // _WIN32
<commit_msg>[ASan] Use ExitProcess rather than _exit on Windows to avoid calling global dtors etc<commit_after>//===-- sanitizer_win.cc --------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements windows-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS

#define WIN32_LEAN_AND_MEAN
#define NOGDI
#include <stdlib.h>
#include <io.h>
#include <windows.h>

#include "sanitizer_common.h"
#include "sanitizer_libc.h"
#include "sanitizer_mutex.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_stacktrace.h"

namespace __sanitizer {

#include "sanitizer_syscall_generic.inc"

// --------------------- sanitizer_common.h
uptr GetPageSize() {
  return 1U << 14;  // FIXME: is this configurable?
}

uptr GetMmapGranularity() {
  return 1U << 16;  // FIXME: is this configurable?
}

uptr GetMaxVirtualAddress() {
  SYSTEM_INFO si;
  GetSystemInfo(&si);
  return (uptr)si.lpMaximumApplicationAddress;
}

bool FileExists(const char *filename) {
  UNIMPLEMENTED();
}

uptr internal_getpid() {
  return GetProcessId(GetCurrentProcess());
}

// In contrast to POSIX, on Windows GetCurrentThreadId()
// returns a system-unique identifier.
uptr GetTid() {
  return GetCurrentThreadId();
}

uptr GetThreadSelf() {
  return GetTid();
}

void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                uptr *stack_bottom) {
  CHECK(stack_top);
  CHECK(stack_bottom);
  MEMORY_BASIC_INFORMATION mbi;
  CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
  // FIXME: is it possible for the stack to not be a single allocation?
  // Are these values what ASan expects to get (reserved, not committed;
  // including stack guard page) ?
  *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
  *stack_bottom = (uptr)mbi.AllocationBase;
}

void *MmapOrDie(uptr size, const char *mem_type) {
  void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  if (rv == 0) {
    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n",
           size, size, mem_type);
    CHECK("unable to mmap" && 0);
  }
  return rv;
}

void UnmapOrDie(void *addr, uptr size) {
  if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
    Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
           size, size, addr);
    CHECK("unable to unmap" && 0);
  }
}

void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
  // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
  // but on Win64 it does.
  void *p = VirtualAlloc((LPVOID)fixed_addr, size,
      MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  if (p == 0)
    Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at %p (%d)\n",
           size, size, fixed_addr, GetLastError());
  return p;
}

void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
  return MmapFixedNoReserve(fixed_addr, size);
}

void *Mprotect(uptr fixed_addr, uptr size) {
  return VirtualAlloc((LPVOID)fixed_addr, size,
                      MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
}

void FlushUnneededShadowMemory(uptr addr, uptr size) {
  // This is almost useless on 32-bits.
  // FIXME: add madvice-analog when we move to 64-bits.
}

bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
  // FIXME: shall we do anything here on Windows?
  return true;
}

void *MapFileToMemory(const char *file_name, uptr *buff_size) {
  UNIMPLEMENTED();
}

static const int kMaxEnvNameLength = 128;
static const DWORD kMaxEnvValueLength = 32767;

namespace {

struct EnvVariable {
  char name[kMaxEnvNameLength];
  char value[kMaxEnvValueLength];
};

}  // namespace

static const int kEnvVariables = 5;
static EnvVariable env_vars[kEnvVariables];
static int num_env_vars;

const char *GetEnv(const char *name) {
  // Note: this implementation caches the values of the environment variables
  // and limits their quantity.
  for (int i = 0; i < num_env_vars; i++) {
    if (0 == internal_strcmp(name, env_vars[i].name))
      return env_vars[i].value;
  }
  CHECK_LT(num_env_vars, kEnvVariables);
  DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value,
                                     kMaxEnvValueLength);
  if (rv > 0 && rv < kMaxEnvValueLength) {
    CHECK_LT(internal_strlen(name), kMaxEnvNameLength);
    internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength);
    num_env_vars++;
    return env_vars[num_env_vars - 1].value;
  }
  return 0;
}

const char *GetPwd() {
  UNIMPLEMENTED();
}

u32 GetUid() {
  UNIMPLEMENTED();
}

void DumpProcessMap() {
  UNIMPLEMENTED();
}

void DisableCoreDumper() {
  UNIMPLEMENTED();
}

void ReExec() {
  UNIMPLEMENTED();
}

void PrepareForSandboxing() {
  // Nothing here for now.
}

bool StackSizeIsUnlimited() {
  UNIMPLEMENTED();
}

void SetStackSizeLimitInBytes(uptr limit) {
  UNIMPLEMENTED();
}

char *FindPathToBinary(const char *name) {
  // Nothing here for now.
  return 0;
}

void SleepForSeconds(int seconds) {
  Sleep(seconds * 1000);
}

void SleepForMillis(int millis) {
  Sleep(millis);
}

u64 NanoTime() {
  return 0;
}

void Abort() {
  abort();
  internal__exit(-1);  // abort is not NORETURN on Windows.
}

uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                      string_predicate_t filter) {
  UNIMPLEMENTED();
};

#ifndef SANITIZER_GO
int Atexit(void (*function)(void)) {
  return atexit(function);
}
#endif

// ------------------ sanitizer_libc.h
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
                   int fd, u64 offset) {
  UNIMPLEMENTED();
}

uptr internal_munmap(void *addr, uptr length) {
  UNIMPLEMENTED();
}

uptr internal_close(fd_t fd) {
  UNIMPLEMENTED();
}

int internal_isatty(fd_t fd) {
  return _isatty(fd);
}

uptr internal_open(const char *filename, int flags) {
  UNIMPLEMENTED();
}

uptr internal_open(const char *filename, int flags, u32 mode) {
  UNIMPLEMENTED();
}

uptr OpenFile(const char *filename, bool write) {
  UNIMPLEMENTED();
}

uptr internal_read(fd_t fd, void *buf, uptr count) {
  UNIMPLEMENTED();
}

uptr internal_write(fd_t fd, const void *buf, uptr count) {
  if (fd != kStderrFd)
    UNIMPLEMENTED();
  HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
  if (err == 0)
    return 0;  // FIXME: this might not work on some apps.
  DWORD ret;
  if (!WriteFile(err, buf, count, &ret, 0))
    return 0;
  return ret;
}

uptr internal_stat(const char *path, void *buf) {
  UNIMPLEMENTED();
}

uptr internal_lstat(const char *path, void *buf) {
  UNIMPLEMENTED();
}

uptr internal_fstat(fd_t fd, void *buf) {
  UNIMPLEMENTED();
}

uptr internal_filesize(fd_t fd) {
  UNIMPLEMENTED();
}

uptr internal_dup2(int oldfd, int newfd) {
  UNIMPLEMENTED();
}

uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
  UNIMPLEMENTED();
}

uptr internal_sched_yield() {
  Sleep(0);
  return 0;
}

void internal__exit(int exitcode) {
  ExitProcess(exitcode);
}

// ---------------------- BlockingMutex ---------------- {{{1
const uptr LOCK_UNINITIALIZED = 0;
const uptr LOCK_READY = (uptr)-1;

BlockingMutex::BlockingMutex(LinkerInitialized li) {
  // FIXME: see comments in BlockingMutex::Lock() for the details.
  CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);

  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
  owner_ = LOCK_READY;
}

BlockingMutex::BlockingMutex() {
  CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
  InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
  owner_ = LOCK_READY;
}

void BlockingMutex::Lock() {
  if (owner_ == LOCK_UNINITIALIZED) {
    // FIXME: hm, global BlockingMutex objects are not initialized?!?
    // This might be a side effect of the clang+cl+link Frankenbuild...
    new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));

    // FIXME: If it turns out the linker doesn't invoke our
    // constructors, we should probably manually Lock/Unlock all the global
    // locks while we're starting in one thread to avoid double-init races.
  }
  EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
  CHECK_EQ(owner_, LOCK_READY);
  owner_ = GetThreadSelf();
}

void BlockingMutex::Unlock() {
  CHECK_EQ(owner_, GetThreadSelf());
  owner_ = LOCK_READY;
  LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
}

void BlockingMutex::CheckLocked() {
  CHECK_EQ(owner_, GetThreadSelf());
}

uptr GetTlsSize() {
  return 0;
}

void InitTlsSize() {
}

void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
                          uptr *tls_addr, uptr *tls_size) {
#ifdef SANITIZER_GO
  *stk_addr = 0;
  *stk_size = 0;
  *tls_addr = 0;
  *tls_size = 0;
#else
  uptr stack_top, stack_bottom;
  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
  *stk_addr = stack_bottom;
  *stk_size = stack_top - stack_bottom;
  *tls_addr = 0;
  *tls_size = 0;
#endif
}

void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
  // FIXME: CaptureStackBackTrace might be too slow for us.
  // FIXME: Compare with StackWalk64.
  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
  size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
                               (void**)trace, 0);
  // Skip the RTL frames by searching for the PC in the stacktrace.
  uptr pc_location = LocatePcInTrace(pc);
  PopStackFrames(pc_location);
}

void MaybeOpenReportFile() {
  // Windows doesn't have native fork, and we don't support Cygwin or other
  // environments that try to fake it, so the initial report_fd will always be
  // correct.
}

void RawWrite(const char *buffer) {
  static const char *kRawWriteError =
      "RawWrite can't output requested buffer!\n";
  uptr length = (uptr)internal_strlen(buffer);
  if (length != internal_write(report_fd, buffer, length)) {
    // stderr may be closed, but we may be able to print to the debugger
    // instead.  This is the case when launching a program from Visual Studio,
    // and the following routine should write to its console.
    OutputDebugStringA(buffer);
  }
}

}  // namespace __sanitizer

#endif  // _WIN32
<|endoftext|>