<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: appmisc.cxx,v $
 *
 *  $Revision: 1.57 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 22:56:24 $
 *
 *  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_sfx2.hxx"

#ifndef _SV_STATUS_HXX
#include <vcl/status.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif
#ifndef _VOS_PROCESS_HXX //autogen
#include <vos/process.hxx>
#endif
#ifndef _XCEPTION_HXX_
#include <vos/xception.hxx>
#endif
#ifndef _SFX_WHITER_HXX //autogen
#include <svtools/whiter.hxx>
#endif
#ifndef _SFXSTRITEM_HXX //autogen
#include <svtools/stritem.hxx>
#endif
#ifndef _SFXINTITEM_HXX //autogen
#include <svtools/intitem.hxx>
#endif
#ifndef _SFXENUMITEM_HXX //autogen
#include <svtools/eitem.hxx>
#endif
#ifndef _FILTER_HXX //autogen
#include <svtools/filter.hxx>
#endif
#ifndef INCLUDED_SVTOOLS_INTERNALOPTIONS_HXX
#include <svtools/internaloptions.hxx>
#endif
#ifndef INCLUDED_SVTOOLS_PATHOPTIONS_HXX
#include <svtools/pathoptions.hxx>
#endif

#ifndef _COM_SUN_STAR_REGISTRY_INVALIDREGISTRYEXCEPTION_HPP_
#include <com/sun/star/registry/InvalidRegistryException.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_PropertyValue_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XFRAME_HPP_
#include <com/sun/star/frame/XFrame.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_
#include <com/sun/star/util/XURLTransformer.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XFRAMESSUPPLIER_HPP_
#include <com/sun/star/frame/XFramesSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _CONFIG_HXX
#include <tools/config.hxx>
#endif
#include <tools/rcid.h>
#include <vos/mutex.hxx>
#ifndef GCC
#endif
#ifndef _UTL_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif
#ifndef _COM_SUN_STAR_FRAME_XDESKTOP_HPP_
#include <com/sun/star/frame/XDesktop.hpp>
#endif

#include <unotools/ucbstreamhelper.hxx>
#include <framework/menuconfiguration.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/localfilehelper.hxx>
#include <unotools/bootstrap.hxx>
#include <svtools/moduleoptions.hxx>
#include <osl/file.hxx>

#include "sfxresid.hxx"
#include <sfx2/app.hxx>
#include "appdata.hxx"
#include "arrdecl.hxx"
#include <sfx2/tbxctrl.hxx>
#include "stbitem.hxx"
#include <sfx2/mnuitem.hxx>
#include <sfx2/docfac.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/request.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/dispatch.hxx>
#include "workwin.hxx"
#include "intro.hxx"
#include <sfx2/fcontnr.hxx>
#include "sfxlocal.hrc"
#include <sfx2/sfx.hrc>
#include "app.hrc"
#include <sfx2/templdlg.hxx>
#include <sfx2/module.hxx>
#include <sfx2/msgpool.hxx>
#include <sfx2/topfrm.hxx>
#include "openflag.hxx"
#include <sfx2/viewsh.hxx>
#include <sfx2/objface.hxx>
#include "helper.hxx"   // SfxContentHelper::Kill()

using namespace ::vos;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;

//===================================================================

SV_IMPL_PTRARR( SfxTbxCtrlFactArr_Impl, SfxTbxCtrlFactory* );
SV_IMPL_PTRARR( SfxStbCtrlFactArr_Impl, SfxStbCtrlFactory* );
SV_IMPL_PTRARR( SfxMenuCtrlFactArr_Impl, SfxMenuCtrlFactory* );
SV_IMPL_PTRARR( SfxChildWinFactArr_Impl, SfxChildWinFactory* );
SV_IMPL_PTRARR( SfxModuleArr_Impl, SfxModule* );

//===================================================================

#define SfxApplication
#include "sfxslots.hxx"

class SfxSpecialConfigError_Impl
{
    String aError;

public:

    SfxSpecialConfigError_Impl( const String& rStr );
    DECL_LINK( TimerHdl, Timer*);
};

SfxSpecialConfigError_Impl::SfxSpecialConfigError_Impl( const String& rStr ) :
    aError( rStr )
{
    Timer *pTimer = new Timer;
    pTimer->SetTimeoutHdl( LINK(this, SfxSpecialConfigError_Impl, TimerHdl) );
    pTimer->SetTimeout( 0 );
    pTimer->Start();
}

IMPL_LINK( SfxSpecialConfigError_Impl, TimerHdl, Timer*, pTimer )
{
    delete pTimer;
    ErrorBox( 0, WinBits( WB_OK ) , aError ).Execute();
    delete this;
    SFX_APP()->GetAppDispatcher_Impl()->Execute( SID_QUITAPP );
    return 0L;
}

//====================================================================

#define SFX_ITEMTYPE_STATBAR             4

SFX_IMPL_INTERFACE(SfxApplication,SfxShell,SfxResId(RID_DESKTOP))
{
    SFX_STATUSBAR_REGISTRATION(SfxResId(SFX_ITEMTYPE_STATBAR));
}

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

void SfxApplication::InitializeDisplayName_Impl()
{
    SfxAppData_Impl* pAppData = Get_Impl();
    if ( !pAppData->pLabelResMgr )
        return;

    String aTitle = Application::GetDisplayName();
    if ( !aTitle.Len() )
    {
        OClearableGuard aGuard( OMutex::getGlobalMutex() );

        // create version string
/*!!! (pb) don't show a version number at the moment
        USHORT nProductVersion = ProductVersion::GetVersion().ToInt32();
        String aVersion( String::CreateFromInt32( nProductVersion / 10 ) );
        aVersion += 0x002E ; // 2Eh ^= '.'
        aVersion += ( String::CreateFromInt32( nProductVersion % 10 ) );
*/
        // load application title
        aTitle = String( ResId( RID_APPTITLE, *pAppData->pLabelResMgr ) );
        // merge version into title
        aTitle.SearchAndReplaceAscii( "$(VER)", String() /*aVersion*/ );

        aGuard.clear();

#ifndef PRODUCT
        ::rtl::OUString aDefault;
        aTitle += DEFINE_CONST_UNICODE(" [");

        String aVerId( utl::Bootstrap::getBuildIdData( aDefault ));
        aTitle += aVerId;
        aTitle += ']';
#endif
        Application::SetDisplayName( aTitle );
    }
}

//--------------------------------------------------------------------
SfxProgress* SfxApplication::GetProgress() const

/*  [Beschreibung]

    Liefert den f"ur die gesamte Applikation laufenden SfxProgress
    oder 0, falls keiner f"ur die gesamte Applikation l"auft.

    [Querverweise]

    <SfxProgress::GetActiveProgress(SfxViewFrame*)>
    <SfxViewFrame::GetProgress()const>
*/

{
    return pAppData_Impl->pProgress;
}

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

SvUShorts* SfxApplication::GetDisabledSlotList_Impl()
{
    sal_Bool bError = sal_False;
    SvUShorts* pList = pAppData_Impl->pDisabledSlotList;
    if ( !pList )
    {
        // Gibt es eine Slotdatei ?
        INetURLObject aUserObj( SvtPathOptions().GetUserConfigPath() );
        aUserObj.insertName( DEFINE_CONST_UNICODE( "slots.cfg" ) );
        SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aUserObj.GetMainURL( INetURLObject::NO_DECODE ), STREAM_STD_READ );
        if ( !pStream || pStream->GetError() == ERRCODE_IO_NOTEXISTS )
        {
            delete pStream;
            INetURLObject aObj( SvtPathOptions().GetConfigPath() );
            aObj.insertName( DEFINE_CONST_UNICODE( "slots.cfg" ) );
            pStream = ::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::NO_DECODE ), STREAM_STD_READ );
        }

        BOOL bSlotsEnabled = SvtInternalOptions().SlotCFGEnabled();
        BOOL bSlots = ( pStream && !pStream->GetError() );
        if( bSlots && bSlotsEnabled )
        {
            // SlotDatei einlesen
            String aTitle;
            pStream->ReadByteString(aTitle);
            if ( aTitle.CompareToAscii("SfxSlotFile" ) == COMPARE_EQUAL )
            {
                sal_uInt16 nCount;
                (*pStream) >> nCount;
                pList = pAppData_Impl->pDisabledSlotList =
                        new SvUShorts( nCount < 255 ? (sal_Int8) nCount : 255, 255 );

                sal_uInt16 nSlot;
                for ( sal_uInt16 n=0; n<nCount; n++ )
                {
                    (*pStream) >> nSlot;
                    pList->Insert( nSlot, n );
                }

                pStream->ReadByteString(aTitle);
                if ( aTitle.CompareToAscii("END" ) != COMPARE_EQUAL || pStream->GetError() )
                {
                    // Lesen schief gegangen
                    DELETEZ( pList );
                    bError = sal_True;
                }
            }
            else
            {
                // Streamerkennung  fehlgeschlagen
                bError = sal_True;
            }
        }
        else if ( bSlots != bSlotsEnabled )
        {
            // Wenn kein Slotlist-Eintrag, dann darf auch keine SlotDatei
            // vorhanden sein
            bError = sal_True;
        }

        delete pStream;
    }
    else if ( pList == (SvUShorts*) -1L )
    {
        return NULL;
    }

    if ( !pList )
        pAppData_Impl->pDisabledSlotList = (SvUShorts*) -1L;

    if ( bError )
    {
        // Wenn ein Sloteintrag vorhanden ist, aber keine oder eine fehlerhafte
        // SlotDatei, oder aber eine Slotdatei, aber kein Sloteintrag, dann
        // gilt dies als fehlerhafte Konfiguration
        new SfxSpecialConfigError_Impl( String( SfxResId( RID_SPECIALCONFIG_ERROR ) ) );
    }

       return pList;
}

SfxModule* SfxApplication::GetModule_Impl()
{
    SfxModule* pModule = SfxModule::GetActiveModule();
    if ( !pModule )
        pModule = SfxModule::GetActiveModule( SfxViewFrame::GetFirst( FALSE ) );
    if( pModule )
        return pModule;
    else
    {
        DBG_ERROR( "No module!" );
        return NULL;
    }
}

ISfxTemplateCommon* SfxApplication::GetCurrentTemplateCommon( SfxBindings& rBindings )
{
    if( pAppData_Impl->pTemplateCommon )
        return pAppData_Impl->pTemplateCommon;
    SfxChildWindow *pChild = rBindings.GetWorkWindow_Impl()->GetChildWindow_Impl(
        SfxTemplateDialogWrapper::GetChildWindowId() );
    if ( pChild )
        return ((SfxTemplateDialog*) pChild->GetWindow())->GetISfxTemplateCommon();
    return 0;
}

SfxCancelManager* SfxApplication::GetCancelManager() const
{
    if ( !pAppData_Impl->pCancelMgr )
        pAppData_Impl->pCancelMgr = new SfxCancelManager;
    return pAppData_Impl->pCancelMgr;
}

