<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: handlerhelper.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2007-07-06 08:49:40 $
 *
 *  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_extensions.hxx"

#ifndef EXTENSIONS_SOURCE_PROPCTRLR_HANDLERHELPER_HXX
#include "handlerhelper.hxx"
#endif
#ifndef EXTENSIONS_PROPRESID_HRC
#include "propresid.hrc"
#endif
#ifndef _COMPHELPER_EXTRACT_HXX_
#include <comphelper/extract.hxx>
#endif
#ifndef _EXTENSIONS_PROPCTRLR_MODULEPRC_HXX_
#include "modulepcr.hxx"
#endif
#ifndef EXTENSIONS_SOURCE_PROPCTRLR_ENUMREPRESENTATION_HXX
#include "enumrepresentation.hxx"
#endif
#ifndef _EXTENSIONS_PROPCTRLR_FORMMETADATA_HXX_
#include "formmetadata.hxx"
#endif
#ifndef EXTENSIONS_SOURCE_PROPCTRLR_PCROMPONENTCONTEXT_HXX
#include "pcrcomponentcontext.hxx"
#endif

/** === begin UNO includes === **/
#ifndef _COM_SUN_STAR_INSPECTION_STRINGREPRESENTATION_HPP_
#include "com/sun/star/inspection/StringRepresentation.hpp"
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COM_SUN_STAR_UNO_XCOMPONENTCONTEXT_HPP_
#include <com/sun/star/uno/XComponentContext.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XMODIFIABLE_HPP_
#include <com/sun/star/util/XModifiable.hpp>
#endif
#ifndef _COM_SUN_STAR_AWT_XWINDOW_HPP_
#include <com/sun/star/awt/XWindow.hpp>
#endif
#ifndef _COM_SUN_STAR_INSPECTION_LINEDESCRIPTOR_HPP_
#include <com/sun/star/inspection/LineDescriptor.hpp>
#endif
#ifndef _COM_SUN_STAR_INSPECTION_PROPERTYCONTROLTYPE_HPP_
#include <com/sun/star/inspection/PropertyControlType.hpp>
#endif
#ifndef _COM_SUN_STAR_INSPECTION_XSTRINGLISTCONTROL_HPP_
#include <com/sun/star/inspection/XStringListControl.hpp>
#endif
#ifndef _COM_SUN_STAR_INSPECTION_XNUMERICCONTROL_HPP_
#include <com/sun/star/inspection/XNumericControl.hpp>
#endif
/** === end UNO includes === **/

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
#include <toolkit/helper/vclunohelper.hxx>
#endif

#include <algorithm>

//........................................................................
namespace pcr
{
//........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;
    using namespace ::com::sun::star::awt;
    using namespace ::com::sun::star::util;
    using namespace ::com::sun::star::beans;
    using namespace ::com::sun::star::script;
    using namespace ::com::sun::star::inspection;

    //====================================================================
    //= PropertyHandlerHelper
    //====================================================================
    //--------------------------------------------------------------------
    void PropertyHandlerHelper::describePropertyLine( const Property& _rProperty,
        LineDescriptor& /* [out] */ _out_rDescriptor, const Reference< XPropertyControlFactory >& _rxControlFactory )
    {
        // display the pure property name - no L10N
        _out_rDescriptor.DisplayName = _rProperty.Name;

        OSL_PRECOND( _rxControlFactory.is(), "PropertyHandlerHelper::describePropertyLine: no factory -> no control!" );
        if ( !_rxControlFactory.is() )
            return;

        sal_Bool bReadOnlyControl = requiresReadOnlyControl( _rProperty.Attributes );

        // special handling for booleans (this will become a list)
        if ( _rProperty.Type.getTypeClass() == TypeClass_BOOLEAN )
        {
            String aBoolOptions = String( PcrRes( RID_STR_BOOL ) );
            Sequence< ::rtl::OUString > aEntries(2);
            for ( xub_StrLen i=0; i<2; ++i )
                aEntries[i] = aBoolOptions.GetToken( i );
            _out_rDescriptor.Control = createListBoxControl( _rxControlFactory, aEntries, bReadOnlyControl, sal_False );
            return;
        }

        sal_Int16 nControlType = PropertyControlType::TextField;
        switch ( _rProperty.Type.getTypeClass() )
        {
        case TypeClass_BYTE:
        case TypeClass_SHORT:
        case TypeClass_UNSIGNED_SHORT:
        case TypeClass_LONG:
        case TypeClass_UNSIGNED_LONG:
        case TypeClass_HYPER:
        case TypeClass_UNSIGNED_HYPER:
        case TypeClass_FLOAT:
        case TypeClass_DOUBLE:
            nControlType = PropertyControlType::NumericField;
            break;

        case TypeClass_SEQUENCE:
            nControlType = PropertyControlType::StringListField;
            break;

        default:
            DBG_ERROR( "PropertyHandlerHelper::describePropertyLine: don't know how to represent this at the UI!" );
            // NO break!

        case TypeClass_STRING:
            nControlType = PropertyControlType::TextField;
            break;
        }

        // create a control
        _out_rDescriptor.Control = _rxControlFactory->createPropertyControl( nControlType, bReadOnlyControl );
    }

    //--------------------------------------------------------------------
    namespace
    {
        Reference< XPropertyControl > lcl_implCreateListLikeControl(
                const Reference< XPropertyControlFactory >& _rxControlFactory,
                const ::std::vector< ::rtl::OUString >& _rInitialListEntries,
                sal_Bool _bReadOnlyControl,
                sal_Bool _bSorted,
                sal_Bool _bTrueIfListBoxFalseIfComboBox
            )
        {
            Reference< XStringListControl > xListControl(
                _rxControlFactory->createPropertyControl(
                    _bTrueIfListBoxFalseIfComboBox ? PropertyControlType::ListBox : PropertyControlType::ComboBox, _bReadOnlyControl
                ),
                UNO_QUERY_THROW
            );

            ::std::vector< ::rtl::OUString > aInitialEntries( _rInitialListEntries );
            if ( _bSorted )
                ::std::sort( aInitialEntries.begin(), aInitialEntries.end() );

            for (   ::std::vector< ::rtl::OUString >::const_iterator loop = aInitialEntries.begin();
                    loop != aInitialEntries.end();
                    ++loop
                )
                xListControl->appendListEntry( *loop );
            return xListControl.get();
        }
    }

    //--------------------------------------------------------------------
    Reference< XPropertyControl > PropertyHandlerHelper::createListBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
                const Sequence< ::rtl::OUString >& _rInitialListEntries, sal_Bool _bReadOnlyControl, sal_Bool _bSorted )
    {
        ::std::vector< ::rtl::OUString > aAsVector( _rInitialListEntries.getConstArray(), _rInitialListEntries.getConstArray() + _rInitialListEntries.getLength() );
        return lcl_implCreateListLikeControl( _rxControlFactory, aAsVector, _bReadOnlyControl, _bSorted, sal_True );
    }

    //--------------------------------------------------------------------
    Reference< XPropertyControl > PropertyHandlerHelper::createListBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
                const ::std::vector< ::rtl::OUString >& _rInitialListEntries, sal_Bool _bReadOnlyControl, sal_Bool _bSorted )
    {
        return lcl_implCreateListLikeControl( _rxControlFactory, _rInitialListEntries, _bReadOnlyControl, _bSorted, sal_True );
    }

    //--------------------------------------------------------------------
    Reference< XPropertyControl > PropertyHandlerHelper::createComboBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
                const Sequence< ::rtl::OUString >& _rInitialListEntries, sal_Bool _bReadOnlyControl, sal_Bool _bSorted )
    {
        ::std::vector< ::rtl::OUString > aAsVector( _rInitialListEntries.getConstArray(), _rInitialListEntries.getConstArray() + _rInitialListEntries.getLength() );
        return lcl_implCreateListLikeControl( _rxControlFactory, aAsVector, _bReadOnlyControl, _bSorted, sal_False );
    }

    //--------------------------------------------------------------------
    Reference< XPropertyControl > PropertyHandlerHelper::createComboBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
                const ::std::vector< ::rtl::OUString >& _rInitialListEntries, sal_Bool _bReadOnlyControl, sal_Bool _bSorted )
    {
        return lcl_implCreateListLikeControl( _rxControlFactory, _rInitialListEntries, _bReadOnlyControl, _bSorted, sal_False );
    }

    //--------------------------------------------------------------------
    Reference< XPropertyControl > PropertyHandlerHelper::createNumericControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
            sal_Int16 _nDigits, const Optional< double >& _rMinValue, const Optional< double >& _rMaxValue, sal_Bool _bReadOnlyControl )
    {
        Reference< XNumericControl > xNumericControl(
            _rxControlFactory->createPropertyControl( PropertyControlType::NumericField, _bReadOnlyControl ),
            UNO_QUERY_THROW
        );

        xNumericControl->setDecimalDigits( _nDigits );
        xNumericControl->setMinValue( _rMinValue );
        xNumericControl->setMaxValue( _rMaxValue );

        return xNumericControl.get();
    }

    //--------------------------------------------------------------------
    Any PropertyHandlerHelper::convertToPropertyValue( const Reference< XComponentContext >& _rxContext,const Reference< XTypeConverter >& _rxTypeConverter,
        const Property& _rProperty, const Any& _rControlValue )
    {
        Any aPropertyValue( _rControlValue );
        if ( !aPropertyValue.hasValue() )
            // NULL is converted to NULL
            return aPropertyValue;

        if ( aPropertyValue.getValueType().equals( _rProperty.Type ) )
            // nothing to do, type is already as desired
            return aPropertyValue;

        if ( _rControlValue.getValueType().getTypeClass() == TypeClass_STRING )
        {
            ::rtl::OUString sControlValue;
            _rControlValue >>= sControlValue;

            Reference< XStringRepresentation > xConversionHelper = StringRepresentation::create( _rxContext,_rxTypeConverter );
            aPropertyValue = xConversionHelper->convertToPropertyValue( sControlValue, _rProperty.Type );
        }
        else
        {
            try
            {
                if ( _rxTypeConverter.is() )
                    aPropertyValue = _rxTypeConverter->convertTo( _rControlValue, _rProperty.Type );
            }
            catch( const Exception& )
            {
                OSL_ENSURE( sal_False, "PropertyHandlerHelper::convertToPropertyValue: caught an exception while converting via TypeConverter!" );
            }
        }

        return aPropertyValue;
    }

    //--------------------------------------------------------------------
    Any PropertyHandlerHelper::convertToControlValue( const Reference< XComponentContext >& _rxContext,const Reference< XTypeConverter >& _rxTypeConverter,
        const Any& _rPropertyValue, const Type& _rControlValueType )
    {
        Any aControlValue( _rPropertyValue );
        if ( !aControlValue.hasValue() )
            // NULL is converted to NULL
            return aControlValue;

        if ( _rControlValueType.getTypeClass() == TypeClass_STRING )
        {
            Reference< XStringRepresentation > xConversionHelper = StringRepresentation::create( _rxContext,_rxTypeConverter );
            aControlValue <<= xConversionHelper->convertToControlValue( _rPropertyValue );
        }
        else
        {
            try
            {
                if ( _rxTypeConverter.is() )
                    aControlValue = _rxTypeConverter->convertTo( _rPropertyValue, _rControlValueType );
            }
            catch( const Exception& )
            {
                OSL_ENSURE( sal_False, "PropertyHandlerHelper::convertToControlValue: caught an exception while converting via TypeConverter!" );
            }
        }

        return aControlValue;
    }

    //--------------------------------------------------------------------
    void PropertyHandlerHelper::setContextDocumentModified( const ComponentContext& _rContext )
    {
        try
        {
            Reference< XModifiable > xDocumentModifiable( _rContext.getContextValueByAsciiName( "ContextDocument" ), UNO_QUERY_THROW );
            xDocumentModifiable->setModified( sal_True );
        }
        catch( const Exception& e )
        {
        #if OSL_DEBUG_LEVEL > 0
            ::rtl::OString sMessage( "PropertyHandlerHelper::setContextDocumentModified: caught an exception!\n" );
            sMessage += "message:\n";
            sMessage += ::rtl::OString( e.Message.getStr(), e.Message.getLength(), osl_getThreadTextEncoding() );
            OSL_ENSURE( false, sMessage );
        #else
            e; // make compiler happy
        #endif
        }
    }

    //--------------------------------------------------------------------
    Window* PropertyHandlerHelper::getDialogParentWindow( const ComponentContext& _rContext )
    {
        Window* pInspectorWindow = NULL;
        try
        {
            Reference< XWindow > xInspectorWindow( _rContext.getContextValueByAsciiName( "DialogParentWindow" ), UNO_QUERY_THROW );
            pInspectorWindow = VCLUnoHelper::GetWindow( xInspectorWindow );
        }
        catch( const Exception& e )
        {
        #if OSL_DEBUG_LEVEL > 0
            ::rtl::OString sMessage( "PropertyHandlerHelper::getDialogParentWindow: caught an exception!\n" );
            sMessage += "message:\n";
            sMessage += ::rtl::OString( e.Message.getStr(), e.Message.getLength(), osl_getThreadTextEncoding() );
            OSL_ENSURE( false, sMessage );
        #else
            e; // make compiler happy
        #endif
        }
        return pInspectorWindow;
    }

