LCOV - code coverage report
Current view: top level - pyuno/source/module - pyuno_runtime.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 279 467 59.7 %
Date: 2014-11-03 Functions: 19 24 79.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; eval:(c-set-style "bsd"); tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <config_features.h>
      21             : #include <config_folders.h>
      22             : 
      23             : #include "pyuno_impl.hxx"
      24             : 
      25             : #include <osl/thread.h>
      26             : #include <osl/module.h>
      27             : #include <osl/process.h>
      28             : #include <rtl/strbuf.hxx>
      29             : #include <rtl/ustrbuf.hxx>
      30             : #include <rtl/bootstrap.hxx>
      31             : #include <locale.h>
      32             : 
      33             : #include <typelib/typedescription.hxx>
      34             : 
      35             : #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
      36             : #include <com/sun/star/beans/XMaterialHolder.hpp>
      37             : #include <com/sun/star/beans/theIntrospection.hpp>
      38             : #include <com/sun/star/script/Converter.hpp>
      39             : #include <com/sun/star/script/InvocationAdapterFactory.hpp>
      40             : #include <com/sun/star/reflection/theCoreReflection.hpp>
      41             : 
      42             : 
      43             : using com::sun::star::uno::Reference;
      44             : using com::sun::star::uno::XInterface;
      45             : using com::sun::star::uno::Any;
      46             : using com::sun::star::uno::TypeDescription;
      47             : using com::sun::star::uno::Sequence;
      48             : using com::sun::star::uno::Type;
      49             : using com::sun::star::uno::UNO_QUERY;
      50             : using com::sun::star::uno::Exception;
      51             : using com::sun::star::uno::RuntimeException;
      52             : using com::sun::star::uno::XComponentContext;
      53             : using com::sun::star::lang::WrappedTargetRuntimeException;
      54             : using com::sun::star::lang::XSingleServiceFactory;
      55             : using com::sun::star::lang::XUnoTunnel;
      56             : using com::sun::star::reflection::theCoreReflection;
      57             : using com::sun::star::reflection::XIdlReflection;
      58             : using com::sun::star::reflection::InvocationTargetException;
      59             : using com::sun::star::script::Converter;
      60             : using com::sun::star::script::XTypeConverter;
      61             : using com::sun::star::script::XInvocationAdapterFactory2;
      62             : using com::sun::star::script::XInvocation;
      63             : using com::sun::star::beans::XMaterialHolder;
      64             : using com::sun::star::beans::XIntrospection;
      65             : using com::sun::star::beans::theIntrospection;
      66             : 
      67             : #include <vector>
      68             : 
      69             : namespace pyuno
      70             : {
      71             : 
      72             : static PyTypeObject RuntimeImpl_Type =
      73             : {
      74             :     PyVarObject_HEAD_INIT (&PyType_Type, 0)
      75             :     "pyuno_runtime",
      76             :     sizeof (RuntimeImpl),
      77             :     0,
      78             :     (destructor) RuntimeImpl::del,
      79             :     (printfunc) 0,
      80             :     (getattrfunc) 0,
      81             :     (setattrfunc) 0,
      82             :     0,
      83             :     (reprfunc) 0,
      84             :     0,
      85             :     0,
      86             :     0,
      87             :     (hashfunc) 0,
      88             :     (ternaryfunc) 0,
      89             :     (reprfunc) 0,
      90             :     (getattrofunc)0,
      91             :     (setattrofunc)0,
      92             :     NULL,
      93             :     0,
      94             :     NULL,
      95             :     (traverseproc)0,
      96             :     (inquiry)0,
      97             :     (richcmpfunc)0,
      98             :     0,
      99             :     (getiterfunc)0,
     100             :     (iternextfunc)0,
     101             :     NULL,
     102             :     NULL,
     103             :     NULL,
     104             :     NULL,
     105             :     NULL,
     106             :     (descrgetfunc)0,
     107             :     (descrsetfunc)0,
     108             :     0,
     109             :     (initproc)0,
     110             :     (allocfunc)0,
     111             :     (newfunc)0,
     112             :     (freefunc)0,
     113             :     (inquiry)0,
     114             :     NULL,
     115             :     NULL,
     116             :     NULL,
     117             :     NULL,
     118             :     NULL,
     119             :     (destructor)0
     120             : #if PY_VERSION_HEX >= 0x02060000
     121             :     , 0
     122             : #endif
     123             : #if PY_VERSION_HEX >= 0x03040000
     124             :     , 0
     125             : #endif
     126             : };
     127             : 
     128             : /*----------------------------------------------------------------------
     129             :   Runtime implementation
     130             :  -----------------------------------------------------------------------*/
     131        5384 : static void getRuntimeImpl( PyRef & globalDict, PyRef &runtimeImpl )
     132             :     throw ( com::sun::star::uno::RuntimeException )
     133             : {
     134        5384 :     PyThreadState * state = PyThreadState_Get();
     135        5384 :     if( ! state )
     136             :     {
     137           0 :         throw RuntimeException( "python global interpreter must be held (thread must be attached)" );
     138             :     }
     139             : 
     140        5384 :     PyObject* pModule = PyImport_AddModule("__main__");
     141             : 
     142        5384 :     if (!pModule)
     143             :     {
     144           0 :         throw RuntimeException("can't import __main__ module");
     145             :     }
     146             : 
     147        5384 :     globalDict = PyRef( PyModule_GetDict(pModule));
     148             : 
     149        5384 :     if( ! globalDict.is() ) // FATAL !
     150             :     {
     151           0 :         throw RuntimeException("can't find __main__ module");
     152             :     }
     153        5384 :     runtimeImpl = PyDict_GetItemString( globalDict.get() , "pyuno_runtime" );
     154        5384 : }
     155             : 
     156           6 : static PyRef importUnoModule( ) throw ( RuntimeException )
     157             : {
     158             :     // import the uno module
     159           6 :     PyRef module( PyImport_ImportModule( "uno" ), SAL_NO_ACQUIRE, NOT_NULL );
     160           6 :     if( PyErr_Occurred() )
     161             :     {
     162           0 :         PyRef excType, excValue, excTraceback;
     163           0 :         PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback);
     164             :         // As of Python 2.7 this gives a rather non-useful "<traceback object at 0xADDRESS>",
     165             :         // but it is the best we can do in the absence of uno._uno_extract_printable_stacktrace
     166             :         // Who knows, a future Python might print something better.
     167           0 :         PyRef str( PyObject_Str( excTraceback.get() ), SAL_NO_ACQUIRE );
     168             : 
     169           0 :         OUStringBuffer buf;
     170           0 :         buf.appendAscii( "python object raised an unknown exception (" );
     171           0 :         PyRef valueRep( PyObject_Repr( excValue.get() ), SAL_NO_ACQUIRE );
     172           0 :         buf.appendAscii( PyStr_AsString( valueRep.get())).appendAscii( ", traceback follows\n" );
     173           0 :         buf.appendAscii( PyStr_AsString( str.get() ) );
     174           0 :         buf.appendAscii( ")" );
     175           0 :         throw RuntimeException( buf.makeStringAndClear() );
     176             :     }
     177           6 :     PyRef dict( PyModule_GetDict( module.get() ) );
     178           6 :     return dict;
     179             : }
     180             : 
     181           6 : static void readLoggingConfig( sal_Int32 *pLevel, FILE **ppFile )
     182             : {
     183           6 :     *pLevel = LogLevel::NONE;
     184           6 :     *ppFile = 0;
     185           6 :     OUString fileName;
     186             :     osl_getModuleURLFromFunctionAddress(
     187             :         reinterpret_cast< oslGenericFunction >(readLoggingConfig),
     188           6 :         (rtl_uString **) &fileName );
     189           6 :     fileName = fileName.copy( fileName.lastIndexOf( '/' )+1 );
     190             : #ifdef MACOSX
     191             :     fileName += "../" LIBO_ETC_FOLDER "/";
     192             : #endif
     193           6 :     fileName += SAL_CONFIGFILE("pyuno" );
     194          12 :     rtl::Bootstrap bootstrapHandle( fileName );
     195             : 
     196          12 :     OUString str;
     197           6 :     if( bootstrapHandle.getFrom( "PYUNO_LOGLEVEL", str ) )
     198             :     {
     199           0 :         if ( str == "NONE" )
     200           0 :             *pLevel = LogLevel::NONE;
     201           0 :         else if ( str == "CALL" )
     202           0 :             *pLevel = LogLevel::CALL;
     203           0 :         else if ( str == "ARGS" )
     204           0 :             *pLevel = LogLevel::ARGS;
     205             :         else
     206             :         {
     207             :             fprintf( stderr, "unknown loglevel %s\n",
     208           0 :                      OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
     209             :         }
     210             :     }
     211           6 :     if( *pLevel > LogLevel::NONE )
     212             :     {
     213           0 :         *ppFile = stdout;
     214           0 :         if( bootstrapHandle.getFrom( "PYUNO_LOGTARGET", str ) )
     215             :         {
     216           0 :             if ( str == "stdout" )
     217           0 :                 *ppFile = stdout;
     218           0 :             else if ( str == "stderr" )
     219           0 :                 *ppFile = stderr;
     220             :             else
     221             :             {
     222             :                 oslProcessInfo data;
     223           0 :                 data.Size = sizeof( data );
     224             :                 osl_getProcessInfo(
     225           0 :                     0 , osl_Process_IDENTIFIER , &data );
     226           0 :                 osl_getSystemPathFromFileURL( str.pData, &str.pData);
     227           0 :                 OString o = OUStringToOString( str, osl_getThreadTextEncoding() );
     228           0 :                 o += ".";
     229           0 :                 o += OString::number( data.Ident );
     230             : 
     231           0 :                 *ppFile = fopen( o.getStr() , "w" );
     232           0 :                 if ( *ppFile )
     233             :                 {
     234             :                     // do not buffer (useful if e.g. analyzing a crash)
     235           0 :                     setvbuf( *ppFile, 0, _IONBF, 0 );
     236             :                 }
     237             :                 else
     238             :                 {
     239             :                     fprintf( stderr, "couldn't create file %s\n",
     240           0 :                              OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() );
     241             : 
     242           0 :                 }
     243             :             }
     244             :         }
     245           6 :     }
     246           6 : }
     247             : 
     248             : /*-------------------------------------------------------------------
     249             :  RuntimeImpl implementations
     250             :  *-------------------------------------------------------------------*/
     251           6 : PyRef stRuntimeImpl::create( const Reference< XComponentContext > &ctx )
     252             :     throw( com::sun::star::uno::RuntimeException )
     253             : {
     254           6 :     RuntimeImpl *me = PyObject_New (RuntimeImpl, &RuntimeImpl_Type);
     255           6 :     if( ! me )
     256           0 :         throw RuntimeException( "cannot instantiate pyuno::RuntimeImpl" );
     257           6 :     me->cargo = 0;
     258             :     // must use a different struct here, as the PyObject_New
     259             :     // makes C++ unusable
     260           6 :     RuntimeCargo *c = new RuntimeCargo();
     261           6 :     readLoggingConfig( &(c->logLevel) , &(c->logFile) );
     262           6 :     log( c, LogLevel::CALL, "Instantiating pyuno bridge" );
     263             : 
     264           6 :     c->valid = true;
     265           6 :     c->xContext = ctx;
     266          12 :     c->xInvocation = Reference< XSingleServiceFactory > (
     267          12 :         ctx->getServiceManager()->createInstanceWithContext(
     268             :             OUString(  "com.sun.star.script.Invocation"  ),
     269           6 :             ctx ),
     270           6 :         UNO_QUERY );
     271           6 :     if( ! c->xInvocation.is() )
     272           0 :         throw RuntimeException( "pyuno: couldn't instantiate invocation service" );
     273             : 
     274           6 :     c->xTypeConverter = Converter::create(ctx);
     275           6 :     if( ! c->xTypeConverter.is() )
     276           0 :         throw RuntimeException( "pyuno: couldn't instantiate typeconverter service" );
     277             : 
     278           6 :     c->xCoreReflection = theCoreReflection::get(ctx);
     279             : 
     280           6 :     c->xAdapterFactory = css::script::InvocationAdapterFactory::create(ctx);
     281             : 
     282           6 :     c->xIntrospection = theIntrospection::get(ctx);
     283             : 
     284           6 :     Any a = ctx->getValueByName("/singletons/com.sun.star.reflection.theTypeDescriptionManager");
     285           6 :     a >>= c->xTdMgr;
     286           6 :     if( ! c->xTdMgr.is() )
     287           0 :         throw RuntimeException( "pyuno: couldn't retrieve typedescriptionmanager" );
     288             : 
     289           6 :     me->cargo =c;
     290           6 :     return PyRef( reinterpret_cast< PyObject * > ( me ), SAL_NO_ACQUIRE );
     291             : }
     292             : 
     293           0 : void  stRuntimeImpl::del(PyObject* self)
     294             : {
     295           0 :     RuntimeImpl *me = reinterpret_cast< RuntimeImpl * > ( self );
     296           0 :     if( me->cargo->logFile )
     297           0 :         fclose( me->cargo->logFile );
     298           0 :     delete me->cargo;
     299           0 :     PyObject_Del (self);
     300           0 : }
     301             : 
     302             : 
     303           6 : void Runtime::initialize( const Reference< XComponentContext > & ctx )
     304             :     throw ( RuntimeException )
     305             : {
     306          12 :     PyRef globalDict, runtime;
     307           6 :     getRuntimeImpl( globalDict , runtime );
     308           6 :     RuntimeImpl *impl = reinterpret_cast< RuntimeImpl * > (runtime.get());
     309             : 
     310           6 :     if( runtime.is() && impl->cargo->valid )
     311             :     {
     312           0 :         throw RuntimeException("pyuno runtime has already been initialized before" );
     313             :     }
     314          12 :     PyRef keep( RuntimeImpl::create( ctx ) );
     315           6 :     PyDict_SetItemString( globalDict.get(), "pyuno_runtime" , keep.get() );
     316          12 :     Py_XINCREF( keep.get() );
     317           6 : }
     318             : 
     319             : 
     320          70 : bool Runtime::isInitialized() throw ( RuntimeException )
     321             : {
     322         140 :     PyRef globalDict, runtime;
     323          70 :     getRuntimeImpl( globalDict , runtime );
     324          70 :     RuntimeImpl *impl = reinterpret_cast< RuntimeImpl * > (runtime.get());
     325         140 :     return runtime.is() && impl->cargo->valid;
     326             : }
     327             : 
     328        5308 : Runtime::Runtime() throw(  RuntimeException )
     329        5308 :     : impl( 0 )
     330             : {
     331       10616 :     PyRef globalDict, runtime;
     332        5308 :     getRuntimeImpl( globalDict , runtime );
     333        5308 :     if( ! runtime.is() )
     334             :     {
     335             :         throw RuntimeException(
     336             :             "pyuno runtime is not initialized, "
     337           0 :             "(the pyuno.bootstrap needs to be called before using any uno classes)" );
     338             :     }
     339        5308 :     impl = reinterpret_cast< RuntimeImpl * > (runtime.get());
     340       10616 :     Py_XINCREF( runtime.get() );
     341        5308 : }
     342             : 
     343           0 : Runtime::Runtime( const Runtime & r )
     344             : {
     345           0 :     impl = r.impl;
     346           0 :     Py_XINCREF( reinterpret_cast< PyObject * >(impl) );
     347           0 : }
     348             : 
     349        5308 : Runtime::~Runtime()
     350             : {
     351        5308 :     Py_XDECREF( reinterpret_cast< PyObject * >(impl) );
     352        5308 : }
     353             : 
     354           0 : Runtime & Runtime::operator = ( const Runtime & r )
     355             : {
     356           0 :     PyRef temp( reinterpret_cast< PyObject * >(r.impl) );
     357           0 :     Py_XINCREF( temp.get() );
     358           0 :     Py_XDECREF( reinterpret_cast< PyObject * >(impl) );
     359           0 :     impl = r.impl;
     360           0 :     return *this;
     361             : }
     362             : 
     363        2300 : PyRef Runtime::any2PyObject (const Any &a ) const
     364             :     throw ( com::sun::star::script::CannotConvertException,
     365             :             com::sun::star::lang::IllegalArgumentException,
     366             :             RuntimeException)
     367             : {
     368        2300 :     if( ! impl->cargo->valid )
     369             :     {
     370           0 :         throw RuntimeException("pyuno runtime must be initialized before calling any2PyObject" );
     371             :     }
     372             : 
     373        2300 :     switch (a.getValueTypeClass ())
     374             :     {
     375             :     case typelib_TypeClass_VOID:
     376             :     {
     377         184 :         Py_INCREF (Py_None);
     378         184 :         return PyRef(Py_None);
     379             :     }
     380             :     case typelib_TypeClass_CHAR:
     381             :     {
     382           0 :         sal_Unicode c = *(sal_Unicode*)a.getValue();
     383           0 :         return PyRef( PyUNO_char_new( c , *this ), SAL_NO_ACQUIRE );
     384             :     }
     385             :     case typelib_TypeClass_BOOLEAN:
     386             :     {
     387             :         bool b;
     388         204 :         if ((a >>= b) && b)
     389         138 :             return Py_True;
     390             :         else
     391          66 :             return Py_False;
     392             :     }
     393             :     case typelib_TypeClass_BYTE:
     394             :     case typelib_TypeClass_SHORT:
     395             :     case typelib_TypeClass_UNSIGNED_SHORT:
     396             :     case typelib_TypeClass_LONG:
     397             :     {
     398         432 :         sal_Int32 l = 0;
     399         432 :         a >>= l;
     400         432 :         return PyRef( PyLong_FromLong (l), SAL_NO_ACQUIRE );
     401             :     }
     402             :     case typelib_TypeClass_UNSIGNED_LONG:
     403             :     {
     404          28 :         sal_uInt32 l = 0;
     405          28 :         a >>= l;
     406          28 :         return PyRef( PyLong_FromUnsignedLong (l), SAL_NO_ACQUIRE );
     407             :     }
     408             :     case typelib_TypeClass_HYPER:
     409             :     {
     410           0 :         sal_Int64 l = 0;
     411           0 :         a >>= l;
     412           0 :         return PyRef( PyLong_FromLongLong (l), SAL_NO_ACQUIRE);
     413             :     }
     414             :     case typelib_TypeClass_UNSIGNED_HYPER:
     415             :     {
     416           0 :         sal_uInt64 l = 0;
     417           0 :         a >>= l;
     418           0 :         return PyRef( PyLong_FromUnsignedLongLong (l), SAL_NO_ACQUIRE);
     419             :     }
     420             :     case typelib_TypeClass_FLOAT:
     421             :     {
     422          12 :         float f = 0.0;
     423          12 :         a >>= f;
     424          12 :         return PyRef(PyFloat_FromDouble (f), SAL_NO_ACQUIRE);
     425             :     }
     426             :     case typelib_TypeClass_DOUBLE:
     427             :     {
     428           6 :         double d = 0.0;
     429           6 :         a >>= d;
     430           6 :         return PyRef( PyFloat_FromDouble (d), SAL_NO_ACQUIRE);
     431             :     }
     432             :     case typelib_TypeClass_STRING:
     433             :     {
     434         436 :         OUString tmp_ostr;
     435         436 :         a >>= tmp_ostr;
     436         436 :         return ustring2PyUnicode( tmp_ostr );
     437             :     }
     438             :     case typelib_TypeClass_TYPE:
     439             :     {
     440           0 :         Type t;
     441           0 :         a >>= t;
     442           0 :         OString o = OUStringToOString( t.getTypeName(), RTL_TEXTENCODING_ASCII_US );
     443             :         return PyRef(
     444             :             PyUNO_Type_new (
     445             :                 o.getStr(),  (com::sun::star::uno::TypeClass)t.getTypeClass(), *this),
     446           0 :             SAL_NO_ACQUIRE);
     447             :     }
     448             :     case typelib_TypeClass_ANY:
     449             :     {
     450             :         //I don't think this can happen.
     451           0 :         Py_INCREF (Py_None);
     452           0 :         return Py_None;
     453             :     }
     454             :     case typelib_TypeClass_ENUM:
     455             :     {
     456          10 :         sal_Int32 l = *(sal_Int32 *) a.getValue();
     457          10 :         TypeDescription desc( a.getValueType() );
     458          10 :         if( desc.is() )
     459             :         {
     460          10 :             desc.makeComplete();
     461             :             typelib_EnumTypeDescription *pEnumDesc =
     462          10 :                 (typelib_EnumTypeDescription *) desc.get();
     463          10 :             for( int i = 0 ; i < pEnumDesc->nEnumValues ; i ++ )
     464             :             {
     465          10 :                 if( pEnumDesc->pEnumValues[i] == l )
     466             :                 {
     467          10 :                     OString v = OUStringToOString( pEnumDesc->ppEnumNames[i], RTL_TEXTENCODING_ASCII_US);
     468          20 :                     OString e = OUStringToOString( pEnumDesc->aBase.pTypeName, RTL_TEXTENCODING_ASCII_US);
     469          20 :                     return PyRef( PyUNO_Enum_new(e.getStr(),v.getStr(), *this ), SAL_NO_ACQUIRE );
     470             :                 }
     471             :             }
     472             :         }
     473           0 :         OUStringBuffer buf;
     474           0 :         buf.appendAscii( "Any carries enum " );
     475           0 :         buf.append( a.getValueType().getTypeName());
     476           0 :         buf.appendAscii( " with invalid value " ).append( l );
     477          10 :         throw RuntimeException( buf.makeStringAndClear() );
     478             :     }
     479             :     case typelib_TypeClass_EXCEPTION:
     480             :     case typelib_TypeClass_STRUCT:
     481             :     {
     482         760 :         PyRef excClass = getClass( a.getValueType().getTypeName(), *this );
     483        1520 :         PyRef value = PyRef( PyUNO_new_UNCHECKED (a, getImpl()->cargo->xInvocation), SAL_NO_ACQUIRE);
     484        1520 :         PyRef argsTuple( PyTuple_New( 1 ) , SAL_NO_ACQUIRE, NOT_NULL );
     485         760 :         PyTuple_SetItem( argsTuple.get() , 0 , value.getAcquired() );
     486        1520 :         PyRef ret( PyObject_CallObject( excClass.get() , argsTuple.get() ), SAL_NO_ACQUIRE );
     487         760 :         if( ! ret.is() )
     488             :         {
     489           0 :             OUStringBuffer buf;
     490           0 :             buf.appendAscii( "Couldn't instantiate python representation of structered UNO type " );
     491           0 :             buf.append( a.getValueType().getTypeName() );
     492           0 :             throw RuntimeException( buf.makeStringAndClear() );
     493             :         }
     494             : 
     495         760 :         if( com::sun::star::uno::TypeClass_EXCEPTION == a.getValueTypeClass() )
     496             :         {
     497             :             // add the message in a standard python way !
     498         140 :             PyRef args( PyTuple_New( 1 ), SAL_NO_ACQUIRE, NOT_NULL );
     499             : 
     500             :             // assuming that the Message is always the first member, wuuuu
     501         140 :             void *pData = (void*)a.getValue();
     502         280 :             OUString message = *(OUString * )pData;
     503         280 :             PyRef pymsg = ustring2PyString( message );
     504         140 :             PyTuple_SetItem( args.get(), 0 , pymsg.getAcquired() );
     505             :             // the exception base functions want to have an "args" tuple,
     506             :             // which contains the message
     507         280 :             PyObject_SetAttrString( ret.get(), "args", args.get() );
     508             :         }
     509        1520 :         return ret;
     510             :     }
     511             :     case typelib_TypeClass_SEQUENCE:
     512             :     {
     513          10 :         Sequence<Any> s;
     514             : 
     515          20 :         Sequence< sal_Int8 > byteSequence;
     516          10 :         if( a >>= byteSequence )
     517             :         {
     518             :             // byte sequence is treated in a special way because of peformance reasons
     519             :             // @since 0.9.2
     520           0 :             return PyRef( PyUNO_ByteSequence_new( byteSequence, *this ), SAL_NO_ACQUIRE );
     521             :         }
     522             :         else
     523             :         {
     524          10 :             Reference< XTypeConverter > tc = getImpl()->cargo->xTypeConverter;
     525          20 :             Reference< XSingleServiceFactory > ssf = getImpl()->cargo->xInvocation;
     526          10 :             tc->convertTo (a, ::getCppuType (&s)) >>= s;
     527          20 :             PyRef tuple( PyTuple_New (s.getLength()), SAL_NO_ACQUIRE, NOT_NULL);
     528          10 :             int i=0;
     529             :             try
     530             :             {
     531         344 :                 for ( i = 0; i < s.getLength (); i++)
     532             :                 {
     533         334 :                     PyRef element;
     534         334 :                     element = any2PyObject (tc->convertTo (s[i], s[i].getValueType() ));
     535             :                     OSL_ASSERT( element.is() );
     536         334 :                     PyTuple_SetItem( tuple.get(), i, element.getAcquired() );
     537         334 :                 }
     538             :             }
     539           0 :             catch( com::sun::star::uno::Exception & )
     540             :             {
     541           0 :                 for( ; i < s.getLength() ; i ++ )
     542             :                 {
     543           0 :                     Py_INCREF( Py_None );
     544           0 :                     PyTuple_SetItem( tuple.get(), i,  Py_None );
     545             :                 }
     546           0 :                 throw;
     547             :             }
     548          20 :             return tuple;
     549          10 :         }
     550             :     }
     551             :     case typelib_TypeClass_INTERFACE:
     552             :     {
     553             :         // fdo#46678 must unlock GIL because getSomething could acquire locks,
     554             :         // and queryInterface too...
     555             :         {
     556         218 :             PyThreadDetach d;
     557             : 
     558         436 :             Reference<XUnoTunnel> tunnel;
     559         218 :             a >>= tunnel;
     560         218 :             if (tunnel.is())
     561             :             {
     562         108 :                 sal_Int64 that = tunnel->getSomething( ::pyuno::Adapter::getUnoTunnelImplementationId() );
     563         108 :                 if( that )
     564           0 :                     return reinterpret_cast<Adapter*>(that)->getWrappedObject();
     565         218 :             }
     566             :         }
     567             :         //This is just like the struct case:
     568         218 :         return PyRef( PyUNO_new (a, getImpl()->cargo->xInvocation), SAL_NO_ACQUIRE );
     569             :     }
     570             :     default:
     571             :     {
     572           0 :         OUStringBuffer buf;
     573           0 :         buf.appendAscii( "Unknown UNO type class " );
     574           0 :         buf.append( (sal_Int32 ) a.getValueTypeClass() );
     575           0 :         throw RuntimeException(buf.makeStringAndClear( ) );
     576             :     }
     577             :     }
     578             : }
     579             : 
     580           8 : static Sequence< Type > invokeGetTypes( const Runtime & r , PyObject * o )
     581             : {
     582           8 :     Sequence< Type > ret;
     583             : 
     584          16 :     PyRef method( PyObject_GetAttrString( o , "getTypes" ), SAL_NO_ACQUIRE );
     585           8 :     raiseInvocationTargetExceptionWhenNeeded( r );
     586           8 :     if( method.is() && PyCallable_Check( method.get() ) )
     587             :     {
     588           8 :         PyRef types( PyObject_CallObject( method.get(), 0 ) , SAL_NO_ACQUIRE );
     589           8 :         raiseInvocationTargetExceptionWhenNeeded( r );
     590           8 :         if( types.is() && PyTuple_Check( types.get() ) )
     591             :         {
     592           8 :             int size = PyTuple_Size( types.get() );
     593             : 
     594             :             // add the XUnoTunnel interface  for uno object identity concept (hack)
     595           8 :             ret.realloc( size + 1 );
     596          28 :             for( int i = 0 ; i < size ; i ++ )
     597             :             {
     598          20 :                 Any a = r.pyObject2Any(PyTuple_GetItem(types.get(),i));
     599          20 :                 a >>= ret[i];
     600          20 :             }
     601           8 :             ret[size] = cppu::UnoType<com::sun::star::lang::XUnoTunnel>::get();
     602           8 :         }
     603             :     }
     604          16 :     return ret;
     605             : }
     606             : 
     607             : static OUString
     608           0 : lcl_ExceptionMessage(PyObject *const o, OUString const*const pWrapped)
     609             : {
     610           0 :     OUStringBuffer buf;
     611           0 :     buf.appendAscii("Couldn't convert ");
     612           0 :     PyRef reprString( PyObject_Str(o), SAL_NO_ACQUIRE );
     613           0 :     buf.appendAscii( PyStr_AsString(reprString.get()) );
     614           0 :     buf.appendAscii(" to a UNO type");
     615           0 :     if (pWrapped)
     616             :     {
     617           0 :         buf.appendAscii("; caught exception: ");
     618           0 :         buf.append(*pWrapped);
     619             :     }
     620           0 :     return buf.makeStringAndClear();
     621             : }
     622             : 
     623        2278 : Any Runtime::pyObject2Any ( const PyRef & source, enum ConversionMode mode ) const
     624             :     throw ( com::sun::star::uno::RuntimeException )
     625             : {
     626        2278 :     if( ! impl->cargo->valid )
     627             :     {
     628           0 :         throw RuntimeException("pyuno runtime must be initialized before calling any2PyObject" );
     629             :     }
     630             : 
     631        2278 :     Any a;
     632        2278 :     PyObject *o = source.get();
     633        2278 :     if( Py_None == o )
     634             :     {
     635             : 
     636             :     }
     637             :     // In Python 3, there is no PyInt type.
     638             : #if PY_MAJOR_VERSION < 3
     639             :     else if (PyInt_Check (o))
     640             :     {
     641             :         if( o == Py_True )
     642             :         {
     643             :             sal_Bool b = sal_True;
     644             :             a = Any( &b, getBooleanCppuType() );
     645             :         }
     646             :         else if ( o == Py_False )
     647             :         {
     648             :             sal_Bool b = sal_False;
     649             :             a = Any( &b, getBooleanCppuType() );
     650             :         }
     651             :         else
     652             :         {
     653             :             sal_Int32 l = (sal_Int32) PyLong_AsLong( o );
     654             :             if( l < 128 && l >= -128 )
     655             :             {
     656             :                 sal_Int8 b = (sal_Int8 ) l;
     657             :                 a <<= b;
     658             :             }
     659             :             else if( l <= 0x7fff && l >= -0x8000 )
     660             :             {
     661             :                 sal_Int16 s = (sal_Int16) l;
     662             :                 a <<= s;
     663             :             }
     664             :             else
     665             :             {
     666             :                 a <<= l;
     667             :             }
     668             :         }
     669             :     }
     670             : #endif /* PY_MAJOR_VERSION < 3 */
     671        2270 :     else if (PyLong_Check (o))
     672             :     {
     673             : #if PY_MAJOR_VERSION >= 3
     674             :         // Convert the Python 3 booleans that are actually of type PyLong.
     675         348 :         if(o == Py_True)
     676             :         {
     677          56 :             sal_Bool b = sal_True;
     678          56 :             a = Any(&b, getBooleanCppuType());
     679             :         }
     680         292 :         else if(o == Py_False)
     681             :         {
     682          64 :             sal_Bool b = sal_False;
     683          64 :             a = Any(&b, getBooleanCppuType());
     684             :         }
     685             :         else
     686             :         {
     687             : #endif /* PY_MAJOR_VERSION >= 3 */
     688         228 :         sal_Int64 l = (sal_Int64)PyLong_AsLong (o);
     689         228 :         if( l < 128 && l >= -128 )
     690             :         {
     691         220 :             sal_Int8 b = (sal_Int8 ) l;
     692         220 :             a <<= b;
     693             :         }
     694           8 :         else if( l <= 0x7fff && l >= -0x8000 )
     695             :         {
     696           4 :             sal_Int16 s = (sal_Int16) l;
     697           4 :             a <<= s;
     698             :         }
     699           8 :         else if( l <= SAL_CONST_INT64(0x7fffffff) &&
     700           4 :                  l >= -SAL_CONST_INT64(0x80000000) )
     701             :         {
     702           4 :             sal_Int32 l32 = (sal_Int32) l;
     703           4 :             a <<= l32;
     704             :         }
     705             :         else
     706             :         {
     707           0 :             a <<= l;
     708             :         }
     709             : #if PY_MAJOR_VERSION >= 3
     710             :         }
     711             : #endif
     712             :     }
     713        1922 :     else if (PyFloat_Check (o))
     714             :     {
     715           8 :         double d = PyFloat_AsDouble (o);
     716           8 :         a <<= d;
     717             :     }
     718        1914 :     else if (PyStrBytes_Check(o) || PyUnicode_Check(o))
     719             :     {
     720         786 :         a <<= pyString2ustring(o);
     721             :     }
     722        1128 :     else if (PyTuple_Check (o))
     723             :     {
     724         968 :         Sequence<Any> s (PyTuple_Size (o));
     725        2004 :         for (int i = 0; i < PyTuple_Size (o); i++)
     726             :         {
     727        1036 :             s[i] = pyObject2Any (PyTuple_GetItem (o, i), mode );
     728             :         }
     729         968 :         a <<= s;
     730             :     }
     731             :     else
     732             :     {
     733         160 :         Runtime runtime;
     734             :         // should be removed, in case ByteSequence gets derived from String
     735         160 :         if( PyObject_IsInstance( o, getByteSequenceClass( runtime ).get() ) )
     736             :         {
     737           0 :             PyRef str(PyObject_GetAttrString( o , "value" ),SAL_NO_ACQUIRE);
     738           0 :             Sequence< sal_Int8 > seq;
     739           0 :             if( PyStrBytes_Check( str.get() ) )
     740             :             {
     741           0 :                 seq = Sequence<sal_Int8 > (
     742           0 :                     (sal_Int8*) PyStrBytes_AsString(str.get()), PyStrBytes_Size(str.get()));
     743             :             }
     744           0 :             a <<= seq;
     745             :         }
     746             :         else
     747         160 :         if( PyObject_IsInstance( o, getTypeClass( runtime ).get() ) )
     748             :         {
     749          20 :             Type t = PyType2Type( o );
     750          20 :             a <<= t;
     751             :         }
     752         140 :         else if( PyObject_IsInstance( o, getEnumClass( runtime ).get() ) )
     753             :         {
     754           0 :             a = PyEnum2Enum( o );
     755             :         }
     756         140 :         else if( isInstanceOfStructOrException( o ) )
     757             :         {
     758          58 :             PyRef struc(PyObject_GetAttrString( o , "value" ),SAL_NO_ACQUIRE);
     759          58 :             PyUNO * obj = (PyUNO*)struc.get();
     760         116 :             Reference< XMaterialHolder > holder( obj->members->xInvocation, UNO_QUERY );
     761          58 :             if( holder.is( ) )
     762          58 :                 a = holder->getMaterial();
     763             :             else
     764             :             {
     765             :                 throw RuntimeException(
     766           0 :                     "struct or exception wrapper does not support XMaterialHolder" );
     767          58 :             }
     768             :         }
     769          82 :         else if( PyObject_IsInstance( o, getPyUnoClass().get() ) )
     770             :         {
     771             :             PyUNO* o_pi;
     772          74 :             o_pi = (PyUNO*) o;
     773         148 :             if (o_pi->members->wrappedObject.getValueTypeClass () ==
     774         148 :                 com::sun::star::uno::TypeClass_STRUCT ||
     775          74 :                 o_pi->members->wrappedObject.getValueTypeClass () ==
     776             :                 com::sun::star::uno::TypeClass_EXCEPTION)
     777             :             {
     778           0 :                 Reference<XMaterialHolder> my_mh (o_pi->members->xInvocation, UNO_QUERY);
     779             : 
     780           0 :                 if (!my_mh.is ())
     781             :                 {
     782             :                     throw RuntimeException(
     783           0 :                         "struct wrapper does not support XMaterialHolder" );
     784             :                 }
     785             :                 else
     786           0 :                     a = my_mh->getMaterial ();
     787             :             }
     788             :             else
     789             :             {
     790          74 :                 a = o_pi->members->wrappedObject;
     791             :             }
     792             :         }
     793           8 :         else if( PyObject_IsInstance( o, getCharClass( runtime ).get() ) )
     794             :         {
     795           0 :             sal_Unicode c = PyChar2Unicode( o );
     796           0 :             a.setValue( &c, getCharCppuType( ));
     797             :         }
     798           8 :         else if( PyObject_IsInstance( o, getAnyClass( runtime ).get() ) )
     799             :         {
     800           0 :             if( ACCEPT_UNO_ANY == mode )
     801             :             {
     802           0 :                 a = pyObject2Any( PyRef( PyObject_GetAttrString( o , "value" ), SAL_NO_ACQUIRE) );
     803           0 :                 Type t;
     804           0 :                 pyObject2Any( PyRef( PyObject_GetAttrString( o, "type" ), SAL_NO_ACQUIRE ) ) >>= t;
     805             : 
     806             :                 try
     807             :                 {
     808           0 :                     a = getImpl()->cargo->xTypeConverter->convertTo( a, t );
     809             :                 }
     810           0 :                 catch( const com::sun::star::uno::Exception & e )
     811             :                 {
     812             :                     throw WrappedTargetRuntimeException(
     813           0 :                             e.Message, e.Context, makeAny(e));
     814           0 :                 }
     815             :             }
     816             :             else
     817             :             {
     818             :                 throw RuntimeException(
     819             :                     "uno.Any instance not accepted during method call, "
     820           0 :                     "use uno.invoke instead" );
     821             :             }
     822             :         }
     823             :         else
     824             :         {
     825           8 :             Reference< XInterface > mappedObject;
     826          16 :             Reference< XInvocation > adapterObject;
     827             : 
     828             :             // instance already mapped out to the world ?
     829           8 :             PyRef2Adapter::iterator ii = impl->cargo->mappedObjects.find( PyRef( o ) );
     830           8 :             if( ii != impl->cargo->mappedObjects.end() )
     831             :             {
     832           0 :                 adapterObject = ii->second;
     833             :             }
     834             : 
     835           8 :             if( adapterObject.is() )
     836             :             {
     837             :                 // object got already bridged !
     838           0 :                 Reference< com::sun::star::lang::XUnoTunnel > tunnel( adapterObject, UNO_QUERY );
     839             : 
     840             :                 Adapter *pAdapter = reinterpret_cast<Adapter*>(
     841           0 :                         tunnel->getSomething(
     842           0 :                             ::pyuno::Adapter::getUnoTunnelImplementationId() ) );
     843             : 
     844           0 :                 mappedObject = impl->cargo->xAdapterFactory->createAdapter(
     845           0 :                     adapterObject, pAdapter->getWrappedTypes() );
     846             :             }
     847             :             else
     848             :             {
     849             :                 try {
     850           8 :                     Sequence<Type> interfaces = invokeGetTypes(*this, o);
     851           8 :                     if (interfaces.getLength())
     852             :                     {
     853           8 :                         Adapter *pAdapter = new Adapter( o, interfaces );
     854          16 :                         mappedObject =
     855           8 :                             getImpl()->cargo->xAdapterFactory->createAdapter(
     856          16 :                                 pAdapter, interfaces );
     857             : 
     858             :                         // keep a list of exported objects to ensure object identity !
     859          16 :                         impl->cargo->mappedObjects[ PyRef(o) ] =
     860          16 :                             com::sun::star::uno::WeakReference< XInvocation > ( pAdapter );
     861           8 :                     }
     862           0 :                 } catch (InvocationTargetException const& e) {
     863           0 :                     OUString const msg(lcl_ExceptionMessage(o, &e.Message));
     864             :                     throw WrappedTargetRuntimeException( // re-wrap that
     865           0 :                             msg, e.Context, e.TargetException);
     866             :                 }
     867             :             }
     868           8 :             if( mappedObject.is() )
     869             :             {
     870           8 :                 a = com::sun::star::uno::makeAny( mappedObject );
     871             :             }
     872             :             else
     873             :             {
     874           0 :                 OUString const msg(lcl_ExceptionMessage(o, 0));
     875           0 :                 throw RuntimeException(msg);
     876           8 :             }
     877         160 :         }
     878             :     }
     879        2278 :     return a;
     880             : }
     881             : 
     882           0 : Any Runtime::extractUnoException( const PyRef & excType, const PyRef &excValue, const PyRef &excTraceback) const
     883             : {
     884           0 :     OUString str;
     885           0 :     Any ret;
     886           0 :     if( excTraceback.is() )
     887             :     {
     888           0 :         Exception e;
     889           0 :         PyRef unoModule;
     890           0 :         if ( impl )
     891             :         {
     892             :             try
     893             :             {
     894           0 :                 unoModule = impl->cargo->getUnoModule();
     895             :             }
     896           0 :             catch (const Exception &ei)
     897             :             {
     898           0 :                 e=ei;
     899             :             }
     900             :         }
     901           0 :         if( unoModule.is() )
     902             :         {
     903             :             PyRef extractTraceback(
     904           0 :                 PyDict_GetItemString(unoModule.get(),"_uno_extract_printable_stacktrace" ) );
     905             : 
     906           0 :             if( PyCallable_Check(extractTraceback.get()) )
     907             :             {
     908           0 :                 PyRef args( PyTuple_New( 1), SAL_NO_ACQUIRE, NOT_NULL );
     909           0 :                 PyTuple_SetItem( args.get(), 0, excTraceback.getAcquired() );
     910           0 :                 PyRef pyStr( PyObject_CallObject( extractTraceback.get(),args.get() ), SAL_NO_ACQUIRE);
     911           0 :                 str = OUString::createFromAscii( PyStr_AsString(pyStr.get()) );
     912             :             }
     913             :             else
     914             :             {
     915           0 :                 str = "Couldn't find uno._uno_extract_printable_stacktrace";
     916           0 :             }
     917             :         }
     918             :         else
     919             :         {
     920           0 :             str = "Could not load uno.py, no stacktrace available";
     921           0 :             if ( !e.Message.isEmpty() )
     922             :             {
     923           0 :                 str += OUString (" (Error loading uno.py: ");
     924           0 :                 str += e.Message;
     925           0 :                 str += OUString (")");
     926             :             }
     927           0 :         }
     928             : 
     929             :     }
     930             :     else
     931             :     {
     932             :         // it may occur, that no traceback is given (e.g. only native code below)
     933           0 :         str = "no traceback available";
     934             :     }
     935             : 
     936           0 :     if( isInstanceOfStructOrException( excValue.get() ) )
     937             :     {
     938           0 :         ret = pyObject2Any( excValue );
     939             :     }
     940             :     else
     941             :     {
     942           0 :         OUStringBuffer buf;
     943           0 :         PyRef typeName( PyObject_Str( excType.get() ), SAL_NO_ACQUIRE );
     944           0 :         if( typeName.is() )
     945             :         {
     946           0 :             buf.appendAscii( PyStr_AsString( typeName.get() ) );
     947             :         }
     948             :         else
     949             :         {
     950           0 :             buf.appendAscii( "no typename available" );
     951             :         }
     952           0 :         buf.appendAscii( ": " );
     953           0 :         PyRef valueRep( PyObject_Str( excValue.get() ), SAL_NO_ACQUIRE );
     954           0 :         if( valueRep.is() )
     955             :         {
     956           0 :             buf.appendAscii( PyStr_AsString( valueRep.get()));
     957             :         }
     958             :         else
     959             :         {
     960           0 :             buf.appendAscii( "Couldn't convert exception value to a string" );
     961             :         }
     962           0 :         buf.appendAscii( ", traceback follows\n" );
     963           0 :         if( !str.isEmpty() )
     964             :         {
     965           0 :             buf.append( str );
     966           0 :             buf.appendAscii( "\n" );
     967             :         }
     968             :         else
     969             :         {
     970           0 :             buf.appendAscii( ", no traceback available\n" );
     971             :         }
     972           0 :         RuntimeException e;
     973           0 :         e.Message = buf.makeStringAndClear();
     974             : #if OSL_DEBUG_LEVEL > 0
     975             :         fprintf( stderr, "Python exception: %s\n",
     976             :                  OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr() );
     977             : #endif
     978           0 :         ret = com::sun::star::uno::makeAny( e );
     979             :     }
     980           0 :     return ret;
     981             : }
     982             : 
     983             : 
     984             : static const char * g_NUMERICID = "pyuno.lcNumeric";
     985           6 : static ::std::vector< OString > g_localeList;
     986             : 
     987          22 : static const char *ensureUnlimitedLifetime( const char *str )
     988             : {
     989          22 :     int size = g_localeList.size();
     990             :     int i;
     991          22 :     for( i = 0 ; i < size ; i ++ )
     992             :     {
     993          18 :         if( 0 == strcmp( g_localeList[i].getStr(), str ) )
     994          18 :             break;
     995             :     }
     996          22 :     if( i == size )
     997             :     {
     998           4 :         g_localeList.push_back( str );
     999             :     }
    1000          22 :     return g_localeList[i].getStr();
    1001             : }
    1002             : 
    1003             : 
    1004          22 : PyThreadAttach::PyThreadAttach( PyInterpreterState *interp)
    1005             :     throw ( com::sun::star::uno::RuntimeException )
    1006             : {
    1007          22 :     tstate = PyThreadState_New( interp );
    1008          22 :     if( !tstate  )
    1009           0 :         throw RuntimeException( "Couldn't create a pythreadstate" );
    1010          22 :     PyEval_AcquireThread( tstate);
    1011             :     // set LC_NUMERIC to "C"
    1012             :     const char * oldLocale =
    1013          22 :         ensureUnlimitedLifetime( setlocale( LC_NUMERIC, 0 )  );
    1014          22 :     setlocale( LC_NUMERIC, "C" );
    1015             :     PyRef locale( // python requires C locale
    1016          22 :         PyLong_FromVoidPtr( (void*)oldLocale ), SAL_NO_ACQUIRE);
    1017             :     PyDict_SetItemString(
    1018          22 :         PyThreadState_GetDict(), g_NUMERICID, locale.get() );
    1019          22 : }
    1020             : 
    1021          22 : PyThreadAttach::~PyThreadAttach()
    1022             : {
    1023             :     PyObject *value =
    1024          22 :         PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID );
    1025          22 :     if( value )
    1026          22 :         setlocale( LC_NUMERIC, (const char * ) PyLong_AsVoidPtr( value ) );
    1027          22 :     PyThreadState_Clear( tstate );
    1028          22 :     PyEval_ReleaseThread( tstate );
    1029          22 :     PyThreadState_Delete( tstate );
    1030             : 
    1031          22 : }
    1032             : 
    1033        4134 : PyThreadDetach::PyThreadDetach() throw ( com::sun::star::uno::RuntimeException )
    1034             : {
    1035        4134 :     tstate = PyThreadState_Get();
    1036             :     PyObject *value =
    1037        4134 :         PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID );
    1038        4134 :     if( value )
    1039         216 :         setlocale( LC_NUMERIC, (const char * ) PyLong_AsVoidPtr( value ) );
    1040        4134 :     PyEval_ReleaseThread( tstate );
    1041        4134 : }
    1042             : 
    1043             :     /** Acquires the global interpreter lock again
    1044             : 
    1045             :     */
    1046        4134 : PyThreadDetach::~PyThreadDetach()
    1047             : {
    1048        4134 :     PyEval_AcquireThread( tstate );
    1049             : //     PyObject *value =
    1050             : //         PyDict_GetItemString( PyThreadState_GetDict( ), g_NUMERICID );
    1051             : 
    1052             :     // python requires C LC_NUMERIC locale,
    1053             :     // always set even when it is already "C"
    1054        4134 :     setlocale( LC_NUMERIC, "C" );
    1055        4134 : }
    1056             : 
    1057             : 
    1058         766 : PyRef RuntimeCargo::getUnoModule()
    1059             : {
    1060         766 :     if( ! dictUnoModule.is() )
    1061             :     {
    1062           6 :         dictUnoModule = importUnoModule();
    1063             :     }
    1064         766 :     return dictUnoModule;
    1065             : }
    1066          18 : }
    1067             : 
    1068             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10