SfxResourceManager& SfxApplication::GetResourceManager() const { return *pAppData_Impl->pResMgr; }
BOOL  SfxApplication::IsDowning() const { return pAppData_Impl->bDowning; }
SfxDispatcher* SfxApplication::GetAppDispatcher_Impl() { return pAppData_Impl->pAppDispat; }
SfxSlotPool& SfxApplication::GetAppSlotPool_Impl() const { return *pAppData_Impl->pSlotPool; }
//SfxOptions&  SfxApplication::GetOptions() { return *pAppData_Impl->pOptions; }
//const SfxOptions& SfxApplication::GetOptions() const { return *pAppData_Impl->pOptions; }

<commit_msg>INTEGRATION: CWS changefileheader (1.57.216); FILE MERGED 2008/04/01 15:38:41 thb 1.57.216.3: #i85898# Stripping all external header guards 2008/04/01 12:40:39 thb 1.57.216.2: #i85898# Stripping all external header guards 2008/03/31 13:38:00 rt 1.57.216.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: appmisc.cxx,v $
 * $Revision: 1.58 $
 *
 * 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_sfx2.hxx"
#include <vcl/status.hxx>
#include <vcl/msgbox.hxx>
#ifndef _VOS_PROCESS_HXX //autogen
#include <vos/process.hxx>
#endif
#include <vos/xception.hxx>
#include <svtools/whiter.hxx>
#include <svtools/stritem.hxx>
#include <svtools/intitem.hxx>
#include <svtools/eitem.hxx>
#include <svtools/filter.hxx>
#include <svtools/internaloptions.hxx>
#include <svtools/pathoptions.hxx>
#include <com/sun/star/registry/InvalidRegistryException.hpp>
#ifndef _COM_SUN_STAR_BEANS_PropertyValue_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif
#include <com/sun/star/frame/XFrame.hpp>
#include <com/sun/star/util/XURLTransformer.hpp>
#include <com/sun/star/frame/XFramesSupplier.hpp>
#include <com/sun/star/uno/Reference.h>
#include <tools/config.hxx>
#include <tools/rcid.h>
#include <vos/mutex.hxx>
#ifndef GCC
#endif
#include <unotools/configmgr.hxx>
#include <com/sun/star/frame/XDesktop.hpp>

#include <unotools/ucbstreamhelper.hxx>
#include <framework/menuconfiguration.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/localfilehelper.hxx>
#include <unotools/bootstrap.hxx>
#include <svtools/moduleoptions.hxx>
#include <osl/file.hxx>

#include "sfxresid.hxx"
#include <sfx2/app.hxx>
#include "appdata.hxx"
#include "arrdecl.hxx"
#include <sfx2/tbxctrl.hxx>
#include "stbitem.hxx"
#include <sfx2/mnuitem.hxx>
#include <sfx2/docfac.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/request.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/dispatch.hxx>
#include "workwin.hxx"
#include "intro.hxx"
#include <sfx2/fcontnr.hxx>
#include "sfxlocal.hrc"
#include <sfx2/sfx.hrc>
#include "app.hrc"
#include <sfx2/templdlg.hxx>
#include <sfx2/module.hxx>
#include <sfx2/msgpool.hxx>
#include <sfx2/topfrm.hxx>
#include "openflag.hxx"
#include <sfx2/viewsh.hxx>
#include <sfx2/objface.hxx>
#include "helper.hxx"   // SfxContentHelper::Kill()

using namespace ::vos;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;

//===================================================================

SV_IMPL_PTRARR( SfxTbxCtrlFactArr_Impl, SfxTbxCtrlFactory* );
SV_IMPL_PTRARR( SfxStbCtrlFactArr_Impl, SfxStbCtrlFactory* );
SV_IMPL_PTRARR( SfxMenuCtrlFactArr_Impl, SfxMenuCtrlFactory* );
SV_IMPL_PTRARR( SfxChildWinFactArr_Impl, SfxChildWinFactory* );
SV_IMPL_PTRARR( SfxModuleArr_Impl, SfxModule* );

//===================================================================

#define SfxApplication
#include "sfxslots.hxx"

class SfxSpecialConfigError_Impl
{
    String aError;

public:

    SfxSpecialConfigError_Impl( const String& rStr );
    DECL_LINK( TimerHdl, Timer*);
};

SfxSpecialConfigError_Impl::SfxSpecialConfigError_Impl( const String& rStr ) :
    aError( rStr )
{
    Timer *pTimer = new Timer;
    pTimer->SetTimeoutHdl( LINK(this, SfxSpecialConfigError_Impl, TimerHdl) );
    pTimer->SetTimeout( 0 );
    pTimer->Start();
}

IMPL_LINK( SfxSpecialConfigError_Impl, TimerHdl, Timer*, pTimer )
{
    delete pTimer;
    ErrorBox( 0, WinBits( WB_OK ) , aError ).Execute();
    delete this;
    SFX_APP()->GetAppDispatcher_Impl()->Execute( SID_QUITAPP );
    return 0L;
}

//====================================================================

#define SFX_ITEMTYPE_STATBAR             4

SFX_IMPL_INTERFACE(SfxApplication,SfxShell,SfxResId(RID_DESKTOP))
{
    SFX_STATUSBAR_REGISTRATION(SfxResId(SFX_ITEMTYPE_STATBAR));
}

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

void SfxApplication::InitializeDisplayName_Impl()
{
    SfxAppData_Impl* pAppData = Get_Impl();
    if ( !pAppData->pLabelResMgr )
        return;

    String aTitle = Application::GetDisplayName();
    if ( !aTitle.Len() )
    {
        OClearableGuard aGuard( OMutex::getGlobalMutex() );

        // create version string
/*!!! (pb) don't show a version number at the moment
        USHORT nProductVersion = ProductVersion::GetVersion().ToInt32();
        String aVersion( String::CreateFromInt32( nProductVersion / 10 ) );
        aVersion += 0x002E ; // 2Eh ^= '.'
        aVersion += ( String::CreateFromInt32( nProductVersion % 10 ) );
*/
        // load application title
        aTitle = String( ResId( RID_APPTITLE, *pAppData->pLabelResMgr ) );
        // merge version into title
        aTitle.SearchAndReplaceAscii( "$(VER)", String() /*aVersion*/ );

        aGuard.clear();

#ifndef PRODUCT
        ::rtl::OUString aDefault;
        aTitle += DEFINE_CONST_UNICODE(" [");

        String aVerId( utl::Bootstrap::getBuildIdData( aDefault ));
        aTitle += aVerId;
        aTitle += ']';
#endif
        Application::SetDisplayName( aTitle );
    }
}

//--------------------------------------------------------------------
SfxProgress* SfxApplication::GetProgress() const

/*  [Beschreibung]

    Liefert den f"ur die gesamte Applikation laufenden SfxProgress
    oder 0, falls keiner f"ur die gesamte Applikation l"auft.

    [Querverweise]

    <SfxProgress::GetActiveProgress(SfxViewFrame*)>
    <SfxViewFrame::GetProgress()const>
*/

{
    return pAppData_Impl->pProgress;
}

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

SvUShorts* SfxApplication::GetDisabledSlotList_Impl()
{
    sal_Bool bError = sal_False;
    SvUShorts* pList = pAppData_Impl->pDisabledSlotList;
    if ( !pList )
    {
        // Gibt es eine Slotdatei ?
        INetURLObject aUserObj( SvtPathOptions().GetUserConfigPath() );
        aUserObj.insertName( DEFINE_CONST_UNICODE( "slots.cfg" ) );
        SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aUserObj.GetMainURL( INetURLObject::NO_DECODE ), STREAM_STD_READ );
        if ( !pStream || pStream->GetError() == ERRCODE_IO_NOTEXISTS )
        {
            delete pStream;
            INetURLObject aObj( SvtPathOptions().GetConfigPath() );
            aObj.insertName( DEFINE_CONST_UNICODE( "slots.cfg" ) );
            pStream = ::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::NO_DECODE ), STREAM_STD_READ );
        }

        BOOL bSlotsEnabled = SvtInternalOptions().SlotCFGEnabled();
        BOOL bSlots = ( pStream && !pStream->GetError() );
        if( bSlots && bSlotsEnabled )
        {
            // SlotDatei einlesen
            String aTitle;
            pStream->ReadByteString(aTitle);
            if ( aTitle.CompareToAscii("SfxSlotFile" ) == COMPARE_EQUAL )
            {
                sal_uInt16 nCount;
                (*pStream) >> nCount;
                pList = pAppData_Impl->pDisabledSlotList =
                        new SvUShorts( nCount < 255 ? (sal_Int8) nCount : 255, 255 );

                sal_uInt16 nSlot;
                for ( sal_uInt16 n=0; n<nCount; n++ )
                {
                    (*pStream) >> nSlot;
                    pList->Insert( nSlot, n );
                }

                pStream->ReadByteString(aTitle);
                if ( aTitle.CompareToAscii("END" ) != COMPARE_EQUAL || pStream->GetError() )
                {
                    // Lesen schief gegangen
                    DELETEZ( pList );
                    bError = sal_True;
                }
            }
            else
            {
                // Streamerkennung  fehlgeschlagen
                bError = sal_True;
            }
        }
        else if ( bSlots != bSlotsEnabled )
        {
            // Wenn kein Slotlist-Eintrag, dann darf auch keine SlotDatei
            // vorhanden sein
            bError = sal_True;
        }

        delete pStream;
    }
    else if ( pList == (SvUShorts*) -1L )
    {
        return NULL;
    }

    if ( !pList )
        pAppData_Impl->pDisabledSlotList = (SvUShorts*) -1L;

    if ( bError )
    {
        // Wenn ein Sloteintrag vorhanden ist, aber keine oder eine fehlerhafte
        // SlotDatei, oder aber eine Slotdatei, aber kein Sloteintrag, dann
        // gilt dies als fehlerhafte Konfiguration
        new SfxSpecialConfigError_Impl( String( SfxResId( RID_SPECIALCONFIG_ERROR ) ) );
    }

       return pList;
}

SfxModule* SfxApplication::GetModule_Impl()
{
    SfxModule* pModule = SfxModule::GetActiveModule();
    if ( !pModule )
        pModule = SfxModule::GetActiveModule( SfxViewFrame::GetFirst( FALSE ) );
    if( pModule )
        return pModule;
    else
    {
        DBG_ERROR( "No module!" );
        return NULL;
    }
}

ISfxTemplateCommon* SfxApplication::GetCurrentTemplateCommon( SfxBindings& rBindings )
{
    if( pAppData_Impl->pTemplateCommon )
        return pAppData_Impl->pTemplateCommon;
    SfxChildWindow *pChild = rBindings.GetWorkWindow_Impl()->GetChildWindow_Impl(
        SfxTemplateDialogWrapper::GetChildWindowId() );
    if ( pChild )
        return ((SfxTemplateDialog*) pChild->GetWindow())->GetISfxTemplateCommon();
    return 0;
}

