LCOV - code coverage report
Current view: top level - bridges/source/cpp_uno/gcc3_linux_x86-64 - uno2cpp.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 143 167 85.6 %
Date: 2015-06-13 12:38:46 Functions: 7 8 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; 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 <sal/alloca.h>
      21             : 
      22             : #include <exception>
      23             : #include <typeinfo>
      24             : 
      25             : #include "rtl/alloc.h"
      26             : #include "rtl/ustrbuf.hxx"
      27             : 
      28             : #include <com/sun/star/uno/genfunc.hxx>
      29             : #include "com/sun/star/uno/RuntimeException.hpp"
      30             : #include <uno/data.h>
      31             : 
      32             : #include <bridges/cpp_uno/shared/bridge.hxx>
      33             : #include <bridges/cpp_uno/shared/types.hxx>
      34             : #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
      35             : #include "bridges/cpp_uno/shared/vtables.hxx"
      36             : 
      37             : #include "abi.hxx"
      38             : #include "callvirtualmethod.hxx"
      39             : #include "share.hxx"
      40             : 
      41             : using namespace ::com::sun::star::uno;
      42             : 
      43             : namespace {
      44             : 
      45             : // Functions for easier insertion of values to registers or stack
      46             : // pSV - pointer to the source
      47             : // nr - order of the value [will be increased if stored to register]
      48             : // pFPR, pGPR - pointer to the registers
      49             : // pDS - pointer to the stack [will be increased if stored here]
      50             : 
      51             : // The value in %xmm register is already prepared to be retrieved as a float,
      52             : // thus we treat float and double the same
      53        1540 : void INSERT_FLOAT_DOUBLE(
      54             :     void const * pSV, sal_uInt32 & nr, double * pFPR, sal_uInt64 *& pDS)
      55             : {
      56        1540 :     if ( nr < x86_64::MAX_SSE_REGS )
      57        1538 :         pFPR[nr++] = *static_cast<double const *>( pSV );
      58             :     else
      59           2 :         *pDS++ = *static_cast<sal_uInt64 const *>( pSV ); // verbatim!
      60        1540 : }
      61             : 
      62     1106046 : void INSERT_INT64(
      63             :     void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
      64             : {
      65     1106046 :     if ( nr < x86_64::MAX_GPR_REGS )
      66     1105196 :         pGPR[nr++] = *static_cast<sal_uInt64 const *>( pSV );
      67             :     else
      68         850 :         *pDS++ = *static_cast<sal_uInt64 const *>( pSV );
      69     1106046 : }
      70             : 
      71      157323 : void INSERT_INT32(
      72             :     void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
      73             : {
      74      157323 :     if ( nr < x86_64::MAX_GPR_REGS )
      75      157316 :         pGPR[nr++] = *static_cast<sal_uInt32 const *>( pSV );
      76             :     else
      77           7 :         *pDS++ = *static_cast<sal_uInt32 const *>( pSV );
      78      157323 : }
      79             : 
      80        9735 : void INSERT_INT16(
      81             :     void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
      82             : {
      83        9735 :     if ( nr < x86_64::MAX_GPR_REGS )
      84        9735 :         pGPR[nr++] = *static_cast<sal_uInt16 const *>( pSV );
      85             :     else
      86           0 :         *pDS++ = *static_cast<sal_uInt16 const *>( pSV );
      87        9735 : }
      88             : 
      89        7321 : void INSERT_INT8(
      90             :     void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
      91             : {
      92        7321 :     if ( nr < x86_64::MAX_GPR_REGS )
      93        7312 :         pGPR[nr++] = *static_cast<sal_uInt8 const *>( pSV );
      94             :     else
      95           9 :         *pDS++ = *static_cast<sal_uInt8 const *>( pSV );
      96        7321 : }
      97             : 
      98           0 : void appendCString(OUStringBuffer & buffer, char const * text) {
      99           0 :     if (text != 0) {
     100             :         buffer.append(
     101           0 :             OStringToOUString(OString(text), RTL_TEXTENCODING_ISO_8859_1));
     102             :             // use 8859-1 to avoid conversion failure
     103             :     }
     104           0 : }
     105             : 
     106             : }
     107             : 
     108      561279 : static void cpp_call(
     109             :     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
     110             :     bridges::cpp_uno::shared::VtableSlot aVtableSlot,
     111             :     typelib_TypeDescriptionReference * pReturnTypeRef,
     112             :     sal_Int32 nParams, typelib_MethodParameter * pParams,
     113             :     void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
     114             : {
     115             :     // Maxium space for [complex ret ptr], values | ptr ...
     116             :     // (but will be used less - some of the values will be in pGPR and pFPR)
     117      561279 :       sal_uInt64 *pStack = static_cast<sal_uInt64 *>(__builtin_alloca( (nParams + 3) * sizeof(sal_uInt64) ));
     118      561279 :       sal_uInt64 *pStackStart = pStack;
     119             : 
     120             :     sal_uInt64 pGPR[x86_64::MAX_GPR_REGS];
     121      561279 :     sal_uInt32 nGPR = 0;
     122             : 
     123             :     double pFPR[x86_64::MAX_SSE_REGS];
     124      561279 :     sal_uInt32 nFPR = 0;
     125             : 
     126             :     // Return
     127      561279 :     typelib_TypeDescription * pReturnTypeDescr = 0;
     128      561279 :     TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
     129             :     assert(pReturnTypeDescr);
     130             : 
     131      561280 :     void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion (see below)
     132             : 
     133      561280 :     bool bSimpleReturn = true;
     134      561280 :     if ( pReturnTypeDescr )
     135             :     {
     136      561280 :         if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
     137      303778 :             bSimpleReturn = false;
     138             : 
     139      561279 :         if ( bSimpleReturn )
     140      257501 :             pCppReturn = pUnoReturn; // direct way for simple types
     141             :         else
     142             :         {
     143             :             // complex return via ptr
     144      303778 :             pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
     145      303778 :                          __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn;
     146      303778 :             INSERT_INT64( &pCppReturn, nGPR, pGPR, pStack );
     147             :         }
     148             :     }
     149             : 
     150             :     // Push "this" pointer
     151      561277 :     void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
     152      561275 :     INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
     153             : 
     154             :     // Args
     155      561274 :     void ** pCppArgs = static_cast<void **>(alloca( 3 * sizeof(void *) * nParams ));
     156             :     // Indices of values this have to be converted (interface conversion cpp<=>uno)
     157      561274 :     sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pCppArgs + nParams);
     158             :     // Type descriptions for reconversions
     159      561274 :     typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pCppArgs + (2 * nParams));
     160             : 
     161      561274 :     sal_Int32 nTempIndices = 0;
     162             : 
     163      978188 :     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
     164             :     {
     165      416914 :         const typelib_MethodParameter & rParam = pParams[nPos];
     166      416914 :         typelib_TypeDescription * pParamTypeDescr = 0;
     167      416914 :         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
     168             : 
     169      416914 :         if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
     170             :         {
     171      527805 :             uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
     172      703741 :                                     pThis->getBridge()->getUno2Cpp() );
     173             : 
     174      175936 :             switch (pParamTypeDescr->eTypeClass)
     175             :             {
     176             :             case typelib_TypeClass_HYPER:
     177             :             case typelib_TypeClass_UNSIGNED_HYPER:
     178          18 :                 INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack );
     179          18 :                 break;
     180             :             case typelib_TypeClass_LONG:
     181             :             case typelib_TypeClass_UNSIGNED_LONG:
     182             :             case typelib_TypeClass_ENUM:
     183      157322 :                 INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack );
     184      157322 :                 break;
     185             :             case typelib_TypeClass_SHORT:
     186             :             case typelib_TypeClass_CHAR:
     187             :             case typelib_TypeClass_UNSIGNED_SHORT:
     188        9735 :                 INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack );
     189        9735 :                 break;
     190             :             case typelib_TypeClass_BOOLEAN:
     191             :             case typelib_TypeClass_BYTE:
     192        7321 :                 INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack );
     193        7321 :                 break;
     194             :             case typelib_TypeClass_FLOAT:
     195             :             case typelib_TypeClass_DOUBLE:
     196        1540 :                 INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, pStack );
     197        1540 :                 break;
     198             :             default:
     199           0 :                 break;
     200             :             }
     201             : 
     202             :             // no longer needed
     203      175936 :             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
     204             :         }
     205             :         else // ptr to complex value | ref
     206             :         {
     207      240978 :             if (! rParam.bIn) // is pure out
     208             :             {
     209             :                 // cpp out is constructed mem, uno out is not!
     210             :                 uno_constructData(
     211         720 :                     pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
     212        1080 :                     pParamTypeDescr );
     213         360 :                 pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
     214             :                 // will be released at reconversion
     215         360 :                 ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
     216             :             }
     217             :             // is in/inout
     218      240618 :             else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
     219             :             {
     220             :                 uno_copyAndConvertData(
     221       60778 :                     pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
     222       91167 :                     pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
     223             : 
     224       30389 :                 pTempIndices[nTempIndices] = nPos; // has to be reconverted
     225             :                 // will be released at reconversion
     226       30389 :                 ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
     227             :             }
     228             :             else // direct way
     229             :             {
     230      210229 :                 pCppArgs[nPos] = pUnoArgs[nPos];
     231             :                 // no longer needed
     232      210229 :                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
     233             :             }
     234      240978 :             INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
     235             :         }
     236             :     }
     237             : 
     238             :     try
     239             :     {
     240             :         try {
     241             :             CPPU_CURRENT_NAMESPACE::callVirtualMethod(
     242             :                 pAdjustedThisPtr, aVtableSlot.index,
     243             :                 pCppReturn, pReturnTypeRef, bSimpleReturn,
     244      561274 :                 pStackStart, ( pStack - pStackStart ),
     245      561274 :                 pGPR, pFPR );
     246        9792 :         } catch (const Exception &) {
     247        4896 :             throw;
     248           0 :         } catch (const std::exception & e) {
     249           0 :             OUStringBuffer buf;
     250           0 :             buf.append("C++ code threw ");
     251           0 :             appendCString(buf, typeid(e).name());
     252           0 :             buf.append(": ");
     253           0 :             appendCString(buf, e.what());
     254           0 :             throw RuntimeException(buf.makeStringAndClear());
     255           0 :         } catch (...) {
     256           0 :             throw RuntimeException("C++ code threw unknown exception");
     257             :         }
     258             : 
     259      556386 :         *ppUnoExc = 0;
     260             : 
     261             :         // reconvert temporary params
     262     1143032 :         for ( ; nTempIndices--; )
     263             :         {
     264       30260 :             sal_Int32 nIndex = pTempIndices[nTempIndices];
     265       30260 :             typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
     266             : 
     267       30260 :             if (pParams[nIndex].bIn)
     268             :             {
     269       29900 :                 if (pParams[nIndex].bOut) // inout
     270             :                 {
     271           6 :                     uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
     272          12 :                     uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
     273          18 :                                             pThis->getBridge()->getCpp2Uno() );
     274             :                 }
     275             :             }
     276             :             else // pure out
     277             :             {
     278         720 :                 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
     279        1080 :                                         pThis->getBridge()->getCpp2Uno() );
     280             :             }
     281             :             // destroy temp cpp param => cpp: every param was constructed
     282       30260 :             uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
     283             : 
     284       30260 :             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
     285             :         }
     286             :         // return value
     287      556386 :         if (pCppReturn && pUnoReturn != pCppReturn)
     288             :         {
     289             :             uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
     290      232183 :                                     pThis->getBridge()->getCpp2Uno() );
     291      232183 :             uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
     292             :         }
     293             :     }
     294        4896 :      catch (...)
     295             :      {
     296             :          // fill uno exception
     297             : #ifdef _LIBCPP_VERSION
     298             :          CPPU_CURRENT_NAMESPACE::fillUnoException(
     299             :              reinterpret_cast< __cxxabiv1::__cxa_eh_globals * >(
     300             :                  __cxxabiv1::__cxa_get_globals())->caughtExceptions,
     301             :              *ppUnoExc, pThis->getBridge()->getCpp2Uno());
     302             : #else
     303             :          fillUnoException(
     304             :              reinterpret_cast< CPPU_CURRENT_NAMESPACE::__cxa_eh_globals * >(
     305        4896 :                  __cxxabiv1::__cxa_get_globals())->caughtExceptions,
     306        9792 :              *ppUnoExc, pThis->getBridge()->getCpp2Uno());
     307             : #endif
     308             : 
     309             :         // temporary params
     310       10281 :         for ( ; nTempIndices--; )
     311             :         {
     312         489 :             sal_Int32 nIndex = pTempIndices[nTempIndices];
     313             :             // destroy temp cpp param => cpp: every param was constructed
     314         489 :             uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
     315         489 :             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
     316             :         }
     317             :         // return type
     318        4896 :         if (pReturnTypeDescr)
     319        4896 :             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
     320             :     }
     321      561282 : }
     322             : 
     323             : 
     324             : namespace bridges { namespace cpp_uno { namespace shared {
     325             : 
     326      571464 : void unoInterfaceProxyDispatch(
     327             :     uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
     328             :     void * pReturn, void * pArgs[], uno_Any ** ppException )
     329             : {
     330             :     // is my surrogate
     331             :     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
     332      571464 :         = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
     333             : #if OSL_DEBUG_LEVEL > 0
     334             :     typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
     335             : #endif
     336             : 
     337      571464 :     switch (pMemberDescr->eTypeClass)
     338             :     {
     339             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     340             :     {
     341             : #if OSL_DEBUG_LEVEL > 0
     342             :         // determine vtable call index
     343             :         sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberDescr)->nPosition;
     344             :         assert(nMemberPos < pTypeDescr->nAllMembers);
     345             : #endif
     346             :         VtableSlot aVtableSlot(
     347             :                 getVtableSlot(
     348             :                     reinterpret_cast<
     349             :                     typelib_InterfaceAttributeTypeDescription const * >(
     350        8622 :                         pMemberDescr)));
     351             : 
     352        8622 :         if (pReturn)
     353             :         {
     354             :             // dependent dispatch
     355             :             cpp_call(
     356             :                 pThis, aVtableSlot,
     357             :                 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef,
     358             :                 0, 0, // no params
     359        7024 :                 pReturn, pArgs, ppException );
     360             :         }
     361             :         else
     362             :         {
     363             :             // is SET
     364             :             typelib_MethodParameter aParam;
     365             :             aParam.pTypeRef =
     366        1598 :                 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef;
     367        1598 :             aParam.bIn      = sal_True;
     368        1598 :             aParam.bOut     = sal_False;
     369             : 
     370        1598 :             typelib_TypeDescriptionReference * pReturnTypeRef = 0;
     371        1598 :             OUString aVoidName("void");
     372             :             typelib_typedescriptionreference_new(
     373        1598 :                 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
     374             : 
     375             :             // dependent dispatch
     376        1598 :             aVtableSlot.index += 1; // get, then set method
     377             :             cpp_call(
     378             :                 pThis, aVtableSlot, // get, then set method
     379             :                 pReturnTypeRef,
     380             :                 1, &aParam,
     381        1598 :                 pReturn, pArgs, ppException );
     382             : 
     383        1598 :             typelib_typedescriptionreference_release( pReturnTypeRef );
     384             :         }
     385             : 
     386        8622 :         break;
     387             :     }
     388             :     case typelib_TypeClass_INTERFACE_METHOD:
     389             :     {
     390             : #if OSL_DEBUG_LEVEL > 0
     391             :         // determine vtable call index
     392             :         sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberDescr)->nPosition;
     393             :         assert(nMemberPos < pTypeDescr->nAllMembers);
     394             : #endif
     395             :         VtableSlot aVtableSlot(
     396             :                 getVtableSlot(
     397             :                     reinterpret_cast<
     398             :                     typelib_InterfaceMethodTypeDescription const * >(
     399      562842 :                         pMemberDescr)));
     400             : 
     401      562844 :         switch (aVtableSlot.index)
     402             :         {
     403             :             // standard calls
     404             :         case 1: // acquire uno interface
     405           0 :             (*pUnoI->acquire)( pUnoI );
     406           0 :             *ppException = 0;
     407           0 :             break;
     408             :         case 2: // release uno interface
     409           0 :             (*pUnoI->release)( pUnoI );
     410           0 :             *ppException = 0;
     411           0 :             break;
     412             :         case 0: // queryInterface() opt
     413             :         {
     414      111582 :             typelib_TypeDescription * pTD = 0;
     415      111582 :             TYPELIB_DANGER_GET( &pTD, static_cast< Type * >( pArgs[0] )->getTypeLibType() );
     416      111582 :             if (pTD)
     417             :             {
     418      111582 :                 uno_Interface * pInterface = 0;
     419      111582 :                 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
     420             :                     pThis->getBridge()->getUnoEnv(),
     421      111582 :                     reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
     422             : 
     423      111582 :                 if (pInterface)
     424             :                 {
     425             :                     ::uno_any_construct(
     426             :                         static_cast< uno_Any * >( pReturn ),
     427       10185 :                         &pInterface, pTD, 0 );
     428       10185 :                     (*pInterface->release)( pInterface );
     429       10185 :                     TYPELIB_DANGER_RELEASE( pTD );
     430       10185 :                     *ppException = 0;
     431       10185 :                     break;
     432             :                 }
     433      101397 :                 TYPELIB_DANGER_RELEASE( pTD );
     434             :             }
     435             :         } // else perform queryInterface()
     436             :         default:
     437             :             // dependent dispatch
     438             :             cpp_call(
     439             :                 pThis, aVtableSlot,
     440             :                 reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pReturnTypeRef,
     441             :                 reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->nParams,
     442             :                 reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pParams,
     443      552659 :                 pReturn, pArgs, ppException );
     444             :         }
     445      562845 :         break;
     446             :     }
     447             :     default:
     448             :     {
     449             :         ::com::sun::star::uno::RuntimeException aExc(
     450             :             OUString("illegal member type description!"),
     451           0 :             ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
     452             : 
     453           0 :         Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
     454             :         // binary identical null reference
     455           0 :         ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
     456             :     }
     457             :     }
     458      571467 : }
     459             : 
     460             : } } }
     461             : 
     462             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11