//........................................................................
} // namespace pcr
//........................................................................
<commit_msg>INTEGRATION: CWS wae4extensions (1.7.44); FILE MERGED 2007/09/27 07:18:25 fs 1.7.44.1: #i81612# warning-free code<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: handlerhelper.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: ihi $ $Date: 2008-01-14 14:59:27 $
 *
 *  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_extensions.hxx"

#ifndef EXTENSIONS_SOURCE_PROPCTRLR_HANDLERHELPER_HXX
#include "handlerhelper.hxx"
#endif
#ifndef EXTENSIONS_PROPRESID_HRC
#include "propresid.hrc"
#endif
#ifndef _COMPHELPER_EXTRACT_HXX_
#include <comphelper/extract.hxx>
#endif
#ifndef _EXTENSIONS_PROPCTRLR_MODULEPRC_HXX_
#include "modulepcr.hxx"
#endif
#ifndef EXTENSIONS_SOURCE_PROPCTRLR_ENUMREPRESENTATION_HXX
#include "enumrepresentation.hxx"
#endif
#ifndef _EXTENSIONS_PROPCTRLR_FORMMETADATA_HXX_
#include "formmetadata.hxx"
#endif
#ifndef EXTENSIONS_SOURCE_PROPCTRLR_PCROMPONENTCONTEXT_HXX
#include "pcrcomponentcontext.hxx"
#endif

/** === begin UNO includes === **/
#ifndef _COM_SUN_STAR_INSPECTION_STRINGREPRESENTATION_HPP_
#include "com/sun/star/inspection/StringRepresentation.hpp"
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COM_SUN_STAR_UNO_XCOMPONENTCONTEXT_HPP_
#include <com/sun/star/uno/XComponentContext.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XMODIFIABLE_HPP_
#include <com/sun/star/util/XModifiable.hpp>
#endif
#ifndef _COM_SUN_STAR_AWT_XWINDOW_HPP_
#include <com/sun/star/awt/XWindow.hpp>
#endif
#ifndef _COM_SUN_STAR_INSPECTION_LINEDESCRIPTOR_HPP_
#include <com/sun/star/inspection/LineDescriptor.hpp>
#endif
#ifndef _COM_SUN_STAR_INSPECTION_PROPERTYCONTROLTYPE_HPP_
#include <com/sun/star/inspection/PropertyControlType.hpp>
#endif
#ifndef _COM_SUN_STAR_INSPECTION_XSTRINGLISTCONTROL_HPP_
#include <com/sun/star/inspection/XStringListControl.hpp>
#endif
#ifndef _COM_SUN_STAR_INSPECTION_XNUMERICCONTROL_HPP_
#include <com/sun/star/inspection/XNumericControl.hpp>
#endif
/** === end UNO includes === **/

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef TOOLS_DIAGNOSE_EX_H
#include <tools/diagnose_ex.h>
#endif
#ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
#include <toolkit/helper/vclunohelper.hxx>
#endif

#include <algorithm>

//........................................................................
namespace pcr
{
//........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;
    using namespace ::com::sun::star::awt;
    using namespace ::com::sun::star::util;
    using namespace ::com::sun::star::beans;
    using namespace ::com::sun::star::script;
    using namespace ::com::sun::star::inspection;

    //====================================================================
    //= PropertyHandlerHelper
    //====================================================================
    //--------------------------------------------------------------------
    void PropertyHandlerHelper::describePropertyLine( const Property& _rProperty,
        LineDescriptor& /* [out] */ _out_rDescriptor, const Reference< XPropertyControlFactory >& _rxControlFactory )
    {
        // display the pure property name - no L10N
        _out_rDescriptor.DisplayName = _rProperty.Name;

        OSL_PRECOND( _rxControlFactory.is(), "PropertyHandlerHelper::describePropertyLine: no factory -> no control!" );
        if ( !_rxControlFactory.is() )
            return;

        sal_Bool bReadOnlyControl = requiresReadOnlyControl( _rProperty.Attributes );

        // special handling for booleans (this will become a list)
        if ( _rProperty.Type.getTypeClass() == TypeClass_BOOLEAN )
        {
            String aBoolOptions = String( PcrRes( RID_STR_BOOL ) );
            Sequence< ::rtl::OUString > aEntries(2);
            for ( xub_StrLen i=0; i<2; ++i )
                aEntries[i] = aBoolOptions.GetToken( i );
            _out_rDescriptor.Control = createListBoxControl( _rxControlFactory, aEntries, bReadOnlyControl, sal_False );
            return;
        }

        sal_Int16 nControlType = PropertyControlType::TextField;
        switch ( _rProperty.Type.getTypeClass() )
        {
        case TypeClass_BYTE:
        case TypeClass_SHORT:
        case TypeClass_UNSIGNED_SHORT:
        case TypeClass_LONG:
        case TypeClass_UNSIGNED_LONG:
        case TypeClass_HYPER:
        case TypeClass_UNSIGNED_HYPER:
        case TypeClass_FLOAT:
        case TypeClass_DOUBLE:
            nControlType = PropertyControlType::NumericField;
            break;

        case TypeClass_SEQUENCE:
            nControlType = PropertyControlType::StringListField;
            break;

        default:
            DBG_ERROR( "PropertyHandlerHelper::describePropertyLine: don't know how to represent this at the UI!" );
            // NO break!

        case TypeClass_STRING:
            nControlType = PropertyControlType::TextField;
            break;
        }

        // create a control
        _out_rDescriptor.Control = _rxControlFactory->createPropertyControl( nControlType, bReadOnlyControl );
    }

    //--------------------------------------------------------------------
    namespace
    {
        Reference< XPropertyControl > lcl_implCreateListLikeControl(
                const Reference< XPropertyControlFactory >& _rxControlFactory,
                const ::std::vector< ::rtl::OUString >& _rInitialListEntries,
                sal_Bool _bReadOnlyControl,
                sal_Bool _bSorted,
                sal_Bool _bTrueIfListBoxFalseIfComboBox
            )
        {
            Reference< XStringListControl > xListControl(
                _rxControlFactory->createPropertyControl(
                    _bTrueIfListBoxFalseIfComboBox ? PropertyControlType::ListBox : PropertyControlType::ComboBox, _bReadOnlyControl
                ),
                UNO_QUERY_THROW
            );

            ::std::vector< ::rtl::OUString > aInitialEntries( _rInitialListEntries );
            if ( _bSorted )
                ::std::sort( aInitialEntries.begin(), aInitialEntries.end() );

            for (   ::std::vector< ::rtl::OUString >::const_iterator loop = aInitialEntries.begin();
                    loop != aInitialEntries.end();
                    ++loop
                )
                xListControl->appendListEntry( *loop );
            return xListControl.get();
        }
    }