SfxCancelManager* SfxApplication::GetCancelManager() const
{
    if ( !pAppData_Impl->pCancelMgr )
        pAppData_Impl->pCancelMgr = new SfxCancelManager;
    return pAppData_Impl->pCancelMgr;
}

SfxResourceManager& SfxApplication::GetResourceManager() const { return *pAppData_Impl->pResMgr; }
BOOL  SfxApplication::IsDowning() const { return pAppData_Impl->bDowning; }
SfxDispatcher* SfxApplication::GetAppDispatcher_Impl() { return pAppData_Impl->pAppDispat; }
SfxSlotPool& SfxApplication::GetAppSlotPool_Impl() const { return *pAppData_Impl->pSlotPool; }
//SfxOptions&  SfxApplication::GetOptions() { return *pAppData_Impl->pOptions; }
//const SfxOptions& SfxApplication::GetOptions() const { return *pAppData_Impl->pOptions; }

<|endoftext|>


<commit_before><commit_msg>fdo#58370 - 'Send Feedback...' URL invalid in other languages then English<commit_after><|endoftext|>


<commit_before>#include "narf/version.h"
#include "narf/bytestream.h"
#include "narf/cursesconsole.h"
#include "narf/gameloop.h"
#include "narf/playercmd.h"
#include "narf/world.h"
#include "narf/cmd/cmd.h"
#include "narf/util/path.h"
#include "narf/net/net.h"

#include <chrono>

#include <enet/enet.h>

#include <string.h>

narf::CursesConsole *cursesConsole;

// TODO: put this somewhere else
class Client {
public:

	Client() : peer(nullptr) {
	}

	ENetPeer* peer;
};

class ServerGameLoop : public narf::GameLoop {
public:
	ServerGameLoop(double maxFrameTime, double tickRate, size_t maxClients);
	~ServerGameLoop();

	void tick(narf::timediff dt) override;
	void updateStatus(const std::string& status) override;
	void draw(float stateBlend) override;

	void processConnect(ENetEvent& evt);
	void processDisconnect(ENetEvent& evt);
	void processChat(ENetEvent& evt, Client* client);
	void processPlayerCommand(ENetEvent& evt, Client* client);
	void processReceive(ENetEvent& evt);
	void processNetEvent(ENetEvent& evt);

	ENetHost* server;
	size_t maxClients;
	Client* clients;
};

ServerGameLoop* game;

narf::World *world;

// TODO: move these
#define WORLD_X_MAX 64
#define WORLD_Y_MAX 64
#define WORLD_Z_MAX 64

// TODO: this is copied from client
narf::BlockType genNormalBlockType() {
	narf::BlockType bt;
	bt.solid = true;
	bt.indestructible = false;
	return bt;
}

// TODO: this is copied from client
void genWorld() {
	world = new narf::World(WORLD_X_MAX, WORLD_Y_MAX, WORLD_Z_MAX, 16, 16, 16);

	// set up block types
	// TODO: put this in a config file
	auto airType = genNormalBlockType(); // TODO
	airType.solid = false;
	world->addBlockType(airType); // air

	auto adminiumType = genNormalBlockType();
	adminiumType.indestructible = true;
	world->addBlockType(adminiumType); // adminium

	world->addBlockType(genNormalBlockType()); // dirt
	world->addBlockType(genNormalBlockType()); // dirt with grass top
	world->addBlockType(genNormalBlockType()); // TODO
	world->addBlockType(genNormalBlockType()); // brick
	world->addBlockType(genNormalBlockType()); // stone1
	auto stone2 = world->addBlockType(genNormalBlockType()); // stone2
	world->addBlockType(genNormalBlockType()); // stone3

	world->set_gravity(-24.0f);
}

void cmdQuit(const std::string &args) {
	narf::console->println("Quitting in response to user command");
	game->quit = true;
}

void tell(const Client* to, const Client* from, const std::string& text) {
	// TODO: use client nickname here
	std::string fromName = from ? narf::net::to_string(from->peer->address) : "server";
	std::string packetData("<" + fromName + "> " + text);
	auto packet = enet_packet_create(packetData.c_str(), packetData.length(), ENET_PACKET_FLAG_RELIABLE);
	enet_peer_send(to->peer, narf::net::CHAN_CHAT, packet);
}

void tellAll(const Client* from, const std::string& text) {
	for (size_t i = 0; i < game->maxClients; i++) {
		auto client = &game->clients[i];
		if (client->peer) {
			tell(client, from, text);
		}
	}
}

void sendChunkUpdate(const Client* to, const narf::World::ChunkCoord& wcc, bool dirtyOnly) {
	auto chunk = world->get_chunk(wcc);
	if (!dirtyOnly || chunk->dirty()) {
		narf::ByteStreamWriter bs;
		world->serializeChunk(bs, wcc);
		auto packet = enet_packet_create(bs.data(), bs.size(), ENET_PACKET_FLAG_RELIABLE);
		enet_peer_send(to->peer, narf::net::CHAN_CHUNK, packet);
	}
}

void markChunksClean() {
	narf::math::coord::ZYXCoordIter<narf::World::ChunkCoord> iter({ 0, 0, 0 }, { world->chunks_x(), world->chunks_y(), world->chunks_z() });
	for (const auto& wcc : iter) {
		world->get_chunk(wcc)->markClean();
	}
}

ServerGameLoop::ServerGameLoop(double maxFrameTime, double tickRate, size_t maxClients) :
	narf::GameLoop(maxFrameTime, tickRate),
	maxClients(maxClients) {

	clients = new Client[maxClients];
	if (!clients) {
		return;
	}

	ENetAddress bindAddress;
	bindAddress.host = ENET_HOST_ANY;
	bindAddress.port = narf::net::DEFAULT_PORT;

	narf::console->println("Binding to " + narf::net::to_string(bindAddress));
	server = enet_host_create(&bindAddress, maxClients, narf::net::MAX_CHANNELS, 0, 0);
	if (server == nullptr) {
		narf::console->println("Could not bind to " + narf::net::to_string(bindAddress));
	}
}

ServerGameLoop::~ServerGameLoop() {
	if (server) {
		enet_host_destroy(server);
	}
	enet_deinitialize();
	if (clients) {
		delete[] clients;
	}
}

void ServerGameLoop::processConnect(ENetEvent& evt) {
	narf::console->println("Client connected from " + narf::net::to_string(evt.peer->address));
	// add the client to list of connected clients
	// find an unused client
	Client* client = nullptr;
	for (unsigned i = 0; i < maxClients; i++) {
		if (!clients[i].peer) {
			client = &clients[i];
			break;
		}
	}

	if (client == nullptr) {
		// TODO!!!!
		narf::console->println("ERROR: No client slots available");
		enet_peer_reset(evt.peer);
		return;
	}

	client->peer = evt.peer;

	// store Client pointer in peer data
	evt.peer->data = client;

	// send a server message greeting
	tellAll(nullptr, "Client connected from " + narf::net::to_string(evt.peer->address));

	// send all chunks (!!)
	narf::math::coord::ZYXCoordIter<narf::World::ChunkCoord> iter({ 0, 0, 0 }, { world->chunks_x(), world->chunks_y(), world->chunks_z() });
	for (const auto& wcc : iter) {
		sendChunkUpdate(client, wcc, false);
	}
}

void ServerGameLoop::processDisconnect(ENetEvent& evt) {
	auto client = static_cast<Client*>(evt.peer->data);
	auto disconnectType = static_cast<narf::net::DisconnectType>(evt.data);
	std::string reason;
	switch (disconnectType) {
	case narf::net::DisconnectType::Timeout:
		reason = "timed out";
		break;
	case narf::net::DisconnectType::UserQuit:
		reason = "user quit";
		break;
	default:
		reason = "unknown";
		break;
	}

	std::string disconnectMsg = "Client disconnected from " + narf::net::to_string(evt.peer->address) + " (" + reason + ")";
	client->peer = nullptr;
	evt.peer->data = nullptr;

	narf::console->println(disconnectMsg);
	tellAll(nullptr, disconnectMsg);
}

void ServerGameLoop::processChat(ENetEvent& evt, Client* client) {
	std::string text((char*)evt.packet->data, evt.packet->dataLength);
	narf::console->println("Chat: " + text);
	// send the chat out to all clients
	tellAll(client, text);
}

void ServerGameLoop::processPlayerCommand(ENetEvent& evt, Client* client) {
	narf::ByteStreamReader bs(evt.packet->data, evt.packet->dataLength);
	narf::PlayerCommand cmd(bs);
	cmd.exec(world);
}

void ServerGameLoop::processReceive(ENetEvent& evt) {
	auto client = static_cast<Client*>(evt.peer->data);
	switch (evt.channelID) {
	case narf::net::CHAN_CHAT:
		processChat(evt, client);
		break;
	case narf::net::CHAN_PLAYERCMD:
		processPlayerCommand(evt, client);
		break;
	default:
		narf::console->println("Got unexpected packet from " + narf::net::to_string(evt.peer->address) + " channel " + std::to_string(evt.channelID) + " size " + std::to_string(evt.packet->dataLength));
		break;
	}
}

void ServerGameLoop::processNetEvent(ENetEvent& evt) {
	switch (evt.type) {
	case ENET_EVENT_TYPE_CONNECT:
		processConnect(evt);
		break;
	case ENET_EVENT_TYPE_DISCONNECT:
		processDisconnect(evt);
		break;
	case ENET_EVENT_TYPE_RECEIVE:
		processReceive(evt);
		break;
	case ENET_EVENT_TYPE_NONE:
		// make the compiler shut up about unhandled enum value
		break;
	}
}

void ServerGameLoop::tick(narf::timediff dt) {
	// check for console input
	auto input = narf::console->pollInput();
	if (input != "") {
		if (input[0] == '/') { // commands begin with slash
			narf::cmd::exec(input.substr(1));
		}
	}
	ENetEvent evt;
	if (enet_host_service(server, &evt, 0) > 0) {
		processNetEvent(evt);
	}

	world->update(dt);

	// send chunk updates to all clients
	for (size_t i = 0; i < maxClients; i++) {
		auto client = &clients[i];
		if (client->peer) {
			narf::math::coord::ZYXCoordIter<narf::World::ChunkCoord> iter({ 0, 0, 0 }, { world->chunks_x(), world->chunks_y(), world->chunks_z() });
			for (const auto& wcc : iter) {
				sendChunkUpdate(client, wcc, true);
			}
		}
	}
	markChunksClean();
}

void ServerGameLoop::updateStatus(const std::string& status) {
	cursesConsole->setStatus(status);
}

void ServerGameLoop::draw(float stateBlend) {
}

