LCOV - code coverage report
Current view: top level - libreoffice/tools/source/string - strimp.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 189 218 86.7 %
Date: 2012-12-27 Functions: 21 23 91.3 %
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           0 : static sal_Int32 ImplStringCompare( const STRCODE* pStr1, const STRCODE* pStr2,
      21             :                                     xub_StrLen nCount )
      22             : {
      23           0 :     sal_Int32 nRet = 0;
      24           0 :     while ( nCount &&
      25             :             ((nRet = ((sal_Int32)((STRCODEU)*pStr1))-((sal_Int32)((STRCODEU)*pStr2))) == 0) &&
      26             :             *pStr2 )
      27             :     {
      28             :         ++pStr1,
      29             :         ++pStr2,
      30           0 :         --nCount;
      31             :     }
      32             : 
      33           0 :     return nRet;
      34             : }
      35             : 
      36      603591 : static sal_Int32 ImplStringCompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2,
      37             :                                                sal_Int32 nCount )
      38             : {
      39      603591 :     sal_Int32 nRet = 0;
      40     5000887 :     while ( nCount &&
      41             :             ((nRet = ((sal_Int32)((STRCODEU)*pStr1))-((sal_Int32)((STRCODEU)*pStr2))) == 0) )
      42             :     {
      43             :         ++pStr1,
      44             :         ++pStr2,
      45     3793705 :         --nCount;
      46             :     }
      47             : 
      48      603591 :     return nRet;
      49             : }
      50             : 
      51             : #ifdef DBG_UTIL
      52             : const char* DBGCHECKSTRING( const void* pString )
      53             : {
      54             :     STRING* p = (STRING*)pString;
      55             : 
      56             :     if ( p->GetBuffer()[p->Len()] != 0 )
      57             :         return "String damaged: aStr[nLen] != 0";
      58             : 
      59             :     return NULL;
      60             : }
      61             : #endif
      62             : 
      63      362569 : static STRINGDATA* ImplAllocData( sal_Int32 nLen )
      64             : {
      65      362569 :     STRINGDATA* pData   = (STRINGDATA*)rtl_allocateMemory( sizeof(STRINGDATA)+(nLen*sizeof( STRCODE )) );
      66      362569 :     pData->mnRefCount   = 1;
      67      362569 :     pData->mnLen        = nLen;
      68      362569 :     pData->maStr[nLen]  = 0;
      69      362569 :     return pData;
      70             : }
      71             : 
      72      198993 : static STRINGDATA* _ImplCopyData( STRINGDATA* pData )
      73             : {
      74      198993 :     unsigned int    nSize       = sizeof(STRINGDATA)+(pData->mnLen*sizeof( STRCODE ));
      75      198993 :     STRINGDATA*     pNewData    = (STRINGDATA*)rtl_allocateMemory( nSize );
      76      198993 :     memcpy( pNewData, pData, nSize );
      77      198993 :     pNewData->mnRefCount = 1;
      78      198993 :     STRING_RELEASE((STRING_TYPE *)pData);
      79      198993 :     return pNewData;
      80             : }
      81             : 
      82      400492 : inline void STRING::ImplCopyData()
      83             : {
      84             :     DBG_ASSERT( (mpData->mnRefCount != 0), "String::ImplCopyData() - RefCount == 0" );
      85             : 
      86             :     // Dereference data if this string is referenced
      87      400492 :     if ( mpData->mnRefCount != 1 )
      88      148910 :         mpData = _ImplCopyData( mpData );
      89      400492 : }
      90             : 
      91      170488 : inline STRCODE* STRING::ImplCopyStringData( STRCODE* pStr )
      92             : {
      93      170488 :     if ( mpData->mnRefCount != 1 ) {
      94             :         DBG_ASSERT( (pStr >= mpData->maStr) &&
      95             :                     ((pStr-mpData->maStr) < mpData->mnLen),
      96             :                     "ImplCopyStringData - pStr from other String-Instanz" );
      97       50083 :         unsigned int nIndex = (unsigned int)(pStr-mpData->maStr);
      98       50083 :         mpData = _ImplCopyData( mpData );
      99       50083 :         pStr = mpData->maStr + nIndex;
     100             :     }
     101      170488 :     return pStr;
     102             : }
     103             : 
     104      115747 : inline sal_Int32 ImplGetCopyLen( sal_Int32 nStrLen, sal_Int32 nCopyLen )
     105             : {
     106             :     OSL_ASSERT(nStrLen <= STRING_MAXLEN && nCopyLen <= STRING_MAXLEN);
     107      115747 :     if ( nCopyLen > STRING_MAXLEN-nStrLen )
     108           0 :         nCopyLen = STRING_MAXLEN-nStrLen;
     109      115747 :     return nCopyLen;
     110             : }
     111             : 
     112     1386291 : STRING::STRING()
     113     1386291 :     : mpData(NULL)
     114             : {
     115             :     DBG_CTOR( STRING, DBGCHECKSTRING );
     116             : 
     117     1386291 :     STRING_NEW((STRING_TYPE **)&mpData);
     118     1386291 : }
     119             : 
     120     3073128 : STRING::STRING( const STRING& rStr )
     121             : {
     122             :     DBG_CTOR( STRING, DBGCHECKSTRING );
     123             :     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
     124             : 
     125             :     // Set pointer to argument string and increase reference counter
     126     3073128 :     STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
     127     3073128 :     mpData = rStr.mpData;
     128     3073128 : }
     129             : 
     130      128724 : STRING::STRING( const STRING& rStr, xub_StrLen nPos, xub_StrLen nLen )
     131      128724 : : mpData( NULL )
     132             : {
     133             :     DBG_CTOR( STRING, DBGCHECKSTRING );
     134             :     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
     135             : 
     136      128724 :     if ( nPos > rStr.mpData->mnLen )
     137           4 :         nLen = 0;
     138             :     else
     139             :     {
     140             :         // correct length if necessary
     141      128720 :         sal_Int32 nMaxLen = rStr.mpData->mnLen-nPos;
     142      128720 :         if ( nLen > nMaxLen )
     143        5363 :             nLen = static_cast< xub_StrLen >(nMaxLen);
     144             :     }
     145             : 
     146      128724 :     if ( nLen )
     147             :     {
     148             :         // Increase reference counter if it suffices
     149      122093 :         if ( (nPos == 0) && (nLen == rStr.mpData->mnLen) )
     150             :         {
     151       79354 :             STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
     152       79354 :             mpData = rStr.mpData;
     153             :         }
     154             :         else
     155             :         {
     156             :             // otherwise, copy string
     157       42739 :             mpData = ImplAllocData( nLen );
     158       42739 :             memcpy( mpData->maStr, rStr.mpData->maStr+nPos, nLen*sizeof( STRCODE ) );
     159             :         }
     160             :     }
     161             :     else
     162             :     {
     163        6631 :         STRING_NEW((STRING_TYPE **)&mpData);
     164             :     }
     165      128724 : }
     166             : 
     167     6566664 : STRING::~STRING()
     168             : {
     169             :     DBG_DTOR( STRING, DBGCHECKSTRING );
     170             : 
     171             :     // free string data
     172     6566664 :     STRING_RELEASE((STRING_TYPE *)mpData);
     173     6566664 : }
     174             : 
     175     1407454 : STRING& STRING::Assign( const STRING& rStr )
     176             : {
     177             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     178             :     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
     179             : 
     180     1407454 :     STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
     181     1407454 :     STRING_RELEASE((STRING_TYPE *)mpData);
     182     1407454 :     mpData = rStr.mpData;
     183     1407454 :     return *this;
     184             : }
     185             : 
     186       60479 : STRING& STRING::Append( const STRING& rStr )
     187             : {
     188             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     189             :     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
     190             : 
     191             :     // Assignment is sufficient if string is empty
     192       60479 :     sal_Int32 nLen = mpData->mnLen;
     193       60479 :     if ( !nLen )
     194             :     {
     195       20018 :         STRING_ACQUIRE((STRING_TYPE *)rStr.mpData);
     196       20018 :         STRING_RELEASE((STRING_TYPE *)mpData);
     197       20018 :         mpData = rStr.mpData;
     198             :     }
     199             :     else
     200             :     {
     201             :         // Detect overflow
     202       40461 :         sal_Int32 nCopyLen = ImplGetCopyLen( nLen, rStr.mpData->mnLen );
     203             : 
     204       40461 :         if ( nCopyLen )
     205             :         {
     206             :             // allocate string of new size
     207       37811 :             STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
     208             : 
     209             :             // copy string
     210       37811 :             memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
     211       37811 :             memcpy( pNewData->maStr+nLen, rStr.mpData->maStr, nCopyLen*sizeof( STRCODE ) );
     212             : 
     213             :             // free old string
     214       37811 :             STRING_RELEASE((STRING_TYPE *)mpData);
     215       37811 :             mpData = pNewData;
     216             :         }
     217             :     }
     218             : 
     219       60479 :     return *this;
     220             : }
     221             : 
     222        5749 : STRING& STRING::Append( const STRCODE* pCharStr )
     223             : {
     224             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     225             :     DBG_ASSERT( pCharStr, "String::Append() - pCharStr is NULL" );
     226             : 
     227             :     // determine string length
     228        5749 :     sal_Int32 nLen = mpData->mnLen;
     229        5749 :     sal_Int32 nCopyLen = ImplStringLen( pCharStr );
     230             : 
     231             :     // detect overflow
     232        5749 :     nCopyLen = ImplGetCopyLen( nLen, nCopyLen );
     233             : 
     234        5749 :     if ( nCopyLen )
     235             :     {
     236             :         // allocate string of new size
     237        5745 :         STRINGDATA* pNewData = ImplAllocData( nLen+nCopyLen );
     238             : 
     239             :         // copy string
     240        5745 :         memcpy( pNewData->maStr, mpData->maStr, nLen*sizeof( STRCODE ) );
     241        5745 :         memcpy( pNewData->maStr+nLen, pCharStr, nCopyLen*sizeof( STRCODE ) );
     242             : 
     243             :         // free old string
     244        5745 :         STRING_RELEASE((STRING_TYPE *)mpData);
     245        5745 :         mpData = pNewData;
     246             :     }
     247             : 
     248        5749 :     return *this;
     249             : }
     250             : 
     251      400129 : void STRING::SetChar( xub_StrLen nIndex, STRCODE c )
     252             : {
     253             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     254             :     DBG_ASSERT( nIndex < mpData->mnLen, "String::SetChar() - nIndex > String.Len()" );
     255             : 
     256             :     // copy data if necessary
     257      400129 :     ImplCopyData();
     258      400129 :     mpData->maStr[nIndex] = c;
     259      400129 : }
     260             : 
     261       66175 : STRING& STRING::Insert( const STRING& rStr, xub_StrLen nIndex )
     262             : {
     263             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     264             :     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
     265             : 
     266             :     // detect overflow
     267       66175 :     sal_Int32 nCopyLen = ImplGetCopyLen( mpData->mnLen, rStr.mpData->mnLen );
     268             : 
     269       66175 :     if ( !nCopyLen )
     270        4405 :         return *this;
     271             : 
     272             :     // adjust index if necessary
     273       61770 :     if ( nIndex > mpData->mnLen )
     274          63 :         nIndex = static_cast< xub_StrLen >(mpData->mnLen);
     275             : 
     276             :     // allocate string of new size
     277       61770 :     STRINGDATA* pNewData = ImplAllocData( mpData->mnLen+nCopyLen );
     278             : 
     279             :     // copy string
     280       61770 :     memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
     281       61770 :     memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr, nCopyLen*sizeof( STRCODE ) );
     282       61770 :     memcpy( pNewData->maStr+nIndex+nCopyLen, mpData->maStr+nIndex,
     283      123540 :             (mpData->mnLen-nIndex)*sizeof( STRCODE ) );
     284             : 
     285             :     // free old string
     286       61770 :     STRING_RELEASE((STRING_TYPE *)mpData);
     287       61770 :     mpData = pNewData;
     288             : 
     289       61770 :     return *this;
     290             : }
     291             : 
     292        1461 : STRING& STRING::Replace( xub_StrLen nIndex, xub_StrLen nCount, const STRING& rStr )
     293             : {
     294             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     295             :     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
     296             : 
     297             :     // Append if index > current length
     298        1461 :     if ( nIndex >= mpData->mnLen )
     299             :     {
     300           0 :         Append( rStr );
     301           0 :         return *this;
     302             :     }
     303             : 
     304             :     // assign if index = 0 and length >= stringlen
     305        1461 :     if ( (nIndex == 0) && (nCount >= mpData->mnLen) )
     306             :     {
     307          46 :         Assign( rStr );
     308          46 :         return *this;
     309             :     }
     310             : 
     311             :     // Use erase if replacestring is empty
     312        1415 :     sal_Int32 nStrLen = rStr.mpData->mnLen;
     313        1415 :     if ( !nStrLen )
     314        1069 :         return Erase( nIndex, nCount );
     315             : 
     316             :     // Adjust nCount if it's larger than the string
     317         346 :     if ( nCount > mpData->mnLen - nIndex )
     318           0 :         nCount = static_cast< xub_StrLen >(mpData->mnLen-nIndex);
     319             : 
     320         346 :     if ( !nCount )
     321           0 :         return Insert( rStr, nIndex );
     322             : 
     323             :     // Use character-based assignment if length is equal
     324         346 :     if ( nCount == nStrLen )
     325             :     {
     326          21 :         ImplCopyData();
     327          21 :         memcpy( mpData->maStr+nIndex, rStr.mpData->maStr, nCount*sizeof( STRCODE ) );
     328          21 :         return *this;
     329             :     }
     330             : 
     331             :     // detect overflow
     332         325 :     nStrLen = ImplGetCopyLen( mpData->mnLen-nCount, nStrLen );
     333             : 
     334             :     // allocate string of new size
     335         325 :     STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount+nStrLen );
     336             : 
     337             :     // copy string
     338         325 :     memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
     339         325 :     memcpy( pNewData->maStr+nIndex, rStr.mpData->maStr, nStrLen*sizeof( STRCODE ) );
     340         325 :     memcpy( pNewData->maStr+nIndex+nStrLen, mpData->maStr+nIndex+nCount,
     341         650 :             (mpData->mnLen-nIndex-nCount+1)*sizeof( STRCODE ) );
     342             : 
     343             :     // free old string
     344         325 :     STRING_RELEASE((STRING_TYPE *)mpData);
     345         325 :     mpData = pNewData;
     346             : 
     347         325 :     return *this;
     348             : }
     349             : 
     350      238593 : STRING& STRING::Erase( xub_StrLen nIndex, xub_StrLen nCount )
     351             : {
     352             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     353             : 
     354             :     // Return if index outside string or count = 0
     355      238593 :     if ( (nIndex >= mpData->mnLen) || !nCount )
     356       62819 :         return *this;
     357             : 
     358             :     // Adjust nCount if it's larger than the string
     359      175774 :     if ( nCount > mpData->mnLen - nIndex )
     360        7338 :         nCount = static_cast< xub_StrLen >(mpData->mnLen-nIndex);
     361             : 
     362      175774 :     if ( mpData->mnLen - nCount )
     363             :     {
     364             :         // allocate string of new size
     365      171002 :         STRINGDATA* pNewData = ImplAllocData( mpData->mnLen-nCount );
     366             : 
     367             :         // copy string
     368      171002 :         memcpy( pNewData->maStr, mpData->maStr, nIndex*sizeof( STRCODE ) );
     369      171002 :         memcpy( pNewData->maStr+nIndex, mpData->maStr+nIndex+nCount,
     370      342004 :                 (mpData->mnLen-nIndex-nCount+1)*sizeof( STRCODE ) );
     371             : 
     372             :         // free old string
     373      171002 :         STRING_RELEASE((STRING_TYPE *)mpData);
     374      171002 :         mpData = pNewData;
     375             :     }
     376             :     else
     377             :     {
     378        4772 :         STRING_NEW((STRING_TYPE **)&mpData);
     379             :     }
     380             : 
     381      175774 :     return *this;
     382             : }
     383             : 
     384       66202 : STRING& STRING::ToLowerAscii()
     385             : {
     386             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     387             : 
     388       66202 :     sal_Int32 nIndex = 0;
     389       66202 :     sal_Int32 nLen = mpData->mnLen;
     390       66202 :     STRCODE*    pStr = mpData->maStr;
     391      972859 :     while ( nIndex < nLen )
     392             :     {
     393             :         // Convert if char is between 'A' and 'Z'
     394      840455 :         if ( (*pStr >= 65) && (*pStr <= 90) )
     395             :         {
     396             :             // allocate string of new size
     397      170430 :             pStr = ImplCopyStringData( pStr );
     398      170430 :             *pStr += 32;
     399             :         }
     400             : 
     401             :         ++pStr,
     402      840455 :         ++nIndex;
     403             :     }
     404             : 
     405       66202 :     return *this;
     406             : }
     407             : 
     408      404276 : xub_StrLen STRING::Search( STRCODE c, xub_StrLen nIndex ) const
     409             : {
     410             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     411             : 
     412      404276 :     sal_Int32       nLen = mpData->mnLen;
     413      404276 :     const STRCODE*  pStr = mpData->maStr;
     414      404276 :     pStr += nIndex;
     415     4634275 :     while ( nIndex < nLen )
     416             :     {
     417     3828646 :         if ( *pStr == c )
     418        2923 :             return nIndex;
     419             :         ++pStr,
     420     3825723 :         ++nIndex;
     421             :     }
     422             : 
     423      401353 :     return STRING_NOTFOUND;
     424             : }
     425             : 
     426        5238 : xub_StrLen STRING::Search( const STRING& rStr, xub_StrLen nIndex ) const
     427             : {
     428             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     429             :     DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING );
     430             : 
     431        5238 :     sal_Int32 nLen = mpData->mnLen;
     432        5238 :     sal_Int32 nStrLen = rStr.mpData->mnLen;
     433             : 
     434             :     // rStr was not found if its length is zero
     435             :     // or index is larger than searched string
     436        5238 :     if ( !nStrLen || (nIndex >= nLen) )
     437          11 :         return STRING_NOTFOUND;
     438             : 
     439        5227 :     const STRCODE* pStr1 = mpData->maStr;
     440        5227 :     pStr1 += nIndex;
     441             : 
     442        5227 :     if ( nStrLen == 1 )
     443             :     {
     444         568 :         STRCODE cSearch = rStr.mpData->maStr[0];
     445        2381 :         while ( nIndex < nLen )
     446             :         {
     447        1245 :             if ( *pStr1 == cSearch )
     448           0 :                 return nIndex;
     449             :             ++pStr1,
     450        1245 :             ++nIndex;
     451             :         }
     452             :     }
     453             :     else
     454             :     {
     455        4659 :         const STRCODE* pStr2 = rStr.mpData->maStr;
     456             : 
     457             :         // search only within string
     458       47610 :         while ( nLen - nIndex >= nStrLen )
     459             :         {
     460             :             // increase match if found
     461       41069 :             if ( ImplStringCompareWithoutZero( pStr1, pStr2, nStrLen ) == 0 )
     462        2777 :                 return nIndex;
     463             :             ++pStr1,
     464       38292 :             ++nIndex;
     465             :         }
     466             :     }
     467             : 
     468        2450 :     return STRING_NOTFOUND;
     469             : }
     470             : 
     471           0 : xub_StrLen STRING::Search( const STRCODE* pCharStr, xub_StrLen nIndex ) const
     472             : {
     473             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     474             : 
     475           0 :     sal_Int32 nLen = mpData->mnLen;
     476           0 :     xub_StrLen nStrLen  = ImplStringLen( pCharStr );
     477             : 
     478             :     // rStr was not found if its length is zero
     479             :     // or index is larger than searched string
     480           0 :     if ( !nStrLen || (nIndex >= nLen) )
     481           0 :         return STRING_NOTFOUND;
     482             : 
     483           0 :     const STRCODE* pStr = mpData->maStr;
     484           0 :     pStr += nIndex;
     485             : 
     486           0 :     if ( nStrLen == 1 )
     487             :     {
     488           0 :         STRCODE cSearch = *pCharStr;
     489           0 :         while ( nIndex < nLen )
     490             :         {
     491           0 :             if ( *pStr == cSearch )
     492           0 :                 return nIndex;
     493             :             ++pStr,
     494           0 :             ++nIndex;
     495             :         }
     496             :     }
     497             :     else
     498             :     {
     499             :         // search only within string
     500           0 :         while ( nLen - nIndex >= nStrLen )
     501             :         {
     502             :             // increase match if found
     503           0 :             if ( ImplStringCompareWithoutZero( pStr, pCharStr, nStrLen ) == 0 )
     504           0 :                 return nIndex;
     505             :             ++pStr,
     506           0 :             ++nIndex;
     507             :         }
     508             :     }
     509             : 
     510           0 :     return STRING_NOTFOUND;
     511             : }
     512             : 
     513         227 : void STRING::SearchAndReplaceAll( STRCODE c, STRCODE cRep )
     514             : {
     515             :     DBG_CHKTHIS( STRING, DBGCHECKSTRING );
     516             : 
     517         227 :     sal_Int32       nLen    = mpData->mnLen;
     518         227 :     const STRCODE*  pStr    = mpData->maStr;
     519         227 :     sal_Int32       nIndex  = 0;
     520        3999 :     while ( nIndex < nLen )
     521             :     {
     522        3545 :         if ( *pStr == c )
     523             :         {
     524           3 :             ImplCopyData();
     525           3 :             mpData->maStr[nIndex] = cRep;
     526             :         }
     527             :         ++pStr,
     528        3545 :         ++nIndex;
     529             :     }
     530         227 : }
     531             : 
     532             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10