    //--------------------------------------------------------------------
    Reference< XPropertyControl > PropertyHandlerHelper::createListBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
                const Sequence< ::rtl::OUString >& _rInitialListEntries, sal_Bool _bReadOnlyControl, sal_Bool _bSorted )
    {
        ::std::vector< ::rtl::OUString > aAsVector( _rInitialListEntries.getConstArray(), _rInitialListEntries.getConstArray() + _rInitialListEntries.getLength() );
        return lcl_implCreateListLikeControl( _rxControlFactory, aAsVector, _bReadOnlyControl, _bSorted, sal_True );
    }

    //--------------------------------------------------------------------
    Reference< XPropertyControl > PropertyHandlerHelper::createListBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
                const ::std::vector< ::rtl::OUString >& _rInitialListEntries, sal_Bool _bReadOnlyControl, sal_Bool _bSorted )
    {
        return lcl_implCreateListLikeControl( _rxControlFactory, _rInitialListEntries, _bReadOnlyControl, _bSorted, sal_True );
    }

    //--------------------------------------------------------------------
    Reference< XPropertyControl > PropertyHandlerHelper::createComboBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
                const Sequence< ::rtl::OUString >& _rInitialListEntries, sal_Bool _bReadOnlyControl, sal_Bool _bSorted )
    {
        ::std::vector< ::rtl::OUString > aAsVector( _rInitialListEntries.getConstArray(), _rInitialListEntries.getConstArray() + _rInitialListEntries.getLength() );
        return lcl_implCreateListLikeControl( _rxControlFactory, aAsVector, _bReadOnlyControl, _bSorted, sal_False );
    }

    //--------------------------------------------------------------------
    Reference< XPropertyControl > PropertyHandlerHelper::createComboBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
                const ::std::vector< ::rtl::OUString >& _rInitialListEntries, sal_Bool _bReadOnlyControl, sal_Bool _bSorted )
    {
        return lcl_implCreateListLikeControl( _rxControlFactory, _rInitialListEntries, _bReadOnlyControl, _bSorted, sal_False );
    }

    //--------------------------------------------------------------------
    Reference< XPropertyControl > PropertyHandlerHelper::createNumericControl( const Reference< XPropertyControlFactory >& _rxControlFactory,
            sal_Int16 _nDigits, const Optional< double >& _rMinValue, const Optional< double >& _rMaxValue, sal_Bool _bReadOnlyControl )
    {
        Reference< XNumericControl > xNumericControl(
            _rxControlFactory->createPropertyControl( PropertyControlType::NumericField, _bReadOnlyControl ),
            UNO_QUERY_THROW
        );

        xNumericControl->setDecimalDigits( _nDigits );
        xNumericControl->setMinValue( _rMinValue );
        xNumericControl->setMaxValue( _rMaxValue );

        return xNumericControl.get();
    }

    //--------------------------------------------------------------------
    Any PropertyHandlerHelper::convertToPropertyValue( const Reference< XComponentContext >& _rxContext,const Reference< XTypeConverter >& _rxTypeConverter,
        const Property& _rProperty, const Any& _rControlValue )
    {
        Any aPropertyValue( _rControlValue );
        if ( !aPropertyValue.hasValue() )
            // NULL is converted to NULL
            return aPropertyValue;

        if ( aPropertyValue.getValueType().equals( _rProperty.Type ) )
            // nothing to do, type is already as desired
            return aPropertyValue;

        if ( _rControlValue.getValueType().getTypeClass() == TypeClass_STRING )
        {
            ::rtl::OUString sControlValue;
            _rControlValue >>= sControlValue;

            Reference< XStringRepresentation > xConversionHelper = StringRepresentation::create( _rxContext,_rxTypeConverter );
            aPropertyValue = xConversionHelper->convertToPropertyValue( sControlValue, _rProperty.Type );
        }
        else
        {
            try
            {
                if ( _rxTypeConverter.is() )
                    aPropertyValue = _rxTypeConverter->convertTo( _rControlValue, _rProperty.Type );
            }
            catch( const Exception& )
            {
                OSL_ENSURE( sal_False, "PropertyHandlerHelper::convertToPropertyValue: caught an exception while converting via TypeConverter!" );
            }
        }

        return aPropertyValue;
    }

    //--------------------------------------------------------------------
    Any PropertyHandlerHelper::convertToControlValue( const Reference< XComponentContext >& _rxContext,const Reference< XTypeConverter >& _rxTypeConverter,
        const Any& _rPropertyValue, const Type& _rControlValueType )
    {
        Any aControlValue( _rPropertyValue );
        if ( !aControlValue.hasValue() )
            // NULL is converted to NULL
            return aControlValue;

        if ( _rControlValueType.getTypeClass() == TypeClass_STRING )
        {
            Reference< XStringRepresentation > xConversionHelper = StringRepresentation::create( _rxContext,_rxTypeConverter );
            aControlValue <<= xConversionHelper->convertToControlValue( _rPropertyValue );
        }
        else
        {
            try
            {
                if ( _rxTypeConverter.is() )
                    aControlValue = _rxTypeConverter->convertTo( _rPropertyValue, _rControlValueType );
            }
            catch( const Exception& )
            {
                OSL_ENSURE( sal_False, "PropertyHandlerHelper::convertToControlValue: caught an exception while converting via TypeConverter!" );
            }
        }

        return aControlValue;
    }

    //--------------------------------------------------------------------
    void PropertyHandlerHelper::setContextDocumentModified( const ComponentContext& _rContext )
    {
        try
        {
            Reference< XModifiable > xDocumentModifiable( _rContext.getContextValueByAsciiName( "ContextDocument" ), UNO_QUERY_THROW );
            xDocumentModifiable->setModified( sal_True );
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
    }

    //--------------------------------------------------------------------
    Window* PropertyHandlerHelper::getDialogParentWindow( const ComponentContext& _rContext )
    {
        Window* pInspectorWindow = NULL;
        try
        {
            Reference< XWindow > xInspectorWindow( _rContext.getContextValueByAsciiName( "DialogParentWindow" ), UNO_QUERY_THROW );
            pInspectorWindow = VCLUnoHelper::GetWindow( xInspectorWindow );
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        return pInspectorWindow;
    }

//........................................................................
} // namespace pcr
//........................................................................
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                       OpenSim:  testAnalyzeTool.cpp                        *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2017 Stanford University and the Authors                *
 * Author(s): Ayman Habib, Ajay Seth                                          *
 *                                                                            *
 * 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
#include <OpenSim/Common/CSVFileAdapter.h>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Simulation/StatesTrajectory.h>
#include <OpenSim/Actuators/Millard2012EquilibriumMuscle.h>
#include <OpenSim/Tools/AnalyzeTool.h>
#include <OpenSim/Analyses/OutputReporter.h>
#include <OpenSim/Auxiliary/auxiliaryTestFunctions.h>
#include <OpenSim/Auxiliary/auxiliaryTestMuscleFunctions.h>
#include <OpenSim/Simulation/SimbodyEngine/FreeJoint.h>
#include <OpenSim/Simulation/Manager/Manager.h>
#include <OpenSim/Analyses/BodyKinematics.h>

using namespace OpenSim;
using namespace std;

void testTutorialOne();
void testActuationAnalysisWithDisabledForce();

// Test different default activations are respected when activation
// states are not provided.
void testTugOfWar(const string& dataFileName, const double& defaultAct);

void testBodyKinematics();

int main()
{
    SimTK::Array_<std::string> failures;

    try { testTutorialOne(); }
    catch (const std::exception& e) {
        cout << e.what() << endl; failures.push_back("testTutorialOne");
    }

    // produce passive force-length curve
    try { testTugOfWar("Tug_of_War_ConstantVelocity.sto", 0.01); }
    catch (const std::exception& e) {
        cout << e.what() << endl;
        failures.push_back("testTugOfWar CoordinatesOnly: default_act = 0.01");
    }

    // produced passive + active muscle force-length
    try { testTugOfWar("Tug_of_War_ConstantVelocity.sto", 1.0); }
    catch (const std::exception& e) {
        cout << e.what() << endl;
        failures.push_back("testTugOfWar CoordinatesOnly: default_act = 1.0");
    }

    // now supply activation states which should be used instead of the default
    try { testTugOfWar("Tug_of_War_ConstantVelocity_RampActivation.sto", 0.0); }
    catch (const std::exception& e) {
        cout << e.what() << endl;
        failures.push_back("testTugOfWar with activation state provided");
    }

    try { testActuationAnalysisWithDisabledForce(); }
    catch (const std::exception& e) {
        cout << e.what() << endl;
        failures.push_back("testActuationAnalysisWithDisabledForce");
    }
    try { testBodyKinematics(); }
    catch (const std::exception& e) {
        cout << e.what() << endl;
        failures.push_back("testBodyKinematics");
    }    if (!failures.empty()) {
        cout << "Done, with failure(s): " << failures << endl;
        return 1;
    }

    cout << "Done" << endl;
    return 0;
}

void testTutorialOne() {
    AnalyzeTool analyze1("PlotterTool.xml");
    analyze1.getModel().print("testAnalyzeTutorialOne.osim");
    analyze1.run();
    /* Once this runs to completion we'll make the test more meaningful by comparing output
    * to a validated standard. Let's make sure we don't crash during run first! -Ayman 5/29/12 */
    Storage resultFiberLength("testPlotterTool/BothLegs__FiberLength.sto");
    Storage standardFiberLength("std_BothLegs_fiberLength.sto");
    CHECK_STORAGE_AGAINST_STANDARD(resultFiberLength, standardFiberLength,
        std::vector<double>(100, 0.0001), __FILE__, __LINE__,
        "testAnalyzeTutorialOne failed");
    // const Model& mdl = analyze1.getModel();
    //mdl.updMultibodySystem()
    analyze1.setStatesFileName("plotterGeneratedStatesHip45.sto");
    //analyze1.setModel(mdl);
    analyze1.setName("BothLegsHip45");
    analyze1.run();
    Storage resultFiberLengthHip45("testPlotterTool/BothLegsHip45__FiberLength.sto");
    Storage standardFiberLength45("std_BothLegsHip45__FiberLength.sto");
    CHECK_STORAGE_AGAINST_STANDARD(resultFiberLengthHip45,
        standardFiberLength45, std::vector<double>(100, 0.0001),
        __FILE__, __LINE__, "testAnalyzeTutorialOne at Hip45 failed");
    cout << "testAnalyzeTutorialOne passed" << endl;
}

void testTugOfWar(const string& dataFileName, const double& defaultAct) {
    AnalyzeTool analyze("Tug_of_War_Setup_Analyze.xml");
    analyze.setCoordinatesFileName("");
    analyze.setStatesFileName("");

    // Access the model and muscle being analyzed
    Model& model = analyze.getModel();
    Millard2012EquilibriumMuscle& muscle =
        static_cast<Millard2012EquilibriumMuscle&>(model.updMuscles()[0]);
    bool isCoordinatesOnly = true;
    // Load in the States used to recompute the results of the Analysis
    Storage dataStore(dataFileName);
    if (dataStore.getColumnLabels().findIndex(muscle.getName() + ".activation") > 0) {
        isCoordinatesOnly = false;
        analyze.setStatesFileName(dataFileName);
        // ramp input starts at 0.0
        muscle.set_minimum_activation(0.0);
    }
    else {
        analyze.setCoordinatesFileName(dataFileName);
    }

    // Test that the default activation is taken into consideration by
    // the Analysis and reflected in the AnalyzeTool solution
    muscle.set_default_activation(defaultAct);

    analyze.run();

    // Load the AnalyzTool results for the muscle's force through time
    TimeSeriesTable_<double> results("Analyze_Tug_of_War/Tug_of_War_Millard_Iso_ForceReporter_forces.sto");
    assert(results.getNumColumns() == 1);
    SimTK::Vector forces = results.getDependentColumnAtIndex(0);

    TimeSeriesTable_<double> outputs_table("Analyze_Tug_of_War/Tug_of_War_Millard_Iso_Outputs.sto");
    SimTK::Vector tf_output = outputs_table.getDependentColumnAtIndex(1);

    // Load input data as StatesTrajectory used to perform the Analysis
    auto statesTraj = StatesTrajectory::createFromStatesStorage(
        model, dataStore, true, false);
    size_t nstates = statesTraj.getSize();

    // muscle active, passive, total muscle and tendon force quantities
    double af, pf, mf, tf, fl;
    af= pf = mf = tf = fl = SimTK::NaN;

    // Tolerance for muscle equilibrium solution
    const double equilTol = muscle.getMaxIsometricForce()*SimTK::SqrtEps;

    // The maximum acceptable change in force between two contiguous states
    const double maxDelta = muscle.getMaxIsometricForce() / 10;

    SimTK::State s = model.getWorkingState();
    // Independently compute the active fiber force at every state
    for (size_t i = 0; i < nstates; ++i) {
        s = statesTraj[i];
        // When the muscle states are not supplied in the input dataStore
        // (isCoordinatesOnly == true), then set it to its default value.
        if (isCoordinatesOnly) {
            muscle.setActivation(s, muscle.get_default_activation());
        }
        // technically, fiber lengths could be supplied, but this test case
        // (a typical use case) does not and therefore set to its default.
        muscle.setFiberLength(s, muscle.get_default_fiber_length());
        try {
            muscle.computeEquilibrium(s);
        }
        catch (const MuscleCannotEquilibrate& x) {
            // Write out the muscle equilibrium for error as a function of
            // fiber-length.
            reportTendonAndFiberForcesAcrossFiberLengths(muscle, s);
            throw x;
        }
        model.realizeDynamics(s);

        // Get the fiber-length
        fl = muscle.getFiberLength(s);

        cout << "t = " << s.getTime() << " | fiber_length = " << fl <<
           " : default_fiber_length = " << muscle.get_default_fiber_length() << endl;

        SimTK_ASSERT_ALWAYS(fl >= muscle.getMinimumFiberLength(),
            "Equilibrium failed to compute valid fiber length.");

        if (isCoordinatesOnly) {
            // check that activation is not reset to zero or other value
            SimTK_ASSERT_ALWAYS(muscle.getActivation(s) == defaultAct,
                "Test failed to correctly use the default activation value.");
        }
        else {
            // check that activation used was that supplied by the dataStore
            SimTK_ASSERT_ALWAYS(muscle.getActivation(s) == s.getTime(),
                "Test failed to correctly use the supplied activation values.");
        }

        // get active and passive forces given the default activation
        af = muscle.getActiveFiberForceAlongTendon(s);
        pf = muscle.getPassiveFiberForceAlongTendon(s);

        // now the total muscle force is the active + passive
        mf = af + pf;
        tf = muscle.getTendonForce(s);

        // equilibrium demands tendon and muscle fiber are equivalent
        ASSERT_EQUAL<double>(tf, mf, equilTol);
        // Verify that the current computed and AnalyzeTool reported force are
        // equivalent for the provided motion file
        cout << s.getTime() << " :: muscle-fiber-force: " << mf <<
            " Analyze reported force: " << forces[int(i)] << endl;
        ASSERT_EQUAL<double>(mf, forces[int(i)], equilTol, __FILE__, __LINE__,
            "Total fiber force failed to match reported muscle force.");

        cout << s.getTime() << " :: tendon-force: " << tf <<
            " Analyze Output reported: " << tf_output[int(i)] << endl;
        ASSERT_EQUAL<double>(tf, tf_output[int(i)], equilTol,
            __FILE__, __LINE__,
            "Output reported muscle-tendon force failed to match computed.");

        double delta = (i > 0) ? abs(forces[int(i)]-forces[int(i-1)]) : 0;

        SimTK_ASSERT_ALWAYS(delta < maxDelta,
            "Force trajectory has unexplained discontinuity.");
    }
}

void testActuationAnalysisWithDisabledForce() {
    AnalyzeTool analyze("PlotterTool.xml");
    Model& model = analyze.getModel();
    auto& muscle = model.updMuscles()[0];
    muscle.set_appliesForce(false);

    std::string resultsDir = "testPlotterToolWithDisabledForce";
    analyze.setResultsDir(resultsDir);
    analyze.run();

    // Reading a file with mismatched nColumns header and actual number of
    // data columns will throw.
    TimeSeriesTable_<double> act_force_table(
            resultsDir + "/BothLegs_Actuation_force.sto");

    // Let's also check that the number of columns is correct (i.e.,
    // (number of muscles in the model) - 1).
    ASSERT_EQUAL(model.getMuscles().getSize() - 1,
            (int)act_force_table.getNumColumns());
}

void testBodyKinematics() {
    Model model;
    model.setGravity(SimTK::Vec3(0));
    Body body("body", 1, SimTK::Vec3(0), SimTK::Inertia(1));
    model.addBody(&body);

    // Rotate child frame so that planar rotational joint is about
    // the body's local X axis, and the ground's Z axis
    FreeJoint joint("joint",
        model.getGround(), SimTK::Vec3(0), SimTK::Vec3(0),
        body, SimTK::Vec3(0), SimTK::Vec3(0, SimTK::Pi/2, 0));
    model.addJoint(&joint);
    model.finalizeConnections();

    BodyKinematics bodyKinematicsLocal;
    bodyKinematicsLocal.setName("local");
    bodyKinematicsLocal.setExpressResultsInLocalFrame(true);
    bodyKinematicsLocal.setInDegrees(true);

    BodyKinematics bodyKinematicsGround;
    bodyKinematicsGround.setName("ground");
    bodyKinematicsGround.setExpressResultsInLocalFrame(false);
    bodyKinematicsGround.setInDegrees(false);

    model.addAnalysis(&bodyKinematicsLocal);
    model.addAnalysis(&bodyKinematicsGround);

    SimTK::State& s = model.initSystem();
    double speedRot = 1.0;
    double speedX = 2.0;
    double speedY = 3.0;
    joint.updCoordinate(FreeJoint::Coord::Rotation3Z)
            .setSpeedValue(s, speedRot);
    joint.updCoordinate(FreeJoint::Coord::TranslationX)
            .setSpeedValue(s, speedX);
    joint.updCoordinate(FreeJoint::Coord::TranslationY)
            .setSpeedValue(s, speedY);

    Manager manager(model);
    double duration = 2.0;
    manager.initialize(s);
    s = manager.integrate(duration);

    bodyKinematicsLocal.printResults("BodyKinematics");
    bodyKinematicsGround.printResults("BodyKinematics");

    Storage localVel("BodyKinematics_local_vel_bodyLocal.sto");
    Storage groundVel("BodyKinematics_ground_vel_global.sto");
    Array<double> localVelOx, localVelOz, globalVelOx, globalVelOz;
    localVel.getDataColumn("body_Ox", localVelOx);
    localVel.getDataColumn("body_Oz", localVelOz);
    groundVel.getDataColumn("body_Ox", globalVelOx);
    groundVel.getDataColumn("body_Oz", globalVelOz);

    assert(localVelOx.getLast() == speedRot * SimTK_RADIAN_TO_DEGREE);
    assert(localVelOz.getLast() == 0);
    assert(groundVelOx.getLast() == 0);
    assert(groundVelOz.getLast() == speedrot);

    Array<double> groundPosX, groundPosY;
    Storage groundPos("BodyKinematics_ground_pos_global.sto");
    groundPos.getDataColumn("body_X", groundPosX);
    groundPos.getDataColumn("body_Y", groundPosY);
    assert(groundPosX.getLast() == speedX * duration);
    assert(groundPosY.getLast() == speedY * duration);
}<commit_msg>fix variable names<commit_after>/* -------------------------------------------------------------------------- *
 *                       OpenSim:  testAnalyzeTool.cpp                        *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2017 Stanford University and the Authors                *
 * Author(s): Ayman Habib, Ajay Seth                                          *
 *                                                                            *
 * 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
#include <OpenSim/Common/CSVFileAdapter.h>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Simulation/StatesTrajectory.h>
#include <OpenSim/Actuators/Millard2012EquilibriumMuscle.h>
#include <OpenSim/Tools/AnalyzeTool.h>
#include <OpenSim/Analyses/OutputReporter.h>
#include <OpenSim/Auxiliary/auxiliaryTestFunctions.h>
#include <OpenSim/Auxiliary/auxiliaryTestMuscleFunctions.h>
#include <OpenSim/Simulation/SimbodyEngine/FreeJoint.h>
#include <OpenSim/Simulation/Manager/Manager.h>
#include <OpenSim/Analyses/BodyKinematics.h>

using namespace OpenSim;
using namespace std;

void testTutorialOne();
void testActuationAnalysisWithDisabledForce();

// Test different default activations are respected when activation
// states are not provided.
void testTugOfWar(const string& dataFileName, const double& defaultAct);

void testBodyKinematics();

int main()
{
    SimTK::Array_<std::string> failures;

    try { testTutorialOne(); }
    catch (const std::exception& e) {
        cout << e.what() << endl; failures.push_back("testTutorialOne");
    }

    // produce passive force-length curve
    try { testTugOfWar("Tug_of_War_ConstantVelocity.sto", 0.01); }
    catch (const std::exception& e) {
        cout << e.what() << endl;
        failures.push_back("testTugOfWar CoordinatesOnly: default_act = 0.01");
    }

    // produced passive + active muscle force-length
    try { testTugOfWar("Tug_of_War_ConstantVelocity.sto", 1.0); }
    catch (const std::exception& e) {
        cout << e.what() << endl;
        failures.push_back("testTugOfWar CoordinatesOnly: default_act = 1.0");
    }

    // now supply activation states which should be used instead of the default
    try { testTugOfWar("Tug_of_War_ConstantVelocity_RampActivation.sto", 0.0); }
    catch (const std::exception& e) {
        cout << e.what() << endl;
        failures.push_back("testTugOfWar with activation state provided");
    }

    try { testActuationAnalysisWithDisabledForce(); }
    catch (const std::exception& e) {
        cout << e.what() << endl;
        failures.push_back("testActuationAnalysisWithDisabledForce");
    }
    try { testBodyKinematics(); }
    catch (const std::exception& e) {
        cout << e.what() << endl;
        failures.push_back("testBodyKinematics");
    }    if (!failures.empty()) {
        cout << "Done, with failure(s): " << failures << endl;
        return 1;
    }

    cout << "Done" << endl;
    return 0;
}

void testTutorialOne() {
    AnalyzeTool analyze1("PlotterTool.xml");
    analyze1.getModel().print("testAnalyzeTutorialOne.osim");
    analyze1.run();
    /* Once this runs to completion we'll make the test more meaningful by comparing output
    * to a validated standard. Let's make sure we don't crash during run first! -Ayman 5/29/12 */
    Storage resultFiberLength("testPlotterTool/BothLegs__FiberLength.sto");
    Storage standardFiberLength("std_BothLegs_fiberLength.sto");
    CHECK_STORAGE_AGAINST_STANDARD(resultFiberLength, standardFiberLength,
        std::vector<double>(100, 0.0001), __FILE__, __LINE__,
        "testAnalyzeTutorialOne failed");
    // const Model& mdl = analyze1.getModel();
    //mdl.updMultibodySystem()
    analyze1.setStatesFileName("plotterGeneratedStatesHip45.sto");
    //analyze1.setModel(mdl);
    analyze1.setName("BothLegsHip45");
    analyze1.run();
    Storage resultFiberLengthHip45("testPlotterTool/BothLegsHip45__FiberLength.sto");
    Storage standardFiberLength45("std_BothLegsHip45__FiberLength.sto");
    CHECK_STORAGE_AGAINST_STANDARD(resultFiberLengthHip45,
        standardFiberLength45, std::vector<double>(100, 0.0001),
        __FILE__, __LINE__, "testAnalyzeTutorialOne at Hip45 failed");
    cout << "testAnalyzeTutorialOne passed" << endl;
}