int main(int argc, char **argv)
{
	cursesConsole = new narf::CursesConsole();
	narf::console = cursesConsole;

	narf::console->println("Hello, world - I'm a server.");
	narf::console->println("Version: " + std::to_string(VERSION_MAJOR) + "." + std::to_string(VERSION_MINOR) + std::string(VERSION_RELEASE) + "+" VERSION_REV);

	if (enet_initialize() != 0) {
		narf::console->println("Error initializing ENet");
		return 1;
	}

	narf::console->println("Executable filename:  " + narf::util::exeName());
	narf::console->println("Executable directory: " + narf::util::exeDir());
	narf::console->println("Data directory: " + narf::util::dataDir());
	narf::console->println("Type /quit to quit.");

	narf::cmd::cmds["quit"] = cmdQuit;

	genWorld();

	// TODO: make tick rate and max clients configurable
	game = new ServerGameLoop(0.25, 60.0, 32);
	game->callDraw = false;
	game->run();
	delete game;
	delete narf::console;
	return 0;
}
<commit_msg>server: format chat the same way as the client<commit_after>#include "narf/version.h"
#include "narf/bytestream.h"
#include "narf/cursesconsole.h"
#include "narf/gameloop.h"
#include "narf/playercmd.h"
#include "narf/world.h"
#include "narf/cmd/cmd.h"
#include "narf/util/path.h"
#include "narf/net/net.h"

#include <chrono>

#include <enet/enet.h>

#include <string.h>

narf::CursesConsole *cursesConsole;

// TODO: put this somewhere else
class Client {
public:

	Client() : peer(nullptr) {
	}

	ENetPeer* peer;
};

class ServerGameLoop : public narf::GameLoop {
public:
	ServerGameLoop(double maxFrameTime, double tickRate, size_t maxClients);
	~ServerGameLoop();

	void tick(narf::timediff dt) override;
	void updateStatus(const std::string& status) override;
	void draw(float stateBlend) override;

	void processConnect(ENetEvent& evt);
	void processDisconnect(ENetEvent& evt);
	void processChat(ENetEvent& evt, Client* client);
	void processPlayerCommand(ENetEvent& evt, Client* client);
	void processReceive(ENetEvent& evt);
	void processNetEvent(ENetEvent& evt);

	ENetHost* server;
	size_t maxClients;
	Client* clients;
};

ServerGameLoop* game;

narf::World *world;

// TODO: move these
#define WORLD_X_MAX 64
#define WORLD_Y_MAX 64
#define WORLD_Z_MAX 64

// TODO: this is copied from client
narf::BlockType genNormalBlockType() {
	narf::BlockType bt;
	bt.solid = true;
	bt.indestructible = false;
	return bt;
}

// TODO: this is copied from client
void genWorld() {
	world = new narf::World(WORLD_X_MAX, WORLD_Y_MAX, WORLD_Z_MAX, 16, 16, 16);

	// set up block types
	// TODO: put this in a config file
	auto airType = genNormalBlockType(); // TODO
	airType.solid = false;
	world->addBlockType(airType); // air

	auto adminiumType = genNormalBlockType();
	adminiumType.indestructible = true;
	world->addBlockType(adminiumType); // adminium

	world->addBlockType(genNormalBlockType()); // dirt
	world->addBlockType(genNormalBlockType()); // dirt with grass top
	world->addBlockType(genNormalBlockType()); // TODO
	world->addBlockType(genNormalBlockType()); // brick
	world->addBlockType(genNormalBlockType()); // stone1
	auto stone2 = world->addBlockType(genNormalBlockType()); // stone2
	world->addBlockType(genNormalBlockType()); // stone3

	world->set_gravity(-24.0f);
}

void cmdQuit(const std::string &args) {
	narf::console->println("Quitting in response to user command");
	game->quit = true;
}

std::string formatChat(const Client* from, const std::string& text) {
	// TODO: use client nickname here
	std::string fromName = from ? narf::net::to_string(from->peer->address) : "server";
	return "<" + fromName + "> " + text;
}

void tell(const Client* to, const Client* from, const std::string& text) {
	std::string packetData(formatChat(from, text));
	auto packet = enet_packet_create(packetData.c_str(), packetData.length(), ENET_PACKET_FLAG_RELIABLE);
	enet_peer_send(to->peer, narf::net::CHAN_CHAT, packet);
}

void tellAll(const Client* from, const std::string& text) {
	for (size_t i = 0; i < game->maxClients; i++) {
		auto client = &game->clients[i];
		if (client->peer) {
			tell(client, from, text);
		}
	}
}

void sendChunkUpdate(const Client* to, const narf::World::ChunkCoord& wcc, bool dirtyOnly) {
	auto chunk = world->get_chunk(wcc);
	if (!dirtyOnly || chunk->dirty()) {
		narf::ByteStreamWriter bs;
		world->serializeChunk(bs, wcc);
		auto packet = enet_packet_create(bs.data(), bs.size(), ENET_PACKET_FLAG_RELIABLE);
		enet_peer_send(to->peer, narf::net::CHAN_CHUNK, packet);
	}
}

void markChunksClean() {
	narf::math::coord::ZYXCoordIter<narf::World::ChunkCoord> iter({ 0, 0, 0 }, { world->chunks_x(), world->chunks_y(), world->chunks_z() });
	for (const auto& wcc : iter) {
		world->get_chunk(wcc)->markClean();
	}
}

ServerGameLoop::ServerGameLoop(double maxFrameTime, double tickRate, size_t maxClients) :
	narf::GameLoop(maxFrameTime, tickRate),
	maxClients(maxClients) {

	clients = new Client[maxClients];
	if (!clients) {
		return;
	}

	ENetAddress bindAddress;
	bindAddress.host = ENET_HOST_ANY;
	bindAddress.port = narf::net::DEFAULT_PORT;

	narf::console->println("Binding to " + narf::net::to_string(bindAddress));
	server = enet_host_create(&bindAddress, maxClients, narf::net::MAX_CHANNELS, 0, 0);
	if (server == nullptr) {
		narf::console->println("Could not bind to " + narf::net::to_string(bindAddress));
	}
}

ServerGameLoop::~ServerGameLoop() {
	if (server) {
		enet_host_destroy(server);
	}
	enet_deinitialize();
	if (clients) {
		delete[] clients;
	}
}

void ServerGameLoop::processConnect(ENetEvent& evt) {
	narf::console->println("Client connected from " + narf::net::to_string(evt.peer->address));
	// add the client to list of connected clients
	// find an unused client
	Client* client = nullptr;
	for (unsigned i = 0; i < maxClients; i++) {
		if (!clients[i].peer) {
			client = &clients[i];
			break;
		}
	}

	if (client == nullptr) {
		// TODO!!!!
		narf::console->println("ERROR: No client slots available");
		enet_peer_reset(evt.peer);
		return;
	}

	client->peer = evt.peer;

	// store Client pointer in peer data
	evt.peer->data = client;

	// send a server message greeting
	tellAll(nullptr, "Client connected from " + narf::net::to_string(evt.peer->address));

	// send all chunks (!!)
	narf::math::coord::ZYXCoordIter<narf::World::ChunkCoord> iter({ 0, 0, 0 }, { world->chunks_x(), world->chunks_y(), world->chunks_z() });
	for (const auto& wcc : iter) {
		sendChunkUpdate(client, wcc, false);
	}
}

void ServerGameLoop::processDisconnect(ENetEvent& evt) {
	auto client = static_cast<Client*>(evt.peer->data);
	auto disconnectType = static_cast<narf::net::DisconnectType>(evt.data);
	std::string reason;
	switch (disconnectType) {
	case narf::net::DisconnectType::Timeout:
		reason = "timed out";
		break;
	case narf::net::DisconnectType::UserQuit:
		reason = "user quit";
		break;
	default:
		reason = "unknown";
		break;
	}

	std::string disconnectMsg = "Client disconnected from " + narf::net::to_string(evt.peer->address) + " (" + reason + ")";
	client->peer = nullptr;
	evt.peer->data = nullptr;

	narf::console->println(disconnectMsg);
	tellAll(nullptr, disconnectMsg);
}

void ServerGameLoop::processChat(ENetEvent& evt, Client* client) {
	std::string text((char*)evt.packet->data, evt.packet->dataLength);
	narf::console->println(formatChat(client, text));
	// send the chat out to all clients
	tellAll(client, text);
}

void ServerGameLoop::processPlayerCommand(ENetEvent& evt, Client* client) {
	narf::ByteStreamReader bs(evt.packet->data, evt.packet->dataLength);
	narf::PlayerCommand cmd(bs);
	cmd.exec(world);
}

void ServerGameLoop::processReceive(ENetEvent& evt) {
	auto client = static_cast<Client*>(evt.peer->data);
	switch (evt.channelID) {
	case narf::net::CHAN_CHAT:
		processChat(evt, client);
		break;
	case narf::net::CHAN_PLAYERCMD:
		processPlayerCommand(evt, client);
		break;
	default:
		narf::console->println("Got unexpected packet from " + narf::net::to_string(evt.peer->address) + " channel " + std::to_string(evt.channelID) + " size " + std::to_string(evt.packet->dataLength));
		break;
	}
}

void ServerGameLoop::processNetEvent(ENetEvent& evt) {
	switch (evt.type) {
	case ENET_EVENT_TYPE_CONNECT:
		processConnect(evt);
		break;
	case ENET_EVENT_TYPE_DISCONNECT:
		processDisconnect(evt);
		break;
	case ENET_EVENT_TYPE_RECEIVE:
		processReceive(evt);
		break;
	case ENET_EVENT_TYPE_NONE:
		// make the compiler shut up about unhandled enum value
		break;
	}
}

void ServerGameLoop::tick(narf::timediff dt) {
	// check for console input
	auto input = narf::console->pollInput();
	if (input != "") {
		if (input[0] == '/') { // commands begin with slash
			narf::cmd::exec(input.substr(1));
		} else {
			narf::console->println(formatChat(nullptr, input));
			tellAll(nullptr, input);
		}
	}
	ENetEvent evt;
	if (enet_host_service(server, &evt, 0) > 0) {
		processNetEvent(evt);
	}

	world->update(dt);

	// send chunk updates to all clients
	for (size_t i = 0; i < maxClients; i++) {
		auto client = &clients[i];
		if (client->peer) {
			narf::math::coord::ZYXCoordIter<narf::World::ChunkCoord> iter({ 0, 0, 0 }, { world->chunks_x(), world->chunks_y(), world->chunks_z() });
			for (const auto& wcc : iter) {
				sendChunkUpdate(client, wcc, true);
			}
		}
	}
	markChunksClean();
}

void ServerGameLoop::updateStatus(const std::string& status) {
	cursesConsole->setStatus(status);
}

void ServerGameLoop::draw(float stateBlend) {
}