void testTugOfWar(const string& dataFileName, const double& defaultAct) {
    AnalyzeTool analyze("Tug_of_War_Setup_Analyze.xml");
    analyze.setCoordinatesFileName("");
    analyze.setStatesFileName("");

    // Access the model and muscle being analyzed
    Model& model = analyze.getModel();
    Millard2012EquilibriumMuscle& muscle =
        static_cast<Millard2012EquilibriumMuscle&>(model.updMuscles()[0]);
    bool isCoordinatesOnly = true;
    // Load in the States used to recompute the results of the Analysis
    Storage dataStore(dataFileName);
    if (dataStore.getColumnLabels().findIndex(muscle.getName() + ".activation") > 0) {
        isCoordinatesOnly = false;
        analyze.setStatesFileName(dataFileName);
        // ramp input starts at 0.0
        muscle.set_minimum_activation(0.0);
    }
    else {
        analyze.setCoordinatesFileName(dataFileName);
    }

    // Test that the default activation is taken into consideration by
    // the Analysis and reflected in the AnalyzeTool solution
    muscle.set_default_activation(defaultAct);

    analyze.run();

    // Load the AnalyzTool results for the muscle's force through time
    TimeSeriesTable_<double> results("Analyze_Tug_of_War/Tug_of_War_Millard_Iso_ForceReporter_forces.sto");
    assert(results.getNumColumns() == 1);
    SimTK::Vector forces = results.getDependentColumnAtIndex(0);

    TimeSeriesTable_<double> outputs_table("Analyze_Tug_of_War/Tug_of_War_Millard_Iso_Outputs.sto");
    SimTK::Vector tf_output = outputs_table.getDependentColumnAtIndex(1);

    // Load input data as StatesTrajectory used to perform the Analysis
    auto statesTraj = StatesTrajectory::createFromStatesStorage(
        model, dataStore, true, false);
    size_t nstates = statesTraj.getSize();

    // muscle active, passive, total muscle and tendon force quantities
    double af, pf, mf, tf, fl;
    af= pf = mf = tf = fl = SimTK::NaN;

    // Tolerance for muscle equilibrium solution
    const double equilTol = muscle.getMaxIsometricForce()*SimTK::SqrtEps;

    // The maximum acceptable change in force between two contiguous states
    const double maxDelta = muscle.getMaxIsometricForce() / 10;

    SimTK::State s = model.getWorkingState();
    // Independently compute the active fiber force at every state
    for (size_t i = 0; i < nstates; ++i) {
        s = statesTraj[i];
        // When the muscle states are not supplied in the input dataStore
        // (isCoordinatesOnly == true), then set it to its default value.
        if (isCoordinatesOnly) {
            muscle.setActivation(s, muscle.get_default_activation());
        }
        // technically, fiber lengths could be supplied, but this test case
        // (a typical use case) does not and therefore set to its default.
        muscle.setFiberLength(s, muscle.get_default_fiber_length());
        try {
            muscle.computeEquilibrium(s);
        }
        catch (const MuscleCannotEquilibrate& x) {
            // Write out the muscle equilibrium for error as a function of
            // fiber-length.
            reportTendonAndFiberForcesAcrossFiberLengths(muscle, s);
            throw x;
        }
        model.realizeDynamics(s);

        // Get the fiber-length
        fl = muscle.getFiberLength(s);

        cout << "t = " << s.getTime() << " | fiber_length = " << fl <<
           " : default_fiber_length = " << muscle.get_default_fiber_length() << endl;

        SimTK_ASSERT_ALWAYS(fl >= muscle.getMinimumFiberLength(),
            "Equilibrium failed to compute valid fiber length.");

        if (isCoordinatesOnly) {
            // check that activation is not reset to zero or other value
            SimTK_ASSERT_ALWAYS(muscle.getActivation(s) == defaultAct,
                "Test failed to correctly use the default activation value.");
        }
        else {
            // check that activation used was that supplied by the dataStore
            SimTK_ASSERT_ALWAYS(muscle.getActivation(s) == s.getTime(),
                "Test failed to correctly use the supplied activation values.");
        }

        // get active and passive forces given the default activation
        af = muscle.getActiveFiberForceAlongTendon(s);
        pf = muscle.getPassiveFiberForceAlongTendon(s);

        // now the total muscle force is the active + passive
        mf = af + pf;
        tf = muscle.getTendonForce(s);

        // equilibrium demands tendon and muscle fiber are equivalent
        ASSERT_EQUAL<double>(tf, mf, equilTol);
        // Verify that the current computed and AnalyzeTool reported force are
        // equivalent for the provided motion file
        cout << s.getTime() << " :: muscle-fiber-force: " << mf <<
            " Analyze reported force: " << forces[int(i)] << endl;
        ASSERT_EQUAL<double>(mf, forces[int(i)], equilTol, __FILE__, __LINE__,
            "Total fiber force failed to match reported muscle force.");

        cout << s.getTime() << " :: tendon-force: " << tf <<
            " Analyze Output reported: " << tf_output[int(i)] << endl;
        ASSERT_EQUAL<double>(tf, tf_output[int(i)], equilTol,
            __FILE__, __LINE__,
            "Output reported muscle-tendon force failed to match computed.");

        double delta = (i > 0) ? abs(forces[int(i)]-forces[int(i-1)]) : 0;

        SimTK_ASSERT_ALWAYS(delta < maxDelta,
            "Force trajectory has unexplained discontinuity.");
    }
}