int main(int argc, char **argv)
{
	cursesConsole = new narf::CursesConsole();
	narf::console = cursesConsole;

	narf::console->println("Hello, world - I'm a server.");
	narf::console->println("Version: " + std::to_string(VERSION_MAJOR) + "." + std::to_string(VERSION_MINOR) + std::string(VERSION_RELEASE) + "+" VERSION_REV);

	if (enet_initialize() != 0) {
		narf::console->println("Error initializing ENet");
		return 1;
	}

	narf::console->println("Executable filename:  " + narf::util::exeName());
	narf::console->println("Executable directory: " + narf::util::exeDir());
	narf::console->println("Data directory: " + narf::util::dataDir());
	narf::console->println("Type /quit to quit.");

	narf::cmd::cmds["quit"] = cmdQuit;

	genWorld();

	// TODO: make tick rate and max clients configurable
	game = new ServerGameLoop(0.25, 60.0, 32);
	game->callDraw = false;
	game->run();
	delete game;
	delete narf::console;
	return 0;
}
<|endoftext|>


<commit_before>#include <yuni/yuni.h>
#include <yuni/string.h>
#include <nany/nany.h>
#include <iostream>
#include <cassert>

using namespace Yuni;

static int printNoInputScript(const char* argv0)
#include <iostream>
{
	std::cerr << argv0 << ": no input script file\n";
	return EXIT_FAILURE;
}

static int printUsage(const char* const argv0)
{
	std::cout
		<< "Usage: " << argv0 << " [options] file...\n"
		<< "Options:\n"
		<< "  --bugreport       Display some useful information to report a bug\n"
		<< "                    (https://github.com/nany-lang/nany/issues/new)\n"
		<< "  --help, -h        Display this information\n"
		<< "  --version, -v     Print the version\n\n";
	return EXIT_SUCCESS;
}

static int printBugReportInfo()
{
	nylib_print_info_for_bugreport();
	return EXIT_SUCCESS;
}

static int printVersion()
{
	std::cout << nylib_version() << '\n';
	return EXIT_SUCCESS;
}

static int unknownOption(const char* argv0, const AnyString& name)
{
	std::cerr << argv0 << ": unknown option '" << name << "'\n";
	return EXIT_FAILURE;
}

static void on_error_file_eacces(const nyproject_t*, nybuild_t*, const char* file, uint32_t length)
{
	std::cerr << "error: failed to access to '";
	std::cerr << AnyString{file, length} << "'\n";
}

int main(int argc, const char** argv)
{
	const char* const argv0 = argv[0];

	if (argc > 1)
	{
		nyrun_cf_t runcf;
		nyrun_cf_init(&runcf);

		int firstarg = argc; // end of the list

		for (int i = 1; i < argc; ++i)
		{
			const char* const carg = argv[i];
			if (carg[0] == '-')
			{
				if (carg[1] == '-')
				{
					if (carg[2] != '\0') // to handle '--' option
					{
						AnyString arg{carg};

						if (arg == "--help")
							return printUsage(argv[0]);
						if (arg == "--version")
							return printVersion();
						if (arg == "--bugreport")
							return printBugReportInfo();
						if (arg == "--verbose")
						{
							runcf.verbose = nytrue;
							continue;
						}
						return unknownOption(argv0, arg);
					}
					else
					{
						// nothing must interpreted after '--'
						firstarg = i + 1;
						break;
					}
				}
				else
				{
					AnyString arg{carg};
					if (arg == "-h")
						return printUsage(argv[0]);
					if (arg == "-v")
						return printVersion();
					return unknownOption(argv0, arg);
				}
			}

			firstarg = i;
			break;
		}

		//
		// -- execute the script
		//
		int exitstatus = -1;
		if (firstarg < argc)
		{
			// callbacks
			runcf.build.on_error_file_eacces = &on_error_file_eacces;

			// the new arguments, after removing all command line arguments
			int nargc = argc - firstarg;
			const char** nargv = argv + firstarg;
			// the nany sript to load, which should be the first new argument
			const char* nargv0 = nargv[0];

			--nargc;
			uint32_t pargc = (nargc > 0) ? static_cast<uint32_t>(nargc) : 0;
			const char** pargv = (!pargc ? nullptr : (++nargv));

			exitstatus = nyrun_file_n(&runcf, nargv0, strlen(nargv0), pargc, pargv);
		}

		nyrun_cf_release(&runcf);
		return exitstatus;
	}

	return printNoInputScript(argv0);
}
<commit_msg>nany: remove spurious include in the middle of the code<commit_after>#include <yuni/yuni.h>
#include <yuni/string.h>
#include <nany/nany.h>
#include <iostream>
#include <cassert>

using namespace Yuni;

static int printNoInputScript(const char* argv0)
{
	std::cerr << argv0 << ": no input script file\n";
	return EXIT_FAILURE;
}

static int printUsage(const char* const argv0)
{
	std::cout
		<< "Usage: " << argv0 << " [options] file...\n"
		<< "Options:\n"
		<< "  --bugreport       Display some useful information to report a bug\n"
		<< "                    (https://github.com/nany-lang/nany/issues/new)\n"
		<< "  --help, -h        Display this information\n"
		<< "  --version, -v     Print the version\n\n";
	return EXIT_SUCCESS;
}

static int printBugReportInfo()
{
	nylib_print_info_for_bugreport();
	return EXIT_SUCCESS;
}

static int printVersion()
{
	std::cout << nylib_version() << '\n';
	return EXIT_SUCCESS;
}

static int unknownOption(const char* argv0, const AnyString& name)
{
	std::cerr << argv0 << ": unknown option '" << name << "'\n";
	return EXIT_FAILURE;
}

static void on_error_file_eacces(const nyproject_t*, nybuild_t*, const char* file, uint32_t length)
{
	std::cerr << "error: failed to access to '";
	std::cerr << AnyString{file, length} << "'\n";
}

int main(int argc, const char** argv)
{
	const char* const argv0 = argv[0];

	if (argc > 1)
	{
		nyrun_cf_t runcf;
		nyrun_cf_init(&runcf);

		int firstarg = argc; // end of the list

		for (int i = 1; i < argc; ++i)
		{
			const char* const carg = argv[i];
			if (carg[0] == '-')
			{
				if (carg[1] == '-')
				{
					if (carg[2] != '\0') // to handle '--' option
					{
						AnyString arg{carg};

						if (arg == "--help")
							return printUsage(argv[0]);
						if (arg == "--version")
							return printVersion();
						if (arg == "--bugreport")
							return printBugReportInfo();
						if (arg == "--verbose")
						{
							runcf.verbose = nytrue;
							continue;
						}
						return unknownOption(argv0, arg);
					}
					else
					{
						// nothing must interpreted after '--'
						firstarg = i + 1;
						break;
					}
				}
				else
				{
					AnyString arg{carg};
					if (arg == "-h")
						return printUsage(argv[0]);
					if (arg == "-v")
						return printVersion();
					return unknownOption(argv0, arg);
				}
			}

			firstarg = i;
			break;
		}

		//
		// -- execute the script
		//
		int exitstatus = -1;
		if (firstarg < argc)
		{
			// callbacks
			runcf.build.on_error_file_eacces = &on_error_file_eacces;

			// the new arguments, after removing all command line arguments
			int nargc = argc - firstarg;
			const char** nargv = argv + firstarg;
			// the nany sript to load, which should be the first new argument
			const char* nargv0 = nargv[0];

			--nargc;
			uint32_t pargc = (nargc > 0) ? static_cast<uint32_t>(nargc) : 0;
			const char** pargv = (!pargc ? nullptr : (++nargv));

			exitstatus = nyrun_file_n(&runcf, nargv0, strlen(nargv0), pargc, pargv);
		}

		nyrun_cf_release(&runcf);
		return exitstatus;
	}

	return printNoInputScript(argv0);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2008-2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include "esnpapi.h"

namespace
{

NPObject* stubAllocate(NPP npp, NPClass* aClass)
{
    return new StubObject(npp);
}

void stubDeallocate(NPObject* object)
{
    static_cast<StubObject*>(object)->deallocate();
}

void stubInvalidate(NPObject* object)
{
    static_cast<StubObject*>(object)->invalidate();
}

bool stubHasMethod(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->hasMethod(name);
}

bool stubInvoke(NPObject* object, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->invoke(name, args, argCount, result);
}

bool stubInvokeDefault(NPObject* object, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->invokeDefault(args, argCount, result);
}

bool stubHasProperty(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->hasProperty(name);
}

bool stubGetProperty(NPObject* object, NPIdentifier name, NPVariant* result)
{
    return static_cast<StubObject*>(object)->getProperty(name, result);
}

bool stubSetProperty(NPObject* object, NPIdentifier name, const NPVariant* value)
{
    return static_cast<StubObject*>(object)->setProperty(name, value);
}

bool stubRemoveProperty(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->removeProperty(name);
}

bool stubEnumeration(NPObject* object, NPIdentifier** value, uint32_t* count)
{
    return static_cast<StubObject*>(object)->enumeration(value, count);
}

bool stubConstruct(NPObject* object, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->construct(args, argCount, result);
}

const Reflect::SymbolData* lookupSymbolTalbe(Object* object, const char* identifier, unsigned& interfaceNumber, unsigned& symbolNumber)
{
    const Reflect::SymbolData* symbolTable;
    while (symbolTable = object->getSymbolTable(interfaceNumber))
    {
        unsigned offset = 0;
        for (symbolTable += symbolNumber; symbolTable->symbol; ++symbolNumber, ++symbolTable)
        {
            if (!std::strcmp(symbolTable->symbol, identifier))
            {
                return symbolTable;
            }
        }
        ++interfaceNumber;
    }
    return 0;
}

void processResult(NPP npp, const Any& any, NPVariant* variant)
{
    if (any.getType() == Any::TypeString)
    {
        const std::string value = static_cast<const std::string>(any);
        if (value.length() == 0)
        {
            STRINGN_TO_NPVARIANT(0, 0, *variant);
            return;
        }
        void* buffer = NPN_MemAlloc(value.length());
        if (!buffer)
        {
            STRINGN_TO_NPVARIANT(0, 0, *variant);
            return;
        }
        memmove(buffer, value.c_str(), value.length());
        STRINGN_TO_NPVARIANT(static_cast<NPUTF8*>(buffer), value.length(), *variant);
        return;
    }
    convertToVariant(npp, any, variant);
}

}   // namespace

long StubObject::enter()
{
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        ProxyControl* proxyControl = instance->getProxyControl();
        if (proxyControl)
        {
            return proxyControl->enter();
        }
    }
    return 0;
}

long StubObject::leave()
{
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        ProxyControl* proxyControl = instance->getProxyControl();
        if (proxyControl)
        {
            return proxyControl->leave();
        }
    }
    return 0;
}

// Note deallocate() can be invoked after the plugin instance is destroyed.
void StubObject::deallocate()
{
    printf("%s()\n", __func__);
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        StubControl* stubControl = instance->getStubControl();
        if (stubControl)
        {
            stubControl->remove(object);
        }
    }
    delete object;
    delete this;
}

void StubObject::invalidate()
{
    printf("%s()\n", __func__);
}

bool StubObject::hasMethod(NPIdentifier name)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kOperation)
        {
            found = true;
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::invoke(NPIdentifier name, const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s, %p, %u, %p)\n", __func__, identifier, args, arg_count, result);
    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kOperation)
        {
            Reflect::Method method(metaData);
            unsigned argumentCount = method.getParameterCount();
            // TODO: Support variadic operation
            if (argumentCount != arg_count)
            {
                continue;
            }
            enter();
            Reflect::Parameter parameter = method.listParameter();
            Any arguments[argumentCount];
            for (unsigned i = 0; i < argumentCount; ++i)
            {
                parameter.next();
                arguments[i] = convertToAny(npp, &args[i], parameter.getType());
            }
            Any value = object->call(interfaceNumber, data->number, argumentCount, arguments);
            processResult(npp, value, result);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::invokeDefault(const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    printf("%s()\n", __func__);
    return false;
}

bool StubObject::hasProperty(NPIdentifier name)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstant || *metaData == Reflect::kGetter || *metaData == Reflect::kSetter)
        {
            found = true;
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::getProperty(NPIdentifier name, NPVariant* result)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstant)
        {
            // TODO: eval the constant value
            found = true;
            break;
        }
        if (*metaData == Reflect::kGetter)
        {
            enter();
            Any property = object->call(interfaceNumber, data->number, 0, 0);
            processResult(npp, property, result);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::setProperty(NPIdentifier name, const NPVariant* value)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kSetter)
        {
            Reflect::Method method(metaData);
            Reflect::Parameter parameter = method.listParameter();
            parameter.next();
            enter();
            Any argument = convertToAny(npp, value, parameter.getType());
            object->call(interfaceNumber, data->number, 1, &argument);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::removeProperty(NPIdentifier name)
{
    return false;
}

bool StubObject::enumeration(NPIdentifier** value, uint32_t* count)
{
    return false;
}

bool StubObject::construct(const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    printf("%s(%p, %u, %p)\n", __func__, args, arg_count, result);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, "createInstance", interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstructor)
        {
            Reflect::Method method(metaData);
            unsigned argumentCount = method.getParameterCount();
            // TODO: Support variadic operation
            if (argumentCount != arg_count)
            {
                continue;
            }
            enter();
            Reflect::Parameter parameter = method.listParameter();
            Any arguments[argumentCount];
            for (unsigned i = 0; i < argumentCount; ++i)
            {
                parameter.next();
                arguments[i] = convertToAny(npp, &args[i], parameter.getType());
            }
            Any value = object->call(interfaceNumber, data->number, argumentCount, arguments);
            processResult(npp, value, result);
            found = true;
            leave();
            break;
        }
    }
    return found;
}

NPClass StubObject::npclass =
{
    NP_CLASS_STRUCT_VERSION_CTOR,
    stubAllocate,
    stubDeallocate,
    stubInvalidate,
    stubHasMethod,
    stubInvoke,
    stubInvokeDefault,
    stubHasProperty,
    stubGetProperty,
    stubSetProperty,
    stubRemoveProperty,
    stubEnumeration,
    stubConstruct
};

StubControl::StubControl(NPP npp) :
    npp(npp)
{
}

StubControl::~StubControl()
{
}

NPObject* StubControl::findStub(Object* object)
{
    std::map<Object*, StubObject*>::iterator i;
    i = stubMap.find(object);
    if (i != stubMap.end())
    {
        return i->second;
    }
    return 0;
}

NPObject* StubControl::createStub(Object* object)
{
    NPObject* npobject = findStub(object);
    if (npobject)
    {
        return npobject;
    }
    npobject = NPN_CreateObject(npp, &StubObject::npclass);
    if (!npobject)
    {
        return 0;
    }
    StubObject* stub = static_cast<StubObject*>(npobject);
    stub->setObject(object);
    stubMap.insert(std::pair<Object*, StubObject*>(object, stub));
    return stub;
}

void StubControl::remove(Object* object)
{
    stubMap.erase(object);
}

unsigned int PluginInstance::retain(Object* stub)
{
    NPObject* npobject = stubControl.findStub(stub);
    if (!npobject)
    {
        return 1;
    }
    NPN_RetainObject(npobject);
    return npobject->referenceCount;
}

unsigned int PluginInstance::release(Object* stub)
{
    NPObject* npobject = stubControl.findStub(stub);
    if (!npobject)
    {
        delete stub;
        return 0;
    }
    unsigned int count = npobject->referenceCount;
    NPN_ReleaseObject(npobject);
    return --count;
}
<commit_msg>(StubObject) : Add one more TODO.<commit_after>/*
 * Copyright 2008-2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include "esnpapi.h"

namespace
{

NPObject* stubAllocate(NPP npp, NPClass* aClass)
{
    return new StubObject(npp);
}

void stubDeallocate(NPObject* object)
{
    static_cast<StubObject*>(object)->deallocate();
}

void stubInvalidate(NPObject* object)
{
    static_cast<StubObject*>(object)->invalidate();
}

bool stubHasMethod(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->hasMethod(name);
}

bool stubInvoke(NPObject* object, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->invoke(name, args, argCount, result);
}

bool stubInvokeDefault(NPObject* object, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->invokeDefault(args, argCount, result);
}

bool stubHasProperty(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->hasProperty(name);
}

bool stubGetProperty(NPObject* object, NPIdentifier name, NPVariant* result)
{
    return static_cast<StubObject*>(object)->getProperty(name, result);
}

bool stubSetProperty(NPObject* object, NPIdentifier name, const NPVariant* value)
{
    return static_cast<StubObject*>(object)->setProperty(name, value);
}

bool stubRemoveProperty(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->removeProperty(name);
}

bool stubEnumeration(NPObject* object, NPIdentifier** value, uint32_t* count)
{
    return static_cast<StubObject*>(object)->enumeration(value, count);
}

bool stubConstruct(NPObject* object, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->construct(args, argCount, result);
}

const Reflect::SymbolData* lookupSymbolTalbe(Object* object, const char* identifier, unsigned& interfaceNumber, unsigned& symbolNumber)
{
    const Reflect::SymbolData* symbolTable;
    while (symbolTable = object->getSymbolTable(interfaceNumber))
    {
        unsigned offset = 0;
        for (symbolTable += symbolNumber; symbolTable->symbol; ++symbolNumber, ++symbolTable)
        {
            if (!std::strcmp(symbolTable->symbol, identifier))
            {
                return symbolTable;
            }
        }
        ++interfaceNumber;
    }
    return 0;
}

void processResult(NPP npp, const Any& any, NPVariant* variant)
{
    // TODO: Additional code if any.isSequence() is true.
    if (any.getType() == Any::TypeString)
    {
        const std::string value = static_cast<const std::string>(any);
        if (value.length() == 0)
        {
            STRINGN_TO_NPVARIANT(0, 0, *variant);
            return;
        }
        void* buffer = NPN_MemAlloc(value.length());
        if (!buffer)
        {
            STRINGN_TO_NPVARIANT(0, 0, *variant);
            return;
        }
        memmove(buffer, value.c_str(), value.length());
        STRINGN_TO_NPVARIANT(static_cast<NPUTF8*>(buffer), value.length(), *variant);
        return;
    }
    convertToVariant(npp, any, variant);
}

}   // namespace

long StubObject::enter()
{
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        ProxyControl* proxyControl = instance->getProxyControl();
        if (proxyControl)
        {
            return proxyControl->enter();
        }
    }
    return 0;
}

long StubObject::leave()
{
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        ProxyControl* proxyControl = instance->getProxyControl();
        if (proxyControl)
        {
            return proxyControl->leave();
        }
    }
    return 0;
}

// Note deallocate() can be invoked after the plugin instance is destroyed.
void StubObject::deallocate()
{
    printf("%s()\n", __func__);
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        StubControl* stubControl = instance->getStubControl();
        if (stubControl)
        {
            stubControl->remove(object);
        }
    }
    delete object;
    delete this;
}

void StubObject::invalidate()
{
    printf("%s()\n", __func__);
}

bool StubObject::hasMethod(NPIdentifier name)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kOperation)
        {
            found = true;
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::invoke(NPIdentifier name, const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s, %p, %u, %p)\n", __func__, identifier, args, arg_count, result);
    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kOperation)
        {
            Reflect::Method method(metaData);
            unsigned argumentCount = method.getParameterCount();
            // TODO: Support variadic operation
            if (argumentCount != arg_count)
            {
                continue;
            }
            enter();
            Reflect::Parameter parameter = method.listParameter();
            Any arguments[argumentCount];
            for (unsigned i = 0; i < argumentCount; ++i)
            {
                parameter.next();
                arguments[i] = convertToAny(npp, &args[i], parameter.getType());
            }
            Any value = object->call(interfaceNumber, data->number, argumentCount, arguments);
            processResult(npp, value, result);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::invokeDefault(const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    printf("%s()\n", __func__);
    return false;
}

bool StubObject::hasProperty(NPIdentifier name)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstant || *metaData == Reflect::kGetter || *metaData == Reflect::kSetter)
        {
            found = true;
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::getProperty(NPIdentifier name, NPVariant* result)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstant)
        {
            // TODO: eval the constant value
            found = true;
            break;
        }
        if (*metaData == Reflect::kGetter)
        {
            enter();
            Any property = object->call(interfaceNumber, data->number, 0, 0);
            processResult(npp, property, result);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::setProperty(NPIdentifier name, const NPVariant* value)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kSetter)
        {
            Reflect::Method method(metaData);
            Reflect::Parameter parameter = method.listParameter();
            parameter.next();
            enter();
            Any argument = convertToAny(npp, value, parameter.getType());
            object->call(interfaceNumber, data->number, 1, &argument);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::removeProperty(NPIdentifier name)
{
    return false;
}

bool StubObject::enumeration(NPIdentifier** value, uint32_t* count)
{
    return false;
}

bool StubObject::construct(const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    printf("%s(%p, %u, %p)\n", __func__, args, arg_count, result);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, "createInstance", interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstructor)
        {
            Reflect::Method method(metaData);
            unsigned argumentCount = method.getParameterCount();
            // TODO: Support variadic operation
            if (argumentCount != arg_count)
            {
                continue;
            }
            enter();
            Reflect::Parameter parameter = method.listParameter();
            Any arguments[argumentCount];
            for (unsigned i = 0; i < argumentCount; ++i)
            {
                parameter.next();
                arguments[i] = convertToAny(npp, &args[i], parameter.getType());
            }
            Any value = object->call(interfaceNumber, data->number, argumentCount, arguments);
            processResult(npp, value, result);
            found = true;
            leave();
            break;
        }
    }
    return found;
}

NPClass StubObject::npclass =
{
    NP_CLASS_STRUCT_VERSION_CTOR,
    stubAllocate,
    stubDeallocate,
    stubInvalidate,
    stubHasMethod,
    stubInvoke,
    stubInvokeDefault,
    stubHasProperty,
    stubGetProperty,
    stubSetProperty,
    stubRemoveProperty,
    stubEnumeration,
    stubConstruct
};

StubControl::StubControl(NPP npp) :
    npp(npp)
{
}

StubControl::~StubControl()
{
}

NPObject* StubControl::findStub(Object* object)
{
    std::map<Object*, StubObject*>::iterator i;
    i = stubMap.find(object);
    if (i != stubMap.end())
    {
        return i->second;
    }
    return 0;
}

NPObject* StubControl::createStub(Object* object)
{
    NPObject* npobject = findStub(object);
    if (npobject)
    {
        return npobject;
    }
    npobject = NPN_CreateObject(npp, &StubObject::npclass);
    if (!npobject)
    {
        return 0;
    }
    StubObject* stub = static_cast<StubObject*>(npobject);
    stub->setObject(object);
    stubMap.insert(std::pair<Object*, StubObject*>(object, stub));
    return stub;
}

void StubControl::remove(Object* object)
{
    stubMap.erase(object);
}

unsigned int PluginInstance::retain(Object* stub)
{
    NPObject* npobject = stubControl.findStub(stub);
    if (!npobject)
    {
        return 1;
    }
    NPN_RetainObject(npobject);
    return npobject->referenceCount;
}

unsigned int PluginInstance::release(Object* stub)
{
    NPObject* npobject = stubControl.findStub(stub);
    if (!npobject)
    {
        delete stub;
        return 0;
    }
    unsigned int count = npobject->referenceCount;
    NPN_ReleaseObject(npobject);
    return --count;
}
<|endoftext|>


<commit_before>/*
*  killstreaks.cpp
*  StatusSpec project
*
*  Copyright (c) 2014 thesupremecommander
*  BSD 2-Clause License
*  http://opensource.org/licenses/BSD-2-Clause
*
*/