void testActuationAnalysisWithDisabledForce() {
    AnalyzeTool analyze("PlotterTool.xml");
    Model& model = analyze.getModel();
    auto& muscle = model.updMuscles()[0];
    muscle.set_appliesForce(false);

    std::string resultsDir = "testPlotterToolWithDisabledForce";
    analyze.setResultsDir(resultsDir);
    analyze.run();

    // Reading a file with mismatched nColumns header and actual number of
    // data columns will throw.
    TimeSeriesTable_<double> act_force_table(
            resultsDir + "/BothLegs_Actuation_force.sto");

    // Let's also check that the number of columns is correct (i.e.,
    // (number of muscles in the model) - 1).
    ASSERT_EQUAL(model.getMuscles().getSize() - 1,
            (int)act_force_table.getNumColumns());
}

void testBodyKinematics() {
    Model model;
    model.setGravity(SimTK::Vec3(0));
    Body body("body", 1, SimTK::Vec3(0), SimTK::Inertia(1));
    model.addBody(&body);

    // Rotate child frame so that planar rotational joint is about
    // the body's local X axis, and the ground's Z axis
    FreeJoint joint("joint",
        model.getGround(), SimTK::Vec3(0), SimTK::Vec3(0),
        body, SimTK::Vec3(0), SimTK::Vec3(0, SimTK::Pi/2, 0));
    model.addJoint(&joint);
    model.finalizeConnections();

    BodyKinematics bodyKinematicsLocal;
    bodyKinematicsLocal.setName("local");
    bodyKinematicsLocal.setExpressResultsInLocalFrame(true);
    bodyKinematicsLocal.setInDegrees(true);

    BodyKinematics bodyKinematicsGround;
    bodyKinematicsGround.setName("ground");
    bodyKinematicsGround.setExpressResultsInLocalFrame(false);
    bodyKinematicsGround.setInDegrees(false);

    model.addAnalysis(&bodyKinematicsLocal);
    model.addAnalysis(&bodyKinematicsGround);

    SimTK::State& s = model.initSystem();
    double speedRot = 1.0;
    double speedX = 2.0;
    double speedY = 3.0;
    joint.updCoordinate(FreeJoint::Coord::Rotation3Z)
            .setSpeedValue(s, speedRot);
    joint.updCoordinate(FreeJoint::Coord::TranslationX)
            .setSpeedValue(s, speedX);
    joint.updCoordinate(FreeJoint::Coord::TranslationY)
            .setSpeedValue(s, speedY);

    Manager manager(model);
    double duration = 2.0;
    manager.initialize(s);
    s = manager.integrate(duration);

    bodyKinematicsLocal.printResults("BodyKinematics");
    bodyKinematicsGround.printResults("BodyKinematics");

    Storage localVel("BodyKinematics_local_vel_bodyLocal.sto");
    Storage groundVel("BodyKinematics_ground_vel_global.sto");
    Array<double> localVelOx, localVelOz, groundVelOx, groundVelOz;
    localVel.getDataColumn("body_Ox", localVelOx);
    localVel.getDataColumn("body_Oz", localVelOz);
    groundVel.getDataColumn("body_Ox", groundVelOx);
    groundVel.getDataColumn("body_Oz", groundVelOz);

    double tol = 1e-6;
    ASSERT_EQUAL<double>(localVelOx.getLast(), speedRot * SimTK_RADIAN_TO_DEGREE, tol);
    ASSERT_EQUAL<double>(localVelOz.getLast(), 0, tol);
    ASSERT_EQUAL<double>(groundVelOx.getLast(), 0, tol);
    ASSERT_EQUAL<double>(groundVelOz.getLast(), speedRot, tol);

    Array<double> groundPosX, groundPosY;
    Storage groundPos("BodyKinematics_ground_pos_global.sto");
    groundPos.getDataColumn("body_X", groundPosX);
    groundPos.getDataColumn("body_Y", groundPosY);
    ASSERT_EQUAL<double>(groundPosX.getLast(), speedX * duration, tol);
    ASSERT_EQUAL<double>(groundPosY.getLast(), speedY * duration, tol);
}
<|endoftext|>