#include "killstreaks.h"

Killstreaks::Killstreaks() {
	enabled = new ConVar("statusspec_killstreaks_enabled", "0", FCVAR_NONE, "enable killstreaks display", Killstreaks::ToggleEnabled);
}

bool Killstreaks::IsEnabled() {
	return enabled->GetBool();
}

bool Killstreaks::FireEvent(IGameEvent *event) {
	if (strcmp(event->GetName(), "player_spawn") == 0) {
		int userID = event->GetInt("userid", -1);

		if (userID != -1) {
			currentKillstreaks.erase(userID);
		}
	}
	else if (strcmp(event->GetName(), "player_death") == 0) {
		int victimUserID = event->GetInt("userid", -1);
		int attackerUserID = event->GetInt("attacker", -1);
		int assisterUserID = event->GetInt("assister", -1);
		int weaponID = event->GetInt("weaponid");

		if (attackerUserID != -1) {
			if (attackerUserID != victimUserID) {
				currentKillstreaks[attackerUserID][weaponID]++;

				if (IsEnabled()) {
					int attackerKillstreak = 0;

					for (auto iterator = currentKillstreaks[victimUserID].begin(); iterator != currentKillstreaks[victimUserID].end(); ++iterator) {
						attackerKillstreak += iterator->second;
					}

					event->SetInt("kill_streak_total", GetCurrentKillstreak(attackerUserID));

					if (weaponID != TF_WEAPON_NONE) {
						event->SetInt("kill_streak_wep", currentKillstreaks[attackerUserID][weaponID]);
					}
					else {
						event->SetInt("kill_streak_wep", 0);
					}

				}
			}
			else {
				if (IsEnabled()) {
					event->SetInt("kill_streak_total", 0);
					event->SetInt("kill_streak_wep", 0);
				}
			}
		}

		if (assisterUserID != -1) {
			IClientEntity *assister = Interfaces::pClientEntityList->GetClientEntity(Interfaces::pEngineClient->GetPlayerForUserID(assisterUserID));

			if (assister && Entities::CheckClassBaseclass(assister->GetClientClass(), "DT_TFPlayer")) {
				for (int i = 0; i < MAX_WEAPONS; i++) {
					IClientEntity *weapon = Interfaces::pClientEntityList->GetClientEntity(ENTITY_INDEX_FROM_ENTITY_OFFSET(assister, Entities::pCTFPlayer__m_hMyWeapons[i]));

					if (!weapon || !Entities::CheckClassBaseclass(weapon->GetClientClass(), "DT_WeaponMedigun")) {
						continue;
					}

					bool healing = *MAKE_PTR(bool *, weapon, Entities::pCWeaponMedigun__m_bHealing);

					if (healing) {
						int healingTarget = ENTITY_INDEX_FROM_ENTITY_OFFSET(weapon, Entities::pCWeaponMedigun__m_hHealingTarget);

						if (healingTarget == Interfaces::pEngineClient->GetPlayerForUserID(attackerUserID)) {
							currentKillstreaks[assisterUserID][TF_WEAPON_MEDIGUN]++;
						}
					}
				}
			}

			if (IsEnabled()) {
				event->SetInt("kill_streak_assist", GetCurrentKillstreak(assisterUserID));
			}
		}

		if (victimUserID != -1) {
			if (IsEnabled()) {
				event->SetInt("kill_streak_victim", GetCurrentKillstreak(victimUserID));
			}
		}

		if (IsEnabled()) {
			return true;
		}
	}

	return false;
}

void Killstreaks::ProcessEntity(IClientEntity* entity) {
	if (!Entities::CheckClassBaseclass(entity->GetClientClass(), "DT_TFPlayer")) {
		return;
	}

	if (IsEnabled()) {
		int *killstreakPlayer = MAKE_PTR(int *, entity, Entities::pCTFPlayer__m_iKillStreak);
		*killstreakPlayer = 0;

		C_PlayerResource *playerResource = dynamic_cast<C_PlayerResource *>(Interfaces::GetGameResources());

		if (playerResource) {
			player_info_t playerInfo;

			if (Interfaces::pEngineClient->GetPlayerInfo(entity->entindex(), &playerInfo)) {
				int *killstreakGlobal = MAKE_PTR(int *, playerResource, Entities::pCTFPlayerResource__m_iKillstreak[entity->entindex()]);
				*killstreakGlobal = 0;
			}
		}
	}
}

void Killstreaks::PostEntityUpdate() {
	C_PlayerResource *playerResource = dynamic_cast<C_PlayerResource *>(Interfaces::GetGameResources());

	for (auto iterator = currentKillstreaks.begin(); iterator != currentKillstreaks.end(); ++iterator) {
		int player = Interfaces::pEngineClient->GetPlayerForUserID(iterator->first);
		IClientEntity *playerEntity = Interfaces::pClientEntityList->GetClientEntity(player);

		if (!playerEntity || !Entities::CheckClassBaseclass(playerEntity->GetClientClass(), "DT_TFPlayer")) {
			currentKillstreaks.erase(iterator);
			continue;
		}

		if (IsEnabled() && Interfaces::GetGameResources()->IsAlive(player)) {
			int currentKillstreak = GetCurrentKillstreak(iterator->first);

			int *killstreakPlayer = MAKE_PTR(int *, playerEntity, Entities::pCTFPlayer__m_iKillStreak);
			*killstreakPlayer = currentKillstreak;

			if (playerResource) {
				int *killstreakGlobal = MAKE_PTR(int *, playerResource, Entities::pCTFPlayerResource__m_iKillstreak[player]);
				*killstreakGlobal = currentKillstreak;
			}
		}
	}
}

int Killstreaks::GetCurrentKillstreak(int userid) {
	int killstreak = 0;

	for (auto iterator = currentKillstreaks[userid].begin(); iterator != currentKillstreaks[userid].end(); ++iterator) {
		killstreak += iterator->second;
	}

	return killstreak;
}

void Killstreaks::ToggleEnabled(IConVar *var, const char *pOldValue, float flOldValue) {
	if (!g_Killstreaks->IsEnabled()) {
		for (int i = 0; i <= MAX_PLAYERS; i++) {
			IClientEntity *entity = Interfaces::pClientEntityList->GetClientEntity(i);

			if (!entity) {
				continue;
			}

			if (!Entities::CheckClassBaseclass(entity->GetClientClass(), "DT_TFPlayer")) {
				continue;
			}

			C_PlayerResource *playerResource = dynamic_cast<C_PlayerResource *>(Interfaces::GetGameResources());

			if (playerResource) {
				player_info_t playerInfo;

				if (Interfaces::pEngineClient->GetPlayerInfo(entity->entindex(), &playerInfo)) {
					int *killstreak = MAKE_PTR(int *, playerResource, Entities::pCTFPlayerResource__m_iKillstreak[entity->entindex()]);
					*killstreak = 0;
				}
			}
		}
	}
}<commit_msg>Fix killstreak module causing post-game crashes.<commit_after>/*
*  killstreaks.cpp
*  StatusSpec project
*
*  Copyright (c) 2014 thesupremecommander
*  BSD 2-Clause License
*  http://opensource.org/licenses/BSD-2-Clause
*
*/

#include "killstreaks.h"

Killstreaks::Killstreaks() {
	enabled = new ConVar("statusspec_killstreaks_enabled", "0", FCVAR_NONE, "enable killstreaks display", Killstreaks::ToggleEnabled);
}

bool Killstreaks::IsEnabled() {
	return enabled->GetBool();
}

bool Killstreaks::FireEvent(IGameEvent *event) {
	if (strcmp(event->GetName(), "player_spawn") == 0) {
		int userID = event->GetInt("userid", -1);

		if (userID != -1) {
			currentKillstreaks.erase(userID);
		}
	}
	else if (strcmp(event->GetName(), "player_death") == 0) {
		int victimUserID = event->GetInt("userid", -1);
		int attackerUserID = event->GetInt("attacker", -1);
		int assisterUserID = event->GetInt("assister", -1);
		int weaponID = event->GetInt("weaponid");

		if (attackerUserID != -1) {
			if (attackerUserID != victimUserID) {
				currentKillstreaks[attackerUserID][weaponID]++;

				if (IsEnabled()) {
					int attackerKillstreak = 0;

					for (auto iterator = currentKillstreaks[victimUserID].begin(); iterator != currentKillstreaks[victimUserID].end(); ++iterator) {
						attackerKillstreak += iterator->second;
					}

					event->SetInt("kill_streak_total", GetCurrentKillstreak(attackerUserID));

					if (weaponID != TF_WEAPON_NONE) {
						event->SetInt("kill_streak_wep", currentKillstreaks[attackerUserID][weaponID]);
					}
					else {
						event->SetInt("kill_streak_wep", 0);
					}

				}
			}
			else {
				if (IsEnabled()) {
					event->SetInt("kill_streak_total", 0);
					event->SetInt("kill_streak_wep", 0);
				}
			}
		}

		if (assisterUserID != -1) {
			IClientEntity *assister = Interfaces::pClientEntityList->GetClientEntity(Interfaces::pEngineClient->GetPlayerForUserID(assisterUserID));

			if (assister && Entities::CheckClassBaseclass(assister->GetClientClass(), "DT_TFPlayer")) {
				for (int i = 0; i < MAX_WEAPONS; i++) {
					IClientEntity *weapon = Interfaces::pClientEntityList->GetClientEntity(ENTITY_INDEX_FROM_ENTITY_OFFSET(assister, Entities::pCTFPlayer__m_hMyWeapons[i]));

					if (!weapon || !Entities::CheckClassBaseclass(weapon->GetClientClass(), "DT_WeaponMedigun")) {
						continue;
					}

					bool healing = *MAKE_PTR(bool *, weapon, Entities::pCWeaponMedigun__m_bHealing);

					if (healing) {
						int healingTarget = ENTITY_INDEX_FROM_ENTITY_OFFSET(weapon, Entities::pCWeaponMedigun__m_hHealingTarget);

						if (healingTarget == Interfaces::pEngineClient->GetPlayerForUserID(attackerUserID)) {
							currentKillstreaks[assisterUserID][TF_WEAPON_MEDIGUN]++;
						}
					}
				}
			}

			if (IsEnabled()) {
				event->SetInt("kill_streak_assist", GetCurrentKillstreak(assisterUserID));
			}
		}

		if (victimUserID != -1) {
			if (IsEnabled()) {
				event->SetInt("kill_streak_victim", GetCurrentKillstreak(victimUserID));
			}
		}

		if (IsEnabled()) {
			return true;
		}
	}

	return false;
}