<commit_before>/*
 The MIT License (MIT)

 Copyright (c) [2016] [BTC.COM]

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <err.h>
#include <errno.h>
#include <unistd.h>

#include <iostream>

#include <glog/logging.h>
#include <libconfig.h++>

#include "zmq.hpp"

#include "Utils.h"
#include "GbtMaker.h"

using namespace std;
using namespace libconfig;

GbtMaker *gGbtMaker = nullptr;

void handler(int sig) {
  if (gGbtMaker) {
    gGbtMaker->stop();
  }
}

void usage() {
  fprintf(stderr, "Usage:\n\tgbtmaker -c \"gbtmaker.cfg\" -l \"log_dir\"\n");
}

int main(int argc, char **argv) {
  char *optLogDir = NULL;
  char *optConf   = NULL;
  int c;

  if (argc <= 1) {
    usage();
    return 1;
  }
  while ((c = getopt(argc, argv, "c:l:h")) != -1) {
    switch (c) {
      case 'c':
        optConf = optarg;
        break;
      case 'l':
        optLogDir = optarg;
        break;
      case 'h': default:
        usage();
        exit(0);
    }
  }

  // Initialize Google's logging library.
  google::InitGoogleLogging(argv[0]);
  FLAGS_log_dir = string(optLogDir);
  FLAGS_max_log_size = 100;  // max log file size 100 MB
  FLAGS_logbuflevel = -1;
  FLAGS_stop_logging_if_full_disk = true;

  // Read the file. If there is an error, report it and exit.
  Config cfg;
  try
  {
    cfg.readFile(optConf);
  } catch(const FileIOException &fioex) {
    std::cerr << "I/O error while reading file." << std::endl;
    return(EXIT_FAILURE);
  } catch(const ParseException &pex) {
    std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
    << " - " << pex.getError() << std::endl;
    return(EXIT_FAILURE);
  }

  signal(SIGTERM, handler);
  signal(SIGINT,  handler);

  int32_t rpcCallInterval = 5;
  cfg.lookupValue("gbtmaker.rpcinterval", rpcCallInterval);
  gGbtMaker = new GbtMaker(cfg.lookup("bitcoind.zmq_addr"),
                           cfg.lookup("bitcoind.rpc_addr"),
                           cfg.lookup("bitcoind.rpc_userpwd"),
                           cfg.lookup("kafka.brokers"),
                           rpcCallInterval);

  try {
    if (!gGbtMaker->init()) {
      LOG(FATAL) << "gbtmaker init failure";
    }
    gGbtMaker->run();
    delete gGbtMaker;
  } catch (std::exception & e) {
    LOG(FATAL) << "exception: " << e.what();
    return 1;
  }

  google::ShutdownGoogleLogging();
  return 0;
}
<commit_msg>add lock cfg file<commit_after>/*
 The MIT License (MIT)

 Copyright (c) [2016] [BTC.COM]

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <err.h>
#include <errno.h>
#include <unistd.h>

#include <iostream>

#include <boost/interprocess/sync/file_lock.hpp>
#include <glog/logging.h>
#include <libconfig.h++>

#include "zmq.hpp"

#include "Utils.h"
#include "GbtMaker.h"

using namespace std;
using namespace libconfig;

GbtMaker *gGbtMaker = nullptr;

void handler(int sig) {
  if (gGbtMaker) {
    gGbtMaker->stop();
  }
}

void usage() {
  fprintf(stderr, "Usage:\n\tgbtmaker -c \"gbtmaker.cfg\" -l \"log_dir\"\n");
}

int main(int argc, char **argv) {
  char *optLogDir = NULL;
  char *optConf   = NULL;
  int c;

  if (argc <= 1) {
    usage();
    return 1;
  }
  while ((c = getopt(argc, argv, "c:l:h")) != -1) {
    switch (c) {
      case 'c':
        optConf = optarg;
        break;
      case 'l':
        optLogDir = optarg;
        break;
      case 'h': default:
        usage();
        exit(0);
    }
  }

  // Initialize Google's logging library.
  google::InitGoogleLogging(argv[0]);
  FLAGS_log_dir = string(optLogDir);
  FLAGS_max_log_size = 100;  // max log file size 100 MB
  FLAGS_logbuflevel = -1;
  FLAGS_stop_logging_if_full_disk = true;

  // Read the file. If there is an error, report it and exit.
  Config cfg;
  try
  {
    cfg.readFile(optConf);
  } catch(const FileIOException &fioex) {
    std::cerr << "I/O error while reading file." << std::endl;
    return(EXIT_FAILURE);
  } catch(const ParseException &pex) {
    std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
    << " - " << pex.getError() << std::endl;
    return(EXIT_FAILURE);
  }

  // lock cfg file:
  //    you can't run more than one progress with the same config file
  boost::interprocess::file_lock pidFileLock(optConf);
  if (pidFileLock.try_lock() == false) {
    LOG(FATAL) << "lock cfg file fail";
    return(EXIT_FAILURE);
  }

  signal(SIGTERM, handler);
  signal(SIGINT,  handler);

  int32_t rpcCallInterval = 5;
  cfg.lookupValue("gbtmaker.rpcinterval", rpcCallInterval);
  gGbtMaker = new GbtMaker(cfg.lookup("bitcoind.zmq_addr"),
                           cfg.lookup("bitcoind.rpc_addr"),
                           cfg.lookup("bitcoind.rpc_userpwd"),
                           cfg.lookup("kafka.brokers"),
                           rpcCallInterval);

  try {
    if (!gGbtMaker->init()) {
      LOG(FATAL) << "gbtmaker init failure";
    }
    gGbtMaker->run();
    delete gGbtMaker;
  } catch (std::exception & e) {
    LOG(FATAL) << "exception: " << e.what();
    return 1;
  }

  google::ShutdownGoogleLogging();
  return 0;
}
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "extproc/spawner.hpp"

#include <signal.h>

#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>

#include "arch/fd_send_recv.hpp"
#include "extproc/job.hpp"
#include "utils.hpp"

namespace extproc {

void exec_spawner(fd_t socket) NORETURN;
void exec_worker(pid_t spawner_pid, fd_t socket) NORETURN;

// Checks that we only create one spawner. This is an ugly restriction, but it
// means we can put the SIGCHLD-handling logic in here, so that it is properly
// scoped to the lifetime of the spawner.
//
// TODO(rntz): More general way of handling SIGCHLD.
static pid_t spawner_pid = -1;

static void sigchld_handler(int signo) {
    guarantee(signo == SIGCHLD);
    guarantee(spawner_pid > 0);

    int status;
    pid_t pid = waitpid(-1, &status, WNOHANG);
    guarantee_err(-1 != pid, "could not waitpid()");

    // We might spawn processes other than the spawner, whose deaths we ignore.
    // waitpid() might also return 0, indicating some event other than child
    // process termination (ie. SIGSTOP or SIGCONT). We ignore this.
    if (pid == spawner_pid) {
        crash_or_trap("Spawner process died!");
    }
}

spawner_t::spawner_t(info_t *info)
    : pid_(info->pid), socket_(&info->socket)
{
    guarantee(-1 == spawner_pid);
    spawner_pid = pid_;

    // Check that the spawner hasn't already exited.
    guarantee(0 == waitpid(pid_, NULL, WNOHANG),
              "spawner process already died!");

    // Establish SIGCHLD handler for spawner.
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = sigchld_handler;
    guarantee_err(0 == sigemptyset(&act.sa_mask), "could not empty signal mask");
    guarantee_err(0 == sigaction(SIGCHLD, &act, NULL), "could not set SIGCHLD handler");
}

spawner_t::~spawner_t() {
    // De-establish SIGCHLD handler.
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = SIG_DFL;
    guarantee_err(0 == sigemptyset(&act.sa_mask), "could not empty signal mask");
    guarantee_err(0 == sigaction(SIGCHLD, &act, NULL), "could not unset SIGCHLD handler");

    guarantee(spawner_pid > 0);
    spawner_pid = -1;
}

void spawner_t::create(info_t *info) {
    int fds[2];
    guarantee_err(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fds),
                  "could not create socketpair for spawner");

    pid_t pid = fork();
    guarantee_err(-1 != pid, "could not fork spawner process");

    if (0 == pid) {
        // We're the child; run the spawner.
        guarantee_err(0 == close(fds[0]), "could not close fd");
        exec_spawner(fds[1]);
        unreachable();
    }

    // We're the parent. Return.
    guarantee_err(0 == close(fds[1]), "could not close fd");
    info->pid = pid;
    info->socket.reset(fds[0]);
}

pid_t spawner_t::spawn_process(scoped_fd_t *socket) {
    assert_thread();

    // Create a socket pair.
    fd_t fds[2];
    int res = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
    if (res) return -1;

    // We need to send the fd & receive the pid atomically with respect to other
    // calls to spawn_process().
    mutex_t::acq_t lock(&mutex_);

    // Send one half to the spawner process.
    guarantee(0 == socket_.send_fd(fds[1]));
    guarantee_err(0 == close(fds[1]), "could not close fd");
    socket->reset(fds[0]);

    // Receive the pid from the spawner process.
    pid_t pid;
    guarantee(sizeof(pid) == force_read(&socket_, &pid, sizeof(pid)));
    guarantee(pid > 0);

    return pid;
}

// ---------- Spawner & worker processes ----------
// Runs the spawner process. Does not return.
void exec_spawner(fd_t socket) {
    // We set our PGID to our own PID (rather than inheriting our parent's PGID)
    // so that a signal (eg. SIGINT) sent to the parent's PGID (by eg. hitting
    // Ctrl-C at a terminal) will not propagate to us or our children.
    //
    // This is desirable because the RethinkDB engine deliberately crashes with
    // an error message if the spawner or a worker process dies; but a
    // command-line SIGINT should trigger a clean shutdown, not a crash.
    //
    // TODO(rntz): This is an ugly, hackish way to handle the problem.
    guarantee_err(0 == setpgid(0, 0), "spawner: could not set PGID");

    // We ignore SIGCHLD so that we don't accumulate zombie children.
    {
        // NB. According to `man 2 sigaction` on linux, POSIX.1-2001 says that
        // this will prevent zombies, but may not be "fully portable".
        struct sigaction act;
        memset(&act, 0, sizeof(act));
        act.sa_handler = SIG_IGN;

        guarantee_err(0 == sigaction(SIGCHLD, &act, NULL),
                      "spawner: Could not ignore SIGCHLD");
    }

    pid_t spawner_pid = getpid();

    for (;;) {
        // Get an fd from our parent.
        fd_t fd;
        fd_recv_result_t fdres = recv_fds(socket, 1, &fd);
        if (fdres == FD_RECV_EOF) {
            // Other end shut down cleanly; we should too.
            exit(EXIT_SUCCESS);
        } else if (fdres != FD_RECV_OK) {
            exit(EXIT_FAILURE);
        }

        // Fork a worker process.
        pid_t pid = fork();
        if (-1 == pid)
            exit(EXIT_FAILURE);

        if (0 == pid) {
            // We're the child/worker.
            guarantee_err(0 == close(socket), "worker: could not close fd");
            exec_worker(spawner_pid, fd);
            unreachable();
        }

        // We're the parent.
        guarantee_err(0 == close(fd), "spawner: couldn't close fd");

        // Send back its pid. Wish we could use unix_socket_stream_t for this,
        // but its destructor calls shutdown(), and we can't have that happening
        // in the worker child.
        const char *buf = reinterpret_cast<const char *>(&pid);
        size_t sz = sizeof(pid);
        while (sz) {
            ssize_t w = write(socket, buf, sz);
            if (w == -1 && errno == EINTR) continue;
            guarantee_err(w > 0, "spawner: could not write() to engine socket");
            guarantee((size_t)w <= sz);
            sz -= w, buf += w;
        }
    }
}

#ifdef __MACH__
// On OS X, we have to poll the ppid to detect when the parent process dies.  So we use SIGALRM and
// setitimer to do that.  (We could also use kqueue to do this without polling, in a separate
// thread.  We could also just make a separate thread and poll from it.)  We have to make this
// global variable because setitimer doesn't let you pass the value through a siginfo_t parameter.
pid_t spawner_pid_for_sigalrm = 0;

void check_ppid_for_death(int) {
    pid_t ppid = getppid();
    std::string s = strprintf("sigalrm: rdb_pid=%d, ppid=%d\n", spawner_pid_for_sigalrm, ppid);
    write(STDOUT_FILENO, s.data(), s.size());

    if (spawner_pid_for_sigalrm != 0 && spawner_pid_for_sigalrm != ppid) {
        write(STDOUT_FILENO, "crap\n", 5);
        // We didn't fail, so should we exit with failure?  This status code doesn't really matter.
        _exit(EXIT_FAILURE);
    }
}
#endif  // __MACH__

// Runs the worker process. Does not return.
void exec_worker(pid_t spawner_pid, fd_t sockfd) {
    // Make sure we die when our parent dies.  (The parent, the spawner process, dies when the
    // rethinkdb process dies.)
    {
        debugf("exec_worker, setting rdb_pid_for_sigalrm to %d\n", spawner_pid);
        spawner_pid_for_sigalrm = spawner_pid;

        struct sigaction sa;
        memset(&sa, 0, sizeof(struct sigaction));
        sa.sa_handler = check_ppid_for_death;
        int res = sigfillset(&sa.sa_mask);
        guarantee_err(res == 0, "worker: sigfillset failed");
        res = sigaction(SIGALRM, &sa, NULL);
        guarantee_err(res == 0, "worker: could not set action for ALRM signal");

        struct itimerval timerval;
        timerval.it_interval.tv_sec = 0;
        timerval.it_interval.tv_usec = 500 * THOUSAND;
        timerval.it_value = timerval.it_interval;
        struct itimerval old_timerval;
        res = setitimer(ITIMER_REAL, &timerval, &old_timerval);
        guarantee_err(res == 0, "worker: setitimer failed");
        guarantee(old_timerval.it_value.tv_sec == 0 && old_timerval.it_value.tv_usec == 0,
                  "worker: setitimer saw that we already had an itimer!");
    }

    // Receive one job and run it.
    scoped_fd_t fd(sockfd);
    job_t::control_t control(getpid(), spawner_pid, &fd);
    exit(job_t::accept_job(&control, NULL));
}

} // namespace extproc
<commit_msg>Removed some temporary debugf statements and such in the extproc code.<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "extproc/spawner.hpp"

#include <signal.h>

#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>

#include "arch/fd_send_recv.hpp"
#include "extproc/job.hpp"
#include "utils.hpp"

namespace extproc {

void exec_spawner(fd_t socket) NORETURN;
void exec_worker(pid_t spawner_pid, fd_t socket) NORETURN;

// Checks that we only create one spawner. This is an ugly restriction, but it
// means we can put the SIGCHLD-handling logic in here, so that it is properly
// scoped to the lifetime of the spawner.
//
// TODO(rntz): More general way of handling SIGCHLD.
static pid_t spawner_pid = -1;

static void sigchld_handler(int signo) {
    guarantee(signo == SIGCHLD);
    guarantee(spawner_pid > 0);

    int status;
    pid_t pid = waitpid(-1, &status, WNOHANG);
    guarantee_err(-1 != pid, "could not waitpid()");

    // We might spawn processes other than the spawner, whose deaths we ignore.
    // waitpid() might also return 0, indicating some event other than child
    // process termination (ie. SIGSTOP or SIGCONT). We ignore this.
    if (pid == spawner_pid) {
        crash_or_trap("Spawner process died!");
    }
}

spawner_t::spawner_t(info_t *info)
    : pid_(info->pid), socket_(&info->socket)
{
    guarantee(-1 == spawner_pid);
    spawner_pid = pid_;

    // Check that the spawner hasn't already exited.
    guarantee(0 == waitpid(pid_, NULL, WNOHANG),
              "spawner process already died!");

    // Establish SIGCHLD handler for spawner.
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = sigchld_handler;
    guarantee_err(0 == sigemptyset(&act.sa_mask), "could not empty signal mask");
    guarantee_err(0 == sigaction(SIGCHLD, &act, NULL), "could not set SIGCHLD handler");
}

spawner_t::~spawner_t() {
    // De-establish SIGCHLD handler.
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = SIG_DFL;
    guarantee_err(0 == sigemptyset(&act.sa_mask), "could not empty signal mask");
    guarantee_err(0 == sigaction(SIGCHLD, &act, NULL), "could not unset SIGCHLD handler");

    guarantee(spawner_pid > 0);
    spawner_pid = -1;
}

void spawner_t::create(info_t *info) {
    int fds[2];
    guarantee_err(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fds),
                  "could not create socketpair for spawner");

    pid_t pid = fork();
    guarantee_err(-1 != pid, "could not fork spawner process");

    if (0 == pid) {
        // We're the child; run the spawner.
        guarantee_err(0 == close(fds[0]), "could not close fd");
        exec_spawner(fds[1]);
        unreachable();
    }

    // We're the parent. Return.
    guarantee_err(0 == close(fds[1]), "could not close fd");
    info->pid = pid;
    info->socket.reset(fds[0]);
}

pid_t spawner_t::spawn_process(scoped_fd_t *socket) {
    assert_thread();

    // Create a socket pair.
    fd_t fds[2];
    int res = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
    if (res) return -1;

    // We need to send the fd & receive the pid atomically with respect to other
    // calls to spawn_process().
    mutex_t::acq_t lock(&mutex_);

    // Send one half to the spawner process.
    guarantee(0 == socket_.send_fd(fds[1]));
    guarantee_err(0 == close(fds[1]), "could not close fd");
    socket->reset(fds[0]);

    // Receive the pid from the spawner process.
    pid_t pid;
    guarantee(sizeof(pid) == force_read(&socket_, &pid, sizeof(pid)));
    guarantee(pid > 0);

    return pid;
}

// ---------- Spawner & worker processes ----------
// Runs the spawner process. Does not return.
void exec_spawner(fd_t socket) {
    // We set our PGID to our own PID (rather than inheriting our parent's PGID)
    // so that a signal (eg. SIGINT) sent to the parent's PGID (by eg. hitting
    // Ctrl-C at a terminal) will not propagate to us or our children.
    //
    // This is desirable because the RethinkDB engine deliberately crashes with
    // an error message if the spawner or a worker process dies; but a
    // command-line SIGINT should trigger a clean shutdown, not a crash.
    //
    // TODO(rntz): This is an ugly, hackish way to handle the problem.
    guarantee_err(0 == setpgid(0, 0), "spawner: could not set PGID");

    // We ignore SIGCHLD so that we don't accumulate zombie children.
    {
        // NB. According to `man 2 sigaction` on linux, POSIX.1-2001 says that
        // this will prevent zombies, but may not be "fully portable".
        struct sigaction act;
        memset(&act, 0, sizeof(act));
        act.sa_handler = SIG_IGN;

        guarantee_err(0 == sigaction(SIGCHLD, &act, NULL),
                      "spawner: Could not ignore SIGCHLD");
    }

    pid_t spawner_pid = getpid();

    for (;;) {
        // Get an fd from our parent.
        fd_t fd;
        fd_recv_result_t fdres = recv_fds(socket, 1, &fd);
        if (fdres == FD_RECV_EOF) {
            // Other end shut down cleanly; we should too.
            exit(EXIT_SUCCESS);
        } else if (fdres != FD_RECV_OK) {
            exit(EXIT_FAILURE);
        }

        // Fork a worker process.
        pid_t pid = fork();
        if (-1 == pid)
            exit(EXIT_FAILURE);

        if (0 == pid) {
            // We're the child/worker.
            guarantee_err(0 == close(socket), "worker: could not close fd");
            exec_worker(spawner_pid, fd);
            unreachable();
        }

        // We're the parent.
        guarantee_err(0 == close(fd), "spawner: couldn't close fd");

        // Send back its pid. Wish we could use unix_socket_stream_t for this,
        // but its destructor calls shutdown(), and we can't have that happening
        // in the worker child.
        const char *buf = reinterpret_cast<const char *>(&pid);
        size_t sz = sizeof(pid);
        while (sz) {
            ssize_t w = write(socket, buf, sz);
            if (w == -1 && errno == EINTR) continue;
            guarantee_err(w > 0, "spawner: could not write() to engine socket");
            guarantee((size_t)w <= sz);
            sz -= w, buf += w;
        }
    }
}

#ifdef __MACH__
// On OS X, we have to poll the ppid to detect when the parent process dies.  So we use SIGALRM and
// setitimer to do that.  (We could also use kqueue to do this without polling, in a separate
// thread.  We could also just make a separate thread and poll from it.)  We have to make this
// global variable because setitimer doesn't let you pass the value through a siginfo_t parameter.
pid_t spawner_pid_for_sigalrm = 0;

void check_ppid_for_death(int) {
    pid_t ppid = getppid();
    if (spawner_pid_for_sigalrm != 0 && spawner_pid_for_sigalrm != ppid) {
        // We didn't fail, so should we exit with failure?  This status code doesn't really matter.
        _exit(EXIT_FAILURE);
    }
}
#endif  // __MACH__

// Runs the worker process. Does not return.
void exec_worker(pid_t spawner_pid, fd_t sockfd) {
    // Make sure we die when our parent dies.  (The parent, the spawner process, dies when the
    // rethinkdb process dies.)
    {
        spawner_pid_for_sigalrm = spawner_pid;

        struct sigaction sa;
        memset(&sa, 0, sizeof(struct sigaction));
        sa.sa_handler = check_ppid_for_death;
        int res = sigfillset(&sa.sa_mask);
        guarantee_err(res == 0, "worker: sigfillset failed");
        res = sigaction(SIGALRM, &sa, NULL);
        guarantee_err(res == 0, "worker: could not set action for ALRM signal");

        struct itimerval timerval;
        timerval.it_interval.tv_sec = 0;
        timerval.it_interval.tv_usec = 500 * THOUSAND;
        timerval.it_value = timerval.it_interval;
        struct itimerval old_timerval;
        res = setitimer(ITIMER_REAL, &timerval, &old_timerval);
        guarantee_err(res == 0, "worker: setitimer failed");
        guarantee(old_timerval.it_value.tv_sec == 0 && old_timerval.it_value.tv_usec == 0,
                  "worker: setitimer saw that we already had an itimer!");
    }

    // Receive one job and run it.
    scoped_fd_t fd(sockfd);
    job_t::control_t control(getpid(), spawner_pid, &fd);
    exit(job_t::accept_job(&control, NULL));
}

} // namespace extproc
<|endoftext|>


<commit_before>// -*- c++ -*-
// Program to extract word cooccurrence counts from a memory-mapped word-aligned bitext
// stores the counts lexicon in the format for mm2dTable<uint32_t> (ug_mm_2d_table.h)
// (c) 2010-2012 Ulrich Germann

#include <queue>
#include <iomanip>
#include <vector>
#include <iterator>
#include <sstream>

#include <boost/program_options.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
#include <boost/math/distributions/binomial.hpp>

#include "moses/TranslationModel/UG/generic/program_options/ug_get_options.h"
// #include "ug_translation_finder.h"
// #include "ug_sorters.h"
// #include "ug_corpus_sampling.h"
#include "ug_mm_2d_table.h"
#include "ug_mm_ttrack.h"
#include  "ug_corpus_token.h"

using namespace std;
using namespace ugdiss;
using namespace boost::math;

typedef mm2dTable<id_type,id_type,uint32_t,uint32_t> LEX_t;
typedef SimpleWordId Token;

vector<uint32_t> m1; // marginals L1
vector<uint32_t> m2; // marginals L2

id_type first_rare_id=500;
vector<vector<uint32_t> >      JFREQ; // joint count table for frequent L1 words
vector<map<id_type,uint32_t> > JRARE; // joint count table for rare     L1 words

mmTtrack<Token> T1,T2;
mmTtrack<char>     Tx;
TokenIndex      V1,V2;

string bname,cfgFile,L1,L2,oname;

// DECLARATIONS
void interpret_args(int ac, char* av[]);

void
processSentence(id_type sid)
{
  Token const* s1 = T1.sntStart(sid);
  Token const* s2 = T2.sntStart(sid);
  char const* p  = Tx.sntStart(sid);
  char const* q  = Tx.sntEnd(sid);
  ushort r,c;
  bitvector check1(T1.sntLen(sid)), check2(T2.sntLen(sid));
  check1.set();
  check2.set();

  // count links
  while (p < q)
    {
      p = binread(p,r);
      p = binread(p,c);
      check1.reset(r);
      check2.reset(c);
      id_type id1 = (s1+r)->id();
      if (id1 < first_rare_id) JFREQ[id1][(s2+c)->id()]++;
      else                     JRARE[id1][(s2+c)->id()]++;
    }

  // count unaliged words
  for (size_t i = check1.find_first(); i < check1.size(); i = check1.find_next(i))
    {
      id_type id1 = (s1+i)->id();
      if (id1 < first_rare_id) JFREQ[id1][0]++;
      else                     JRARE[id1][0]++;
    }
  for (size_t i = check2.find_first(); i < check2.size(); i = check2.find_next(i))
    JFREQ[0][(s2+i)->id()]++;
}

void
makeTable(string ofname)
{
  ofstream out(ofname.c_str());
  filepos_type idxOffset=0;
  m1.resize(max(first_rare_id,V1.getNumTokens()),0);
  m2.resize(V2.getNumTokens(),0);
  JFREQ.resize(first_rare_id,vector<uint32_t>(m2.size(),0));
  JRARE.resize(m1.size());
  for (size_t sid = 0; sid < T1.size(); ++sid)
    processSentence(sid);

  vector<id_type> index(V1.getNumTokens()+1,0);
  numwrite(out,idxOffset); // blank for the time being
  numwrite(out,id_type(m1.size()));
  numwrite(out,id_type(m2.size()));

  id_type cellCount=0;
  id_type stop = min(first_rare_id,id_type(m1.size()));
  for (id_type id1 = 0; id1 < stop; ++id1)
    {
      index[id1]  = cellCount;
      vector<uint32_t> const& v = JFREQ[id1];
      for (id_type id2 = 0; id2 < id_type(v.size()); ++id2)
        {
          if (!v[id2]) continue;
          cellCount++;
          numwrite(out,id2);
          out.write(reinterpret_cast<char const*>(&v[id2]),sizeof(uint32_t));
          m1[id1] += v[id2];
          m2[id2] += v[id2];
        }
    }
  for (id_type id1 = stop; id1 < id_type(m1.size()); ++id1)
    {
      index[id1]  = cellCount;
      map<id_type,uint32_t> const& M = JRARE[id1];
      for (map<id_type,uint32_t>::const_iterator m = M.begin(); m != M.end(); ++m)
        {
          if (m->second == 0) continue;
          cellCount++;
          numwrite(out,m->first);
          out.write(reinterpret_cast<char const*>(&m->second),sizeof(float));
          m1[id1] += m->second;
          m2[m->first] += m->second;
        }
    }
  index[m1.size()] = cellCount;
  idxOffset    = out.tellp();
  for (size_t i = 0; i < index.size(); ++i)
    numwrite(out,index[i]);
  out.write(reinterpret_cast<char const*>(&m1[0]),m1.size()*sizeof(float));
  out.write(reinterpret_cast<char const*>(&m2[0]),m2.size()*sizeof(float));

  // re-write the file header
  out.seekp(0);
  numwrite(out,idxOffset);
  out.close();
}

int
main(int argc, char* argv[])
{
  interpret_args(argc,argv);
  char c = *bname.rbegin();
  if (c != '/' && c != '.') bname += '.';
  T1.open(bname+L1+".mct");
  T2.open(bname+L2+".mct");
  Tx.open(bname+L1+"-"+L2+".mam");
  V1.open(bname+L1+".tdx");
  V2.open(bname+L2+".tdx");
  makeTable(oname);
  exit(0);
}

void
interpret_args(int ac, char* av[])
{
  namespace po=boost::program_options;
  po::variables_map vm;
  po::options_description o("Options");
  po::options_description h("Hidden Options");
  po::positional_options_description a;

  o.add_options()
    ("help,h",    "print this message")
    ("cfg,f", po::value<string>(&cfgFile),"config file")
    ("oname,o", po::value<string>(&oname),"output file name")
    ;

  h.add_options()
    ("bname", po::value<string>(&bname), "base name")
    ("L1",    po::value<string>(&L1),"L1 tag")
    ("L2",    po::value<string>(&L2),"L2 tag")
    ;
  a.add("bname",1);
  a.add("L1",1);
  a.add("L2",1);
  get_options(ac,av,h.add(o),a,vm,"cfg");

  if (vm.count("help") || bname.empty() || oname.empty())
    {
      cout << "usage:\n\t" << av[0] << " <basename> <L1 tag> <L2 tag> -o <output file>\n" << endl;
      cout << o << endl;
      exit(0);
    }
}

<commit_msg>Added option to also count raw cooccurrences.<commit_after>// -*- c++ -*-
// Program to extract word cooccurrence counts from a memory-mapped word-aligned bitext
// stores the counts lexicon in the format for mm2dTable<uint32_t> (ug_mm_2d_table.h)
// (c) 2010-2012 Ulrich Germann

#include <queue>
#include <iomanip>
#include <vector>
#include <iterator>
#include <sstream>

#include <boost/program_options.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
#include <boost/math/distributions/binomial.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>

#include "moses/TranslationModel/UG/generic/program_options/ug_get_options.h"
// #include "ug_translation_finder.h"
// #include "ug_sorters.h"
// #include "ug_corpus_sampling.h"
#include "ug_mm_2d_table.h"
#include "ug_mm_ttrack.h"
#include  "ug_corpus_token.h"

using namespace std;
using namespace ugdiss;
using namespace boost::math;

typedef mm2dTable<id_type,id_type,uint32_t,uint32_t> LEX_t;
typedef SimpleWordId Token;

id_type first_rare_id=500;
vector<vector<uint32_t> >      JFREQ; // joint count table for frequent L1 words
vector<map<id_type,uint32_t> > JRARE; // joint count table for rare     L1 words
vector<vector<uint32_t> >      CFREQ; // cooc count table for frequent L1 words
vector<map<id_type,uint32_t> > CRARE; // cooc count table for rare     L1 words

mmTtrack<Token> T1,T2;
mmTtrack<char>     Tx;
TokenIndex      V1,V2;

string bname,cfgFile,L1,L2,oname,cooc;

// DECLARATIONS
void interpret_args(int ac, char* av[]);

void
processSentence(id_type sid)
{
  Token const* s1 = T1.sntStart(sid);
  Token const* e1 = T1.sntEnd(sid);
  Token const* s2 = T2.sntStart(sid);
  Token const* e2 = T2.sntEnd(sid);
  char const* p  = Tx.sntStart(sid);
  char const* q  = Tx.sntEnd(sid);
  ushort r,c;
  bitvector check1(T1.sntLen(sid)), check2(T2.sntLen(sid));
  check1.set();
  check2.set();
  vector<ushort> cnt1(V1.ksize(),0);
  vector<ushort> cnt2(V2.ksize(),0);
  boost::unordered_set<pair<id_type,id_type> > mycoocs;

  for (Token const* x = s1; x < e1; ++x) ++cnt1[x->id()];
  for (Token const* x = s2; x < e2; ++x) ++cnt2[x->id()];

  // count links
  while (p < q)
    {
      p = binread(p,r);
      p = binread(p,c);
      check1.reset(r);
      check2.reset(c);
      id_type id1 = (s1+r)->id();
      id_type id2 = (s2+c)->id();
      if (id1 < first_rare_id)
	JFREQ[id1][id2]++;
      else
	JRARE[id1][id2]++;
      if (cooc.size())
	mycoocs.insert(pair<id_type,id_type>(id1,id2));
    }
  // count unaliged words
  for (size_t i = check1.find_first(); i < check1.size(); i = check1.find_next(i))
    {
      id_type id1 = (s1+i)->id();
      if (id1 < first_rare_id) JFREQ[id1][0]++;
      else                     JRARE[id1][0]++;
    }
  for (size_t i = check2.find_first(); i < check2.size(); i = check2.find_next(i))
    JFREQ[0][(s2+i)->id()]++;

  if (cooc.size())
    {
      typedef boost::unordered_set<pair<id_type,id_type> >::iterator iter;
      for (iter m = mycoocs.begin(); m != mycoocs.end(); ++m)
	if (m->first < first_rare_id)
	  CFREQ[m->first][m->second] += cnt1[m->first] * cnt2[m->second];
	else
	  CRARE[m->first][m->second] += cnt1[m->first] * cnt2[m->second];
    }
}

// void
// count_coocs(id_type sid)
// {
//   Token const* s1 = T1.sntStart(sid);
//   Token const* e1 = T1.sntEnd(sid);

//   Token const* s2 = T2.sntStart(sid);
//   Token const* e2 = T2.sntEnd(sid);

//   for (Token const* x = s1; x < e1; ++x)
//     {
//       if (x->id() < first_rare_id)
// 	{
// 	  vector<uint32_t>& v = CFREQ[x->id()];
// 	  for (Token const* y = s2; y < e2; ++y)
// 	    ++v[y->id()];
// 	}
//       else
// 	{
// 	  map<id_type,uint32_t>& m = CRARE[x->id()];
// 	  for (Token const* y = s2; y < e2; ++y)
// 	    ++m[y->id()];
// 	}
//     }
// }

void
writeTable(string ofname, vector<vector<uint32_t> >& FREQ,
	   vector<map<id_type,uint32_t> >& RARE)
{
  ofstream out(ofname.c_str());
  filepos_type idxOffset=0;

  vector<uint32_t> m1; // marginals L1
  vector<uint32_t> m2; // marginals L2
  m1.resize(max(first_rare_id,V1.getNumTokens()),0);
  m2.resize(V2.getNumTokens(),0);
  vector<id_type> index(V1.getNumTokens()+1,0);
  numwrite(out,idxOffset); // blank for the time being
  numwrite(out,id_type(m1.size()));
  numwrite(out,id_type(m2.size()));

  id_type cellCount=0;
  id_type stop = min(first_rare_id,id_type(m1.size()));
  for (id_type id1 = 0; id1 < stop; ++id1)
    {
      index[id1]  = cellCount;
      vector<uint32_t> const& v = FREQ[id1];
      for (id_type id2 = 0; id2 < id_type(v.size()); ++id2)
        {
          if (!v[id2]) continue;
          cellCount++;
          numwrite(out,id2);
          out.write(reinterpret_cast<char const*>(&v[id2]),sizeof(uint32_t));
          m1[id1] += v[id2];
          m2[id2] += v[id2];
        }
    }
  for (id_type id1 = stop; id1 < id_type(m1.size()); ++id1)
    {
      index[id1]  = cellCount;
      map<id_type,uint32_t> const& M = RARE[id1];
      for (map<id_type,uint32_t>::const_iterator m = M.begin(); m != M.end(); ++m)
        {
          if (m->second == 0) continue;
          cellCount++;
          numwrite(out,m->first);
          out.write(reinterpret_cast<char const*>(&m->second),sizeof(float));
          m1[id1] += m->second;
          m2[m->first] += m->second;
        }
    }
  index[m1.size()] = cellCount;
  idxOffset    = out.tellp();
  for (size_t i = 0; i < index.size(); ++i)
    numwrite(out,index[i]);
  out.write(reinterpret_cast<char const*>(&m1[0]),m1.size()*sizeof(float));
  out.write(reinterpret_cast<char const*>(&m2[0]),m2.size()*sizeof(float));

  // re-write the file header
  out.seekp(0);
  numwrite(out,idxOffset);
  out.close();
}

int
main(int argc, char* argv[])
{
  interpret_args(argc,argv);
  char c = *bname.rbegin();
  if (c != '/' && c != '.') bname += '.';
  T1.open(bname+L1+".mct");
  T2.open(bname+L2+".mct");
  Tx.open(bname+L1+"-"+L2+".mam");
  V1.open(bname+L1+".tdx");
  V2.open(bname+L2+".tdx");

  JFREQ.resize(first_rare_id,vector<uint32_t>(V2.ksize(),0));
  JRARE.resize(V1.ksize());

  CFREQ.resize(first_rare_id,vector<uint32_t>(V2.ksize(),0));
  CRARE.resize(V1.ksize());

  for (size_t sid = 0; sid < T1.size(); ++sid)
    {
      if (sid%10000 == 0) cerr << sid << endl;
      processSentence(sid);
    }

  if (oname.size()) writeTable(oname,JFREQ,JRARE);
  if (cooc.size())  writeTable(cooc,CFREQ,CRARE);
  exit(0);
}

void
interpret_args(int ac, char* av[])
{
  namespace po=boost::program_options;
  po::variables_map vm;
  po::options_description o("Options");
  po::options_description h("Hidden Options");
  po::positional_options_description a;

  o.add_options()
    ("help,h",    "print this message")
    ("cfg,f", po::value<string>(&cfgFile),"config file")
    ("oname,o", po::value<string>(&oname),"output file name")
    ("cooc,c", po::value<string>(&cooc),
     "file name for raw co-occurrence counts")
    ;

  h.add_options()
    ("bname", po::value<string>(&bname), "base name")
    ("L1",    po::value<string>(&L1),"L1 tag")
    ("L2",    po::value<string>(&L2),"L2 tag")
    ;
  a.add("bname",1);
  a.add("L1",1);
  a.add("L2",1);
  get_options(ac,av,h.add(o),a,vm,"cfg");

  if (vm.count("help") || bname.empty() || (oname.empty() && cooc.empty()))
    {
      cout << "usage:\n\t" << av[0] << " <basename> <L1 tag> <L2 tag> [-o <output file>] [-c <output file>]\n" << endl;
      cout << "at least one of -o / -c must be specified." << endl;
      cout << o << endl;
      exit(0);
    }
}

<|endoftext|>