void Killstreaks::ProcessEntity(IClientEntity* entity) {
	if (!Entities::CheckClassBaseclass(entity->GetClientClass(), "DT_TFPlayer")) {
		return;
	}

	if (IsEnabled()) {
		int *killstreakPlayer = MAKE_PTR(int *, entity, Entities::pCTFPlayer__m_iKillStreak);
		*killstreakPlayer = 0;

		C_PlayerResource *playerResource = dynamic_cast<C_PlayerResource *>(Interfaces::GetGameResources());

		if (playerResource) {
			player_info_t playerInfo;

			if (Interfaces::pEngineClient->GetPlayerInfo(entity->entindex(), &playerInfo)) {
				int *killstreakGlobal = MAKE_PTR(int *, playerResource, Entities::pCTFPlayerResource__m_iKillstreak[entity->entindex()]);
				*killstreakGlobal = 0;
			}
		}
	}
}

void Killstreaks::PostEntityUpdate() {
	if (!Interfaces::pEngineClient->IsInGame()) {
		currentKillstreaks.clear();
		return;
	}

	C_PlayerResource *playerResource = dynamic_cast<C_PlayerResource *>(Interfaces::GetGameResources());

	for (auto iterator = currentKillstreaks.begin(); iterator != currentKillstreaks.end(); ++iterator) {
		int player = Interfaces::pEngineClient->GetPlayerForUserID(iterator->first);
		IClientEntity *playerEntity = Interfaces::pClientEntityList->GetClientEntity(player);

		if (IsEnabled() && Interfaces::GetGameResources()->IsAlive(player)) {
			int currentKillstreak = GetCurrentKillstreak(iterator->first);

			int *killstreakPlayer = MAKE_PTR(int *, playerEntity, Entities::pCTFPlayer__m_iKillStreak);
			*killstreakPlayer = currentKillstreak;

			if (playerResource) {
				int *killstreakGlobal = MAKE_PTR(int *, playerResource, Entities::pCTFPlayerResource__m_iKillstreak[player]);
				*killstreakGlobal = currentKillstreak;
			}
		}
	}
}

int Killstreaks::GetCurrentKillstreak(int userid) {
	int killstreak = 0;

	for (auto iterator = currentKillstreaks[userid].begin(); iterator != currentKillstreaks[userid].end(); ++iterator) {
		killstreak += iterator->second;
	}

	return killstreak;
}

void Killstreaks::ToggleEnabled(IConVar *var, const char *pOldValue, float flOldValue) {
	if (!g_Killstreaks->IsEnabled()) {
		for (int i = 0; i <= MAX_PLAYERS; i++) {
			IClientEntity *entity = Interfaces::pClientEntityList->GetClientEntity(i);

			if (!entity) {
				continue;
			}

			if (!Entities::CheckClassBaseclass(entity->GetClientClass(), "DT_TFPlayer")) {
				continue;
			}

			C_PlayerResource *playerResource = dynamic_cast<C_PlayerResource *>(Interfaces::GetGameResources());

			if (playerResource) {
				player_info_t playerInfo;

				if (Interfaces::pEngineClient->GetPlayerInfo(entity->entindex(), &playerInfo)) {
					int *killstreak = MAKE_PTR(int *, playerResource, Entities::pCTFPlayerResource__m_iKillstreak[entity->entindex()]);
					*killstreak = 0;
				}
			}
		}
	}
}<|endoftext|>


<commit_before>/** Splits input into tokens (words) */

#include <string.h>
#include <ctype.h>
#include <iostream>
#include <string>

#define PUNCTUATION ".,!?()&@()[]{}/\\\"'#:;<>^”*=-−—"

using namespace std;

class Tokenizer
{
private:
  const char* keep; // punctuation to include in output
  bool includeParens;
  char lastChar;

  inline bool isPunctuation(char ch)
  {
    if(ch == '\'')
      return isWS(lastChar);

    return strchr(PUNCTUATION, ch);
  }

  inline bool isDigit(char ch)
  {
    return isdigit(ch);
  }

  inline bool isKeep(char ch)
  {
    return strchr(keep, ch);
  }

  inline bool isWS(char ch)
  {
    return isspace(ch);
  }

  inline void space()
  {
    if(!isWS(lastChar)) {
      fputc(' ', stdout);
      lastChar = ' ';
    }
  }

  inline void character(char ch)
  {
    fputc(ch, stdout);
    lastChar = ch;
  }

public:
  Tokenizer(const char* keep, bool includeParens) {
    this->keep = keep;
    this->includeParens = includeParens;
    this->lastChar = '\0';
  }

  void tokenize(string input) {
    int parenLevel = 0;
    for(size_t i=0; i < input.length(); i++) {
      char ch = input[i];
      switch(ch) {
      case '(':
        parenLevel++;
        if(!includeParens) // skip over the '('
          continue;
        else {
          space();
          character('(');
          space();
          continue;
        }
        break;
      case ')':
        parenLevel--;
        if(!includeParens) // skip over the ')'
          continue;
        else {
          space();
          character(')');
          space();
          continue;
        }
        break;
      }

      if(parenLevel == 0 || includeParens) {
        if(isWS(ch))
          space();
        else if(isPunctuation(ch) && isKeep(ch)) {
          space();
          character(ch);
          space();
        }
        else if(isPunctuation(ch)) {
          // don't break words on commas delimiting orders of magnitude
          // in numbers, e.g. 1,000,000
          if(ch == ',' && isDigit(lastChar) && isDigit(input[i+1]))
            character(ch);
          else
            space();
        }
        else if(!isPunctuation(ch))
          character(tolower(ch));
      }
    }

    character('\n');
  } // end of tokenize()
};

void printUsage(const char* name)
{
  printf("Usage: %s [--keep CHARACTERS] [--parens]\n", name);
}

int main(int argc, const char** argv)
{
  bool includeParens = false;
  const char* keep = "";

  for(int i=1; i<argc; i++) {
    if(strcmp("--keep", argv[i]) == 0 && i<argc-1) {
      keep = argv[i+1];
      i++;
    }
    else if(strcmp("--parens", argv[i]) == 0) {
      includeParens = true;
    }
    else {
      printUsage(argv[0]);
      return 1;
    }
  }

  Tokenizer tokenizer(keep, includeParens);

  string line;
  try {
    while(getline(cin, line)) {
      tokenizer.tokenize(line);
    }
  } catch(string err) {
    cerr << err << endl;
    return 1;
  }

}
<commit_msg>recognize the ASCII character 0x93 (open quote) as punctuation in the tokenizer<commit_after>/** Splits input into tokens (words) */

#include <string.h>
#include <ctype.h>
#include <iostream>
#include <string>

#define PUNCTUATION ".,!?()&@()[]{}/\\\"'#:;<>^”*=-−—\x93"

using namespace std;

class Tokenizer
{
private:
  const char* keep; // punctuation to include in output
  bool includeParens;
  char lastChar;

  inline bool isPunctuation(char ch)
  {
    if(ch == '\'')
      return isWS(lastChar);

    return strchr(PUNCTUATION, ch);
  }

  inline bool isDigit(char ch)
  {
    return isdigit(ch);
  }

  inline bool isKeep(char ch)
  {
    return strchr(keep, ch);
  }

  inline bool isWS(char ch)
  {
    return isspace(ch);
  }

  inline void space()
  {
    if(!isWS(lastChar)) {
      fputc(' ', stdout);
      lastChar = ' ';
    }
  }

  inline void character(char ch)
  {
    fputc(ch, stdout);
    lastChar = ch;
  }

public:
  Tokenizer(const char* keep, bool includeParens) {
    this->keep = keep;
    this->includeParens = includeParens;
    this->lastChar = '\0';
  }

  void tokenize(string input) {
    int parenLevel = 0;
    for(size_t i=0; i < input.length(); i++) {
      char ch = input[i];
      switch(ch) {
      case '(':
        parenLevel++;
        if(!includeParens) // skip over the '('
          continue;
        else {
          space();
          character('(');
          space();
          continue;
        }
        break;
      case ')':
        parenLevel--;
        if(!includeParens) // skip over the ')'
          continue;
        else {
          space();
          character(')');
          space();
          continue;
        }
        break;
      }

      if(parenLevel == 0 || includeParens) {
        if(isWS(ch))
          space();
        else if(isPunctuation(ch) && isKeep(ch)) {
          space();
          character(ch);
          space();
        }
        else if(isPunctuation(ch)) {
          // don't break words on commas delimiting orders of magnitude
          // in numbers, e.g. 1,000,000
          if(ch == ',' && isDigit(lastChar) && isDigit(input[i+1]))
            character(ch);
          else
            space();
        }
        else if(!isPunctuation(ch))
          character(tolower(ch));
      }
    }

    character('\n');
  } // end of tokenize()
};

void printUsage(const char* name)
{
  printf("Usage: %s [--keep CHARACTERS] [--parens]\n", name);
}

int main(int argc, const char** argv)
{
  bool includeParens = false;
  const char* keep = "";

  for(int i=1; i<argc; i++) {
    if(strcmp("--keep", argv[i]) == 0 && i<argc-1) {
      keep = argv[i+1];
      i++;
    }
    else if(strcmp("--parens", argv[i]) == 0) {
      includeParens = true;
    }
    else {
      printUsage(argv[0]);
      return 1;
    }
  }

  Tokenizer tokenizer(keep, includeParens);

  string line;
  try {
    while(getline(cin, line)) {
      tokenizer.tokenize(line);
    }
  } catch(string err) {
    cerr << err << endl;
    return 1;
  }

}
<|endoftext|>