LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sal/rtl - bootstrap.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 354 419 84.5 %
Date: 2013-07-09 Functions: 38 42 90.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             : 
      21             : #include "rtl/bootstrap.h"
      22             : #include "rtl/bootstrap.hxx"
      23             : #include <osl/diagnose.h>
      24             : #include <osl/module.h>
      25             : #include <osl/process.h>
      26             : #include <osl/file.hxx>
      27             : #include <osl/mutex.hxx>
      28             : #include <osl/profile.hxx>
      29             : #include <osl/security.hxx>
      30             : #include <rtl/alloc.h>
      31             : #include <rtl/string.hxx>
      32             : #include <rtl/ustrbuf.hxx>
      33             : #include <rtl/ustring.hxx>
      34             : #include <rtl/byteseq.hxx>
      35             : #include <rtl/instance.hxx>
      36             : #include <rtl/malformeduriexception.hxx>
      37             : #include <rtl/uri.hxx>
      38             : #include "rtl/allocator.hxx"
      39             : 
      40             : #include <boost/unordered_map.hpp>
      41             : #include <list>
      42             : 
      43             : #ifdef ANDROID
      44             : #include <osl/detail/android-bootstrap.h>
      45             : #endif
      46             : 
      47             : #ifdef IOS
      48             : #include <premac.h>
      49             : #import <Foundation/Foundation.h>
      50             : #include <postmac.h>
      51             : #endif
      52             : 
      53             : using osl::DirectoryItem;
      54             : using osl::FileStatus;
      55             : 
      56             : using rtl::OString;
      57             : using rtl::OUString;
      58             : using rtl::OUStringToOString;
      59             : 
      60             : struct Bootstrap_Impl;
      61             : 
      62             : namespace {
      63             : 
      64             : static char const VND_SUN_STAR_PATHNAME[] = "vnd.sun.star.pathname:";
      65             : 
      66         432 : bool isPathnameUrl(rtl::OUString const & url) {
      67             :     return url.matchIgnoreAsciiCaseAsciiL(
      68         432 :         RTL_CONSTASCII_STRINGPARAM(VND_SUN_STAR_PATHNAME));
      69             : }
      70             : 
      71         201 : bool resolvePathnameUrl(rtl::OUString * url) {
      72             :     OSL_ASSERT(url !=  NULL);
      73         655 :     if (!isPathnameUrl(*url) ||
      74             :         (osl::FileBase::getFileURLFromSystemPath(
      75         357 :             url->copy(RTL_CONSTASCII_LENGTH(VND_SUN_STAR_PATHNAME)), *url) ==
      76             :          osl::FileBase::E_None))
      77             :     {
      78         201 :         return true;
      79             :     } else {
      80           0 :         *url = rtl::OUString();
      81           0 :         return false;
      82             :     }
      83             : }
      84             : 
      85             : enum LookupMode {
      86             :     LOOKUP_MODE_NORMAL, LOOKUP_MODE_URE_BOOTSTRAP,
      87             :     LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION };
      88             : 
      89       86571 : struct ExpandRequestLink {
      90             :     ExpandRequestLink const * next;
      91             :     Bootstrap_Impl const * file;
      92             :     rtl::OUString key;
      93             : };
      94             : 
      95             : rtl::OUString expandMacros(
      96             :     Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode,
      97             :     ExpandRequestLink const * requestStack);
      98             : 
      99       86571 : rtl::OUString recursivelyExpandMacros(
     100             :     Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode,
     101             :     Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey,
     102             :     ExpandRequestLink const * requestStack)
     103             : {
     104      126631 :     for (; requestStack != NULL; requestStack = requestStack->next) {
     105       49966 :         if (requestStack->file == requestFile &&
     106        9906 :             requestStack->key == requestKey)
     107             :         {
     108           0 :             return rtl::OUString("***RECURSION DETECTED***");
     109             :         }
     110             :     }
     111       86571 :     ExpandRequestLink link = { requestStack, requestFile, requestKey };
     112       86571 :     return expandMacros(file, text, mode, &link);
     113             : }
     114             : 
     115             : }
     116             : 
     117             : //----------------------------------------------------------------------------
     118             : 
     119       75614 : struct rtl_bootstrap_NameValue
     120             : {
     121             :     OUString sName;
     122             :     OUString sValue;
     123             : 
     124       28245 :     inline rtl_bootstrap_NameValue() SAL_THROW( () )
     125       28245 :         {}
     126          64 :     inline rtl_bootstrap_NameValue(
     127             :         OUString const & name, OUString const & value ) SAL_THROW( () )
     128             :         : sName( name ),
     129          64 :           sValue( value )
     130          64 :         {}
     131             : };
     132             : 
     133             : typedef std::list<
     134             :     rtl_bootstrap_NameValue,
     135             :     rtl::Allocator< rtl_bootstrap_NameValue >
     136             : > NameValueList;
     137             : 
     138      260292 : bool find(
     139             :     NameValueList const & list, rtl::OUString const & key,
     140             :     rtl::OUString * value)
     141             : {
     142             :     OSL_ASSERT(value != NULL);
     143     1417406 :     for (NameValueList::const_iterator i(list.begin()); i != list.end(); ++i) {
     144     1221170 :         if (i->sName == key) {
     145       64056 :             *value = i->sValue;
     146       64056 :             return true;
     147             :         }
     148             :     }
     149      196236 :     return false;
     150             : }
     151             : 
     152             : namespace {
     153             :     struct rtl_bootstrap_set_list :
     154             :         public rtl::Static< NameValueList, rtl_bootstrap_set_list > {};
     155             : }
     156             : 
     157             : //----------------------------------------------------------------------------
     158             : 
     159       91216 : static sal_Bool getFromCommandLineArgs(
     160             :     rtl::OUString const & key, rtl::OUString * value )
     161             : {
     162             :     OSL_ASSERT(value != NULL);
     163             :     static NameValueList *pNameValueList = 0;
     164       91216 :     if( ! pNameValueList )
     165             :     {
     166         540 :         static NameValueList nameValueList;
     167             : 
     168         540 :         sal_Int32 nArgCount = osl_getCommandArgCount();
     169        4447 :         for(sal_Int32 i = 0; i < nArgCount; ++ i)
     170             :         {
     171        3907 :             rtl_uString *pArg = 0;
     172        3907 :             osl_getCommandArg( i, &pArg );
     173        6807 :             if( ('-' == pArg->buffer[0] || '/' == pArg->buffer[0] ) &&
     174        4231 :                 'e' == pArg->buffer[1] &&
     175        2662 :                 'n' == pArg->buffer[2] &&
     176        2662 :                 'v' == pArg->buffer[3] &&
     177        1331 :                 ':' == pArg->buffer[4] )
     178             :             {
     179        1331 :                 sal_Int32 nIndex = rtl_ustr_indexOfChar( pArg->buffer, '=' );
     180        1331 :                 if( nIndex >= 0 )
     181             :                 {
     182             : 
     183        1331 :                     rtl_bootstrap_NameValue nameValue;
     184        1331 :                     nameValue.sName = OUString( &(pArg->buffer[5]), nIndex - 5  );
     185        1331 :                     nameValue.sValue = OUString( &(pArg->buffer[nIndex+1]) );
     186        2994 :                     if( i == nArgCount-1 &&
     187        1663 :                         nameValue.sValue.getLength() &&
     188         332 :                         nameValue.sValue[nameValue.sValue.getLength()-1] == 13 )
     189             :                     {
     190             :                         // avoid the 13 linefeed for the last argument,
     191             :                         // when the executable is started from a script,
     192             :                         // that was edited on windows
     193           0 :                         nameValue.sValue = nameValue.sValue.copy(0,nameValue.sValue.getLength()-1);
     194             :                     }
     195        1331 :                     nameValueList.push_back( nameValue );
     196             :                 }
     197             :             }
     198        3907 :             rtl_uString_release( pArg );
     199             :         }
     200         540 :         pNameValueList = &nameValueList;
     201             :     }
     202             : 
     203       91216 :     sal_Bool found = sal_False;
     204             : 
     205      744285 :     for( NameValueList::iterator ii = pNameValueList->begin() ;
     206      496190 :          ii != pNameValueList->end() ;
     207             :          ++ii )
     208             :     {
     209      179332 :         if( (*ii).sName.equals(key) )
     210             :         {
     211       22453 :             *value = (*ii).sValue;
     212       22453 :             found = sal_True;
     213       22453 :             break;
     214             :         }
     215             :     }
     216             : 
     217       91216 :     return found;
     218             : }
     219             : 
     220             : //----------------------------------------------------------------------------
     221             : 
     222             : extern "C" oslProcessError SAL_CALL osl_bootstrap_getExecutableFile_Impl (
     223             :     rtl_uString ** ppFileURL) SAL_THROW_EXTERN_C();
     224             : 
     225         487 : inline void getExecutableFile_Impl (rtl_uString ** ppFileURL)
     226             : {
     227         487 :     osl_bootstrap_getExecutableFile_Impl (ppFileURL);
     228         487 : }
     229             : 
     230             : //----------------------------------------------------------------------------
     231             : 
     232           0 : static void getExecutableDirectory_Impl (rtl_uString ** ppDirURL)
     233             : {
     234           0 :     OUString fileName;
     235           0 :     getExecutableFile_Impl (&(fileName.pData));
     236             : 
     237           0 :     sal_Int32 nDirEnd = fileName.lastIndexOf('/');
     238             :     OSL_ENSURE(nDirEnd >= 0, "Cannot locate executable directory");
     239             : 
     240           0 :     rtl_uString_newFromStr_WithLength(ppDirURL,fileName.getStr(),nDirEnd);
     241           0 : }
     242             : 
     243             : //----------------------------------------------------------------------------
     244             : 
     245        5614 : static OUString & getIniFileName_Impl()
     246             : {
     247        5614 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     248             :     static OUString *pStaticName = 0;
     249        5614 :     if( ! pStaticName )
     250             :     {
     251         540 :         OUString fileName;
     252             : 
     253             : #if defined IOS
     254             :         // On iOS hardcode the inifile as "rc" in the .app
     255             :         // directory. Apps are self-contained anyway, there is no
     256             :         // possibility to have several "applications" in the same
     257             :         // installation location with different inifiles.
     258             :         const char *inifile = [[@"vnd.sun.star.pathname:" stringByAppendingString: [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: @"rc"]] UTF8String];
     259             :         fileName = rtl::OUString(inifile, strlen(inifile), RTL_TEXTENCODING_UTF8);
     260             :         resolvePathnameUrl(&fileName);
     261             : #elif defined ANDROID
     262             :         // Apps are self-contained on Android, too, can as well hardcode
     263             :         // it as "rc" in the "/assets" directory, i.e.  inside the app's
     264             :         // .apk (zip) archive as the /assets/rc file.
     265             :         fileName = rtl::OUString("vnd.sun.star.pathname:/assets/rc");
     266             :         resolvePathnameUrl(&fileName);
     267             : #else
     268        1080 :         if(getFromCommandLineArgs(
     269        1080 :                OUString("INIFILENAME"), &fileName))
     270             :         {
     271          53 :             resolvePathnameUrl(&fileName);
     272             :         }
     273             :         else
     274             :         {
     275         487 :             getExecutableFile_Impl (&(fileName.pData));
     276             : 
     277             :             // get rid of a potential executable extension
     278         487 :             OUString progExt = ".bin";
     279        1461 :             if(fileName.getLength() > progExt.getLength()
     280        1948 :             && fileName.copy(fileName.getLength() - progExt.getLength()).equalsIgnoreAsciiCase(progExt))
     281          95 :                 fileName = fileName.copy(0, fileName.getLength() - progExt.getLength());
     282             : 
     283         487 :             progExt = ".exe";
     284        1461 :             if(fileName.getLength() > progExt.getLength()
     285        1948 :             && fileName.copy(fileName.getLength() - progExt.getLength()).equalsIgnoreAsciiCase(progExt))
     286           0 :                 fileName = fileName.copy(0, fileName.getLength() - progExt.getLength());
     287             : 
     288             :             // append config file suffix
     289         487 :             fileName += OUString(SAL_CONFIGFILE(""));
     290             :         }
     291             : #endif
     292             : 
     293         540 :         static OUString theFileName;
     294         540 :         if(fileName.getLength())
     295         538 :             theFileName = fileName;
     296             : 
     297         540 :         pStaticName = &theFileName;
     298             :     }
     299             : 
     300        5614 :     return *pStaticName;
     301             : }
     302             : 
     303             : //----------------------------------------------------------------------------
     304             : 
     305             : static inline bool path_exists( OUString const & path )
     306             : {
     307             :     DirectoryItem dirItem;
     308             :     return (DirectoryItem::E_None == DirectoryItem::get( path, dirItem ));
     309             : }
     310             : 
     311             : //----------------------------------------------------------------------------
     312             : // #111772#
     313             : // ensure the given file url has no final slash
     314             : 
     315           0 : inline void EnsureNoFinalSlash (rtl::OUString & url)
     316             : {
     317           0 :     sal_Int32 i = url.getLength();
     318           0 :     if (i > 0 && url[i - 1] == '/') {
     319           0 :         url = url.copy(0, i - 1);
     320             :     }
     321           0 : }
     322             : 
     323             : struct Bootstrap_Impl
     324             : {
     325             :     sal_Int32 _nRefCount;
     326             :     Bootstrap_Impl * _base_ini;
     327             : 
     328             :     NameValueList _nameValueList;
     329             :     OUString      _iniName;
     330             : 
     331             :     explicit Bootstrap_Impl (OUString const & rIniName);
     332             :     ~Bootstrap_Impl();
     333             : 
     334        5000 :     static void * operator new (std::size_t n) SAL_THROW(())
     335        5000 :         { return rtl_allocateMemory (sal_uInt32(n)); }
     336        3347 :     static void operator delete (void * p , std::size_t) SAL_THROW(())
     337        3347 :         { rtl_freeMemory (p); }
     338             : 
     339             :     bool getValue(
     340             :         rtl::OUString const & key, rtl_uString ** value,
     341             :         rtl_uString * defaultValue, LookupMode mode, bool override,
     342             :         ExpandRequestLink const * requestStack) const;
     343             :     bool getDirectValue(
     344             :         rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
     345             :         ExpandRequestLink const * requestStack) const;
     346             :     bool getAmbienceValue(
     347             :         rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
     348             :         ExpandRequestLink const * requestStack) const;
     349             :     void expandValue(
     350             :         rtl_uString ** value, rtl::OUString const & text, LookupMode mode,
     351             :         Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey,
     352             :         ExpandRequestLink const * requestStack) const;
     353             : };
     354             : 
     355             : //----------------------------------------------------------------------------
     356             : 
     357        5000 : Bootstrap_Impl::Bootstrap_Impl( OUString const & rIniName )
     358             :     : _nRefCount( 0 ),
     359             :       _base_ini( 0 ),
     360        5000 :       _iniName (rIniName)
     361             : {
     362        5000 :     OUString base_ini( getIniFileName_Impl() );
     363             :     // normalize path
     364       10000 :     FileStatus status( osl_FileStatus_Mask_FileURL );
     365       10000 :     DirectoryItem dirItem;
     366        9166 :     if (DirectoryItem::E_None == DirectoryItem::get( base_ini, dirItem ) &&
     367        4166 :         DirectoryItem::E_None == dirItem.getFileStatus( status ))
     368             :     {
     369        4166 :         base_ini = status.getFileURL();
     370        4166 :         if (! rIniName.equals( base_ini ))
     371             :         {
     372             :             _base_ini = static_cast< Bootstrap_Impl * >(
     373        4032 :                 rtl_bootstrap_args_open( base_ini.pData ) );
     374             :         }
     375             :     }
     376             : 
     377             : #if OSL_DEBUG_LEVEL > 1
     378             :     OString sFile = OUStringToOString(_iniName, RTL_TEXTENCODING_ASCII_US);
     379             :     OSL_TRACE("Bootstrap_Impl(): sFile=%s", sFile.getStr());
     380             : #endif /* OSL_DEBUG_LEVEL > 1 */
     381             : 
     382             :     oslFileHandle handle;
     383        9998 :     if (!_iniName.isEmpty() &&
     384        4998 :         osl_File_E_None == osl_openFile(_iniName.pData, &handle, osl_File_OpenFlag_Read))
     385             :     {
     386        4652 :         rtl::ByteSequence seq;
     387             : 
     388       54308 :         while (osl_File_E_None == osl_readLine(handle , (sal_Sequence **)&seq))
     389             :         {
     390       45004 :             OString line( (const sal_Char *) seq.getConstArray(), seq.getLength() );
     391       45004 :             sal_Int32 nIndex = line.indexOf('=');
     392       45004 :             if (nIndex >= 1)
     393             :             {
     394       26914 :                 struct rtl_bootstrap_NameValue nameValue;
     395       53828 :                 nameValue.sName = OStringToOUString(
     396       26914 :                     line.copy(0,nIndex).trim(), RTL_TEXTENCODING_ASCII_US );
     397       53828 :                 nameValue.sValue = OStringToOUString(
     398       26914 :                     line.copy(nIndex+1).trim(), RTL_TEXTENCODING_UTF8 );
     399             : 
     400             : #if OSL_DEBUG_LEVEL > 1
     401             :                 OString name_tmp = OUStringToOString(nameValue.sName, RTL_TEXTENCODING_ASCII_US);
     402             :                 OString value_tmp = OUStringToOString(nameValue.sValue, RTL_TEXTENCODING_UTF8);
     403             :                 OSL_TRACE(
     404             :                     "pushing: name=%s value=%s",
     405             :                     name_tmp.getStr(), value_tmp.getStr() );
     406             : #endif /* OSL_DEBUG_LEVEL > 1 */
     407             : 
     408       26914 :                 _nameValueList.push_back(nameValue);
     409             :             }
     410       45004 :         }
     411        4652 :         osl_closeFile(handle);
     412        5000 :     }
     413             : #if OSL_DEBUG_LEVEL > 1
     414             :     else
     415             :     {
     416             :         OString file_tmp = OUStringToOString(_iniName, RTL_TEXTENCODING_ASCII_US);
     417             :         OSL_TRACE( "couldn't open file: %s", file_tmp.getStr() );
     418             :     }
     419             : #endif /* OSL_DEBUG_LEVEL > 1 */
     420        5000 : }
     421             : 
     422             : //----------------------------------------------------------------------------
     423             : 
     424        6694 : Bootstrap_Impl::~Bootstrap_Impl()
     425             : {
     426        3347 :     if (_base_ini != 0)
     427        3330 :         rtl_bootstrap_args_close( _base_ini );
     428        3347 : }
     429             : 
     430             : //----------------------------------------------------------------------------
     431             : 
     432             : namespace {
     433             : 
     434        8288 : Bootstrap_Impl * get_static_bootstrap_handle() SAL_THROW(())
     435             : {
     436        8288 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     437             :     static Bootstrap_Impl * s_handle = 0;
     438        8288 :     if (s_handle == 0)
     439             :     {
     440         482 :         OUString iniName (getIniFileName_Impl());
     441             :         s_handle = static_cast< Bootstrap_Impl * >(
     442         482 :             rtl_bootstrap_args_open( iniName.pData ) );
     443         482 :         if (s_handle == 0)
     444             :         {
     445         348 :             Bootstrap_Impl * that = new Bootstrap_Impl( iniName );
     446         348 :             ++that->_nRefCount;
     447         348 :             s_handle = that;
     448         482 :         }
     449             :     }
     450        8288 :     return s_handle;
     451             : }
     452             : 
     453             : struct FundamentalIniData {
     454             :     rtlBootstrapHandle ini;
     455             : 
     456         478 :     FundamentalIniData() {
     457         478 :         OUString uri;
     458             :         ini =
     459             :             ((static_cast< Bootstrap_Impl * >(get_static_bootstrap_handle())->
     460             :               getValue(
     461             :                   rtl::OUString("URE_BOOTSTRAP"),
     462        2060 :                   &uri.pData, 0, LOOKUP_MODE_NORMAL, false, 0)) &&
     463         148 :              resolvePathnameUrl(&uri))
     464        2060 :             ? rtl_bootstrap_args_open(uri.pData) : NULL;
     465         478 :     }
     466             : 
     467         478 :     ~FundamentalIniData() { rtl_bootstrap_args_close(ini); }
     468             : 
     469             : private:
     470             :     FundamentalIniData(FundamentalIniData &); // not defined
     471             :     void operator =(FundamentalIniData &); // not defined
     472             : };
     473             : 
     474             : struct FundamentalIni: public rtl::Static< FundamentalIniData, FundamentalIni >
     475             : {};
     476             : 
     477             : }
     478             : 
     479      133607 : bool Bootstrap_Impl::getValue(
     480             :     rtl::OUString const & key, rtl_uString ** value, rtl_uString * defaultValue,
     481             :     LookupMode mode, bool override, ExpandRequestLink const * requestStack)
     482             :     const
     483             : {
     484      267080 :     if (mode == LOOKUP_MODE_NORMAL &&
     485      133473 :         key.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("URE_BOOTSTRAP")))
     486             :     {
     487         572 :         mode = LOOKUP_MODE_URE_BOOTSTRAP;
     488             :     }
     489      133607 :     if (override && getDirectValue(key, value, mode, requestStack)) {
     490         104 :         return true;
     491             :     }
     492      133503 :     if (key == "_OS") {
     493             :         rtl_uString_assign(
     494         410 :             value, rtl::OUString(RTL_OS).pData);
     495         410 :         return true;
     496             :     }
     497      133093 :     if (key == "_ARCH") {
     498             :         rtl_uString_assign(
     499         408 :             value, rtl::OUString(RTL_ARCH).pData);
     500         408 :         return true;
     501             :     }
     502      132685 :     if (key == "_CPPU_ENV") {
     503             :         rtl_uString_assign(
     504             :             value,
     505             :             (rtl::OUString(
     506             :                 SAL_STRINGIFY(CPPU_ENV)).
     507           0 :              pData));
     508           0 :         return true;
     509             :     }
     510             : #ifdef ANDROID
     511             :     if (key == "APP_DATA_DIR") {
     512             :         const char *app_data_dir = lo_get_app_data_dir();
     513             :         rtl_uString_assign(
     514             :             value, rtl::OUString(app_data_dir, strlen(app_data_dir), RTL_TEXTENCODING_UTF8).pData);
     515             :         return true;
     516             :     }
     517             : #endif
     518             : #ifdef IOS
     519             :     if (key == "APP_DATA_DIR") {
     520             :         const char *app_data_dir = [[[[NSBundle mainBundle] bundlePath] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding] UTF8String];
     521             :         rtl_uString_assign(
     522             :             value, rtl::OUString(app_data_dir, strlen(app_data_dir), RTL_TEXTENCODING_UTF8).pData);
     523             :         return true;
     524             :     }
     525             : #endif
     526      132685 :     if (key == "ORIGIN") {
     527             :         rtl_uString_assign(
     528             :             value,
     529             :             _iniName.copy(
     530       41845 :                 0, std::max<sal_Int32>(0, _iniName.lastIndexOf('/'))).pData);
     531       41845 :         return true;
     532             :     }
     533       90840 :     if (getAmbienceValue(key, value, mode, requestStack)) {
     534       22680 :         return true;
     535             :     }
     536       68160 :     if (key == "SYSUSERCONFIG") {
     537           0 :         rtl::OUString v;
     538           0 :         bool b = osl::Security().getConfigDir(v);
     539           0 :         EnsureNoFinalSlash(v);
     540           0 :         rtl_uString_assign(value, v.pData);
     541           0 :         return b;
     542             :     }
     543       68160 :     if (key == "SYSUSERHOME") {
     544           0 :         rtl::OUString v;
     545           0 :         bool b = osl::Security().getHomeDir(v);
     546           0 :         EnsureNoFinalSlash(v);
     547           0 :         rtl_uString_assign(value, v.pData);
     548           0 :         return b;
     549             :     }
     550       68160 :     if (key == "SYSBINDIR") {
     551           0 :         getExecutableDirectory_Impl(value);
     552           0 :         return true;
     553             :     }
     554      128118 :     if (_base_ini != NULL &&
     555       59958 :         _base_ini->getDirectValue(key, value, mode, requestStack))
     556             :     {
     557           0 :         return true;
     558             :     }
     559       68160 :     if (!override && getDirectValue(key, value, mode, requestStack)) {
     560       24857 :         return true;
     561             :     }
     562       43303 :     if (mode == LOOKUP_MODE_NORMAL) {
     563       42962 :         FundamentalIniData const & d = FundamentalIni::get();
     564       42962 :         Bootstrap_Impl const * b = static_cast<Bootstrap_Impl const *>(d.ini);
     565       84192 :         if (b != NULL && b != this &&
     566       41230 :             b->getDirectValue(key, value, mode, requestStack))
     567             :         {
     568       38931 :             return true;
     569             :         }
     570             :     }
     571        4372 :     if (defaultValue != NULL) {
     572         689 :         rtl_uString_assign(value, defaultValue);
     573         689 :         return true;
     574             :     }
     575        3683 :     rtl_uString_new(value);
     576        3683 :     return false;
     577             : }
     578             : 
     579      169452 : bool Bootstrap_Impl::getDirectValue(
     580             :     rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
     581             :     ExpandRequestLink const * requestStack) const
     582             : {
     583      169452 :     rtl::OUString v;
     584      169452 :     if (find(_nameValueList, key, &v)) {
     585       63892 :         expandValue(value, v, mode, this, key, requestStack);
     586       63892 :         return true;
     587             :     } else {
     588      105560 :         return false;
     589      169452 :     }
     590             : }
     591             : 
     592       90840 : bool Bootstrap_Impl::getAmbienceValue(
     593             :     rtl::OUString const & key, rtl_uString ** value, LookupMode mode,
     594             :     ExpandRequestLink const * requestStack) const
     595             : {
     596       90840 :     rtl::OUString v;
     597             :     bool f;
     598             :     {
     599       90840 :         osl::MutexGuard g(osl::Mutex::getGlobalMutex());
     600       90840 :         f = find(rtl_bootstrap_set_list::get(), key, &v);
     601             :     }
     602      159116 :     if (f || getFromCommandLineArgs(key, &v) ||
     603       68276 :         osl_getEnvironment(key.pData, &v.pData) == osl_Process_E_None)
     604             :     {
     605       22680 :         expandValue(value, v, mode, NULL, key, requestStack);
     606       22680 :         return true;
     607             :     } else {
     608       68160 :         return false;
     609       90840 :     }
     610             : }
     611             : 
     612       86572 : void Bootstrap_Impl::expandValue(
     613             :     rtl_uString ** value, rtl::OUString const & text, LookupMode mode,
     614             :     Bootstrap_Impl const * requestFile, rtl::OUString const & requestKey,
     615             :     ExpandRequestLink const * requestStack) const
     616             : {
     617             :     rtl_uString_assign(
     618             :         value,
     619         231 :         (mode == LOOKUP_MODE_URE_BOOTSTRAP && isPathnameUrl(text) ?
     620             :          text :
     621             :          recursivelyExpandMacros(
     622             :              this, text,
     623             :              (mode == LOOKUP_MODE_URE_BOOTSTRAP ?
     624             :               LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION : mode),
     625       86573 :              requestFile, requestKey, requestStack)).pData);
     626       86572 : }
     627             : 
     628             : namespace {
     629             : 
     630             : struct bootstrap_map {
     631             :     typedef boost::unordered_map<
     632             :         rtl::OUString, Bootstrap_Impl *,
     633             :         rtl::OUStringHash, std::equal_to< rtl::OUString >,
     634             :         rtl::Allocator< OUString > > t;
     635             : 
     636             :     // get and release must only be called properly synchronized via some mutex
     637             :     // (e.g., osl::Mutex::getGlobalMutex()):
     638             : 
     639       54486 :     static t * get() {
     640       54486 :         if (m_map == NULL) {
     641        1127 :             m_map = new t;
     642             :         }
     643       54486 :         return m_map;
     644             :     }
     645             : 
     646       25524 :     static void release() {
     647       25524 :         if (m_map != NULL && m_map->empty()) {
     648         589 :             delete m_map;
     649         589 :             m_map = NULL;
     650             :         }
     651       25524 :     }
     652             : 
     653             : private:
     654             :     bootstrap_map(); // not defined
     655             : 
     656             :     static t * m_map;
     657             : };
     658             : 
     659             : bootstrap_map::t * bootstrap_map::m_map = NULL;
     660             : 
     661             : }
     662             : 
     663             : //----------------------------------------------------------------------------
     664             : 
     665       27649 : rtlBootstrapHandle SAL_CALL rtl_bootstrap_args_open (
     666             :     rtl_uString * pIniName
     667             : ) SAL_THROW_EXTERN_C()
     668             : {
     669       27649 :     OUString iniName( pIniName );
     670             : 
     671             :     // normalize path
     672       55298 :     FileStatus status( osl_FileStatus_Mask_FileURL );
     673       55298 :     DirectoryItem dirItem;
     674       53280 :     if (DirectoryItem::E_None != DirectoryItem::get( iniName, dirItem ) ||
     675       25631 :         DirectoryItem::E_None != dirItem.getFileStatus( status ))
     676             :     {
     677        2018 :         return 0;
     678             :     }
     679       25631 :     iniName = status.getFileURL();
     680             : 
     681             :     Bootstrap_Impl * that;
     682       51262 :     osl::ResettableMutexGuard guard( osl::Mutex::getGlobalMutex() );
     683       25631 :     bootstrap_map::t* p_bootstrap_map = bootstrap_map::get();
     684       25631 :     bootstrap_map::t::const_iterator iFind( p_bootstrap_map->find( iniName ) );
     685       25631 :     if (iFind == p_bootstrap_map->end())
     686             :     {
     687        4652 :         bootstrap_map::release();
     688        4652 :         guard.clear();
     689        4652 :         that = new Bootstrap_Impl( iniName );
     690        4652 :         guard.reset();
     691        4652 :         p_bootstrap_map = bootstrap_map::get();
     692        4652 :         iFind = p_bootstrap_map->find( iniName );
     693        4652 :         if (iFind == p_bootstrap_map->end())
     694             :         {
     695        4652 :             ++that->_nRefCount;
     696             :             ::std::pair< bootstrap_map::t::iterator, bool > insertion(
     697             :                 p_bootstrap_map->insert(
     698        4652 :                     bootstrap_map::t::value_type( iniName, that ) ) );
     699             :             (void) insertion; // WaE: unused variable
     700             :             OSL_ASSERT( insertion.second );
     701             :         }
     702             :         else
     703             :         {
     704           0 :             Bootstrap_Impl * obsolete = that;
     705           0 :             that = iFind->second;
     706           0 :             ++that->_nRefCount;
     707           0 :             guard.clear();
     708           0 :             delete obsolete;
     709             :         }
     710             :     }
     711             :     else
     712             :     {
     713       20979 :         that = iFind->second;
     714       20979 :         ++that->_nRefCount;
     715             :     }
     716       53280 :     return static_cast< rtlBootstrapHandle >( that );
     717             : }
     718             : 
     719             : //----------------------------------------------------------------------------
     720             : 
     721       26663 : void SAL_CALL rtl_bootstrap_args_close (
     722             :     rtlBootstrapHandle handle
     723             : ) SAL_THROW_EXTERN_C()
     724             : {
     725       26663 :     if (handle == 0)
     726       29123 :         return;
     727       24203 :     Bootstrap_Impl * that = static_cast< Bootstrap_Impl * >( handle );
     728             : 
     729       24203 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     730       24203 :     bootstrap_map::t* p_bootstrap_map = bootstrap_map::get();
     731             :     OSL_ASSERT(
     732             :         p_bootstrap_map->find( that->_iniName )->second == that );
     733       24203 :     --that->_nRefCount;
     734       24203 :     if (that->_nRefCount == 0)
     735             :     {
     736       20872 :         ::std::size_t nLeaking = 8; // only hold up to 8 files statically
     737             : 
     738             : #if OSL_DEBUG_LEVEL == 1 // nonpro
     739             :         nLeaking = 0;
     740             : #elif OSL_DEBUG_LEVEL > 1 // debug
     741             :         nLeaking = 1;
     742             : #endif /* OSL_DEBUG_LEVEL */
     743             : 
     744       20872 :         if (p_bootstrap_map->size() > nLeaking)
     745             :         {
     746        3347 :             ::std::size_t erased = p_bootstrap_map->erase( that->_iniName );
     747             :             if (erased != 1) {
     748             :                 OSL_ASSERT( false );
     749             :             }
     750        3347 :             delete that;
     751             :         }
     752       20872 :         bootstrap_map::release();
     753       24203 :     }
     754             : }
     755             : 
     756             : //----------------------------------------------------------------------------
     757             : 
     758        6238 : sal_Bool SAL_CALL rtl_bootstrap_get_from_handle(
     759             :     rtlBootstrapHandle handle,
     760             :     rtl_uString      * pName,
     761             :     rtl_uString     ** ppValue,
     762             :     rtl_uString      * pDefault
     763             : ) SAL_THROW_EXTERN_C()
     764             : {
     765        6238 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     766             : 
     767        6238 :     sal_Bool found = sal_False;
     768        6238 :     if(ppValue && pName)
     769             :     {
     770        6238 :         if (handle == 0)
     771        2714 :             handle = get_static_bootstrap_handle();
     772             :         found = static_cast< Bootstrap_Impl * >( handle )->getValue(
     773        6238 :             pName, ppValue, pDefault, LOOKUP_MODE_NORMAL, false, NULL );
     774             :     }
     775             : 
     776        6238 :     return found;
     777             : }
     778             : 
     779             : //----------------------------------------------------------------------------
     780             : 
     781         299 : void SAL_CALL rtl_bootstrap_get_iniName_from_handle (
     782             :     rtlBootstrapHandle handle,
     783             :     rtl_uString     ** ppIniName
     784             : ) SAL_THROW_EXTERN_C()
     785             : {
     786         299 :     if(ppIniName)
     787             :     {
     788         299 :         if(handle)
     789             :         {
     790         167 :             Bootstrap_Impl * pImpl = static_cast<Bootstrap_Impl*>(handle);
     791         167 :             rtl_uString_assign(ppIniName, pImpl->_iniName.pData);
     792             :         }
     793             :         else
     794             :         {
     795         132 :             const OUString & iniName = getIniFileName_Impl();
     796         132 :             rtl_uString_assign(ppIniName, iniName.pData);
     797             :         }
     798             :     }
     799         299 : }
     800             : 
     801             : //----------------------------------------------------------------------------
     802             : 
     803           0 : void SAL_CALL rtl_bootstrap_setIniFileName (
     804             :     rtl_uString * pName
     805             : ) SAL_THROW_EXTERN_C()
     806             : {
     807           0 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     808           0 :     OUString & file = getIniFileName_Impl();
     809           0 :     file = pName;
     810           0 : }
     811             : 
     812             : //----------------------------------------------------------------------------
     813             : 
     814        1775 : sal_Bool SAL_CALL rtl_bootstrap_get (
     815             :     rtl_uString  * pName,
     816             :     rtl_uString ** ppValue,
     817             :     rtl_uString  * pDefault
     818             : ) SAL_THROW_EXTERN_C()
     819             : {
     820        1775 :     return rtl_bootstrap_get_from_handle(0, pName, ppValue, pDefault);
     821             : }
     822             : 
     823             : //----------------------------------------------------------------------------
     824             : 
     825         384 : void SAL_CALL rtl_bootstrap_set (
     826             :     rtl_uString * pName,
     827             :     rtl_uString * pValue
     828             : ) SAL_THROW_EXTERN_C()
     829             : {
     830         384 :     const OUString name( pName );
     831         448 :     const OUString value( pValue );
     832             : 
     833         448 :     osl::MutexGuard guard( osl::Mutex::getGlobalMutex() );
     834             : 
     835         384 :     NameValueList& r_rtl_bootstrap_set_list = rtl_bootstrap_set_list::get();
     836         384 :     NameValueList::iterator iPos( r_rtl_bootstrap_set_list.begin() );
     837         384 :     NameValueList::iterator iEnd( r_rtl_bootstrap_set_list.end() );
     838         390 :     for ( ; iPos != iEnd; ++iPos )
     839             :     {
     840         326 :         if (iPos->sName.equals( name ))
     841             :         {
     842         320 :             iPos->sValue = value;
     843         704 :             return;
     844             :         }
     845             :     }
     846             : 
     847             : #if OSL_DEBUG_LEVEL > 1
     848             :     OString cstr_name( OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ) );
     849             :     OString cstr_value( OUStringToOString( value, RTL_TEXTENCODING_ASCII_US ) );
     850             :     OSL_TRACE(
     851             :         "bootstrap.cxx: explicitly setting: name=%s value=%s\n",
     852             :         cstr_name.getStr(), cstr_value.getStr() );
     853             : #endif /* OSL_DEBUG_LEVEL > 1 */
     854             : 
     855         128 :     r_rtl_bootstrap_set_list.push_back( rtl_bootstrap_NameValue( name, value ) );
     856             : }
     857             : 
     858             : //----------------------------------------------------------------------------
     859             : 
     860       42923 : void SAL_CALL rtl_bootstrap_expandMacros_from_handle (
     861             :     rtlBootstrapHandle handle,
     862             :     rtl_uString     ** macro
     863             : ) SAL_THROW_EXTERN_C()
     864             : {
     865       42923 :     if (handle == NULL) {
     866        4583 :         handle = get_static_bootstrap_handle();
     867             :     }
     868             :     OUString expanded( expandMacros( static_cast< Bootstrap_Impl * >( handle ),
     869             :                                      * reinterpret_cast< OUString const * >( macro ),
     870       42923 :                                      LOOKUP_MODE_NORMAL, NULL ) );
     871       42923 :     rtl_uString_assign( macro, expanded.pData );
     872       42923 : }
     873             : 
     874             : //----------------------------------------------------------------------------
     875             : 
     876        4583 : void SAL_CALL rtl_bootstrap_expandMacros(
     877             :     rtl_uString ** macro )
     878             :     SAL_THROW_EXTERN_C()
     879             : {
     880        4583 :     rtl_bootstrap_expandMacros_from_handle(NULL, macro);
     881        4583 : }
     882             : 
     883          94 : void rtl_bootstrap_encode( rtl_uString const * value, rtl_uString ** encoded )
     884             :     SAL_THROW_EXTERN_C()
     885             : {
     886             :     OSL_ASSERT(value != NULL);
     887          94 :     rtl::OUStringBuffer b;
     888        8368 :     for (sal_Int32 i = 0; i < value->length; ++i) {
     889        8274 :         sal_Unicode c = value->buffer[i];
     890        8274 :         if (c == '$' || c == '\\') {
     891           0 :             b.append(sal_Unicode('\\'));
     892             :         }
     893        8274 :         b.append(c);
     894             :     }
     895          94 :     rtl_uString_assign(encoded, b.makeStringAndClear().pData);
     896          94 : }
     897             : 
     898             : namespace {
     899             : 
     900           0 : int hex(sal_Unicode c) {
     901             :     return
     902           0 :         c >= '0' && c <= '9' ? c - '0' :
     903           0 :         c >= 'A' && c <= 'F' ? c - 'A' + 10 :
     904           0 :         c >= 'a' && c <= 'f' ? c - 'a' + 10 : -1;
     905             : }
     906             : 
     907     7560352 : sal_Unicode read(rtl::OUString const & text, sal_Int32 * pos, bool * escaped) {
     908             :     OSL_ASSERT(
     909             :         pos != NULL && *pos >= 0 && *pos < text.getLength() && escaped != NULL);
     910     7560352 :     sal_Unicode c = text[(*pos)++];
     911     7560352 :     if (c == '\\') {
     912             :         int n1, n2, n3, n4;
     913         630 :         if (*pos < text.getLength() - 4 && text[*pos] == 'u' &&
     914           0 :             ((n1 = hex(text[*pos + 1])) >= 0) &&
     915           0 :             ((n2 = hex(text[*pos + 2])) >= 0) &&
     916         210 :             ((n3 = hex(text[*pos + 3])) >= 0) &&
     917           0 :             ((n4 = hex(text[*pos + 4])) >= 0))
     918             :         {
     919           0 :             *pos += 5;
     920           0 :             *escaped = true;
     921             :             return static_cast< sal_Unicode >(
     922           0 :                 (n1 << 12) | (n2 << 8) | (n3 << 4) | n4);
     923         210 :         } else if (*pos < text.getLength()) {
     924         210 :             *escaped = true;
     925         210 :             return text[(*pos)++];
     926             :         }
     927             :     }
     928     7560142 :     *escaped = false;
     929     7560142 :     return c;
     930             : }
     931             : 
     932      126891 : rtl::OUString lookup(
     933             :     Bootstrap_Impl const * file, LookupMode mode, bool override,
     934             :     rtl::OUString const & key, ExpandRequestLink const * requestStack)
     935             : {
     936      126891 :     rtl::OUString v;
     937             :     (file == NULL ? get_static_bootstrap_handle() : file)->getValue(
     938      126891 :         key, &v.pData, NULL, mode, override, requestStack);
     939      126891 :     return v;
     940             : }
     941             : 
     942      209239 : rtl::OUString expandMacros(
     943             :     Bootstrap_Impl const * file, rtl::OUString const & text, LookupMode mode,
     944             :     ExpandRequestLink const * requestStack)
     945             : {
     946      209239 :     rtl::OUStringBuffer buf;
     947     5772109 :     for (sal_Int32 i = 0; i < text.getLength();) {
     948             :         bool escaped;
     949     5353631 :         sal_Unicode c = read(text, &i, &escaped);
     950     5353631 :         if (escaped || c != '$') {
     951     5226706 :             buf.append(c);
     952             :         } else {
     953      126925 :             if (i < text.getLength() && text[i] == '{') {
     954       59259 :                 ++i;
     955       59259 :                 sal_Int32 p = i;
     956       59259 :                 sal_Int32 nesting = 0;
     957      237036 :                 rtl::OUString seg[3];
     958       59259 :                 int n = 0;
     959     1285617 :                 while (i < text.getLength()) {
     960     1226358 :                     sal_Int32 j = i;
     961     1226358 :                     c = read(text, &i, &escaped);
     962     1226358 :                     if (!escaped) {
     963     1226254 :                         switch (c) {
     964             :                         case '{':
     965         773 :                             ++nesting;
     966         773 :                             break;
     967             :                         case '}':
     968       60032 :                             if (nesting == 0) {
     969       59259 :                                 seg[n++] = text.copy(p, j - p);
     970       59259 :                                 goto done;
     971             :                             } else {
     972         773 :                                 --nesting;
     973             :                             }
     974         773 :                             break;
     975             :                         case ':':
     976       21002 :                             if (nesting == 0 && n < 2) {
     977       20486 :                                 seg[n++] = text.copy(p, j - p);
     978       20486 :                                 p = i;
     979             :                             }
     980       21002 :                             break;
     981             :                         }
     982             :                     }
     983             :                 }
     984             :             done:
     985      139004 :                 for (int j = 0; j < n; ++j) {
     986       79745 :                     seg[j] = expandMacros(file, seg[j], mode, requestStack);
     987             :                 }
     988       59259 :                 if (n == 1) {
     989       39749 :                     buf.append(lookup(file, mode, false, seg[0], requestStack));
     990       19510 :                 } else if (n == 2 && seg[0] == ".link") {
     991           0 :                     osl::File f(seg[1]);
     992           0 :                     rtl::ByteSequence seq;
     993           0 :                     rtl::OUString line;
     994           0 :                     rtl::OUString url;
     995             :                     // Silently ignore any errors (is that good?):
     996           0 :                     if ((f.open(osl_File_OpenFlag_Read) ==
     997           0 :                          osl::FileBase::E_None) &&
     998           0 :                         f.readLine(seq) == osl::FileBase::E_None &&
     999             :                         rtl_convertStringToUString(
    1000             :                             &line.pData,
    1001             :                             reinterpret_cast< char const * >(
    1002           0 :                                 seq.getConstArray()),
    1003             :                             seq.getLength(), RTL_TEXTENCODING_UTF8,
    1004             :                             (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
    1005             :                              RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
    1006           0 :                              RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)) &&
    1007           0 :                         (osl::File::getFileURLFromSystemPath(line, url) ==
    1008             :                          osl::FileBase::E_None))
    1009             :                     {
    1010             :                         try {
    1011             :                             buf.append(
    1012           0 :                                 rtl::Uri::convertRelToAbs(seg[1], url));
    1013           0 :                         } catch (const rtl::MalformedUriException &) {}
    1014           0 :                     }
    1015       19510 :                 } else if (n == 3 && seg[0] == ".override") {
    1016         104 :                     rtl::Bootstrap b(seg[1]);
    1017             :                     Bootstrap_Impl * f = static_cast< Bootstrap_Impl * >(
    1018         104 :                         b.getHandle());
    1019             :                     buf.append(
    1020         104 :                         lookup(f, mode, f != NULL, seg[2], requestStack));
    1021             :                 } else {
    1022       19406 :                     if (n == 3 && seg[1].isEmpty()) {
    1023             :                         // For backward compatibility, treat ${file::key} the
    1024             :                         // same as just ${file:key}:
    1025         838 :                         seg[1] = seg[2];
    1026         838 :                         n = 2;
    1027             :                     }
    1028       19406 :                     if (n == 2) {
    1029             :                         buf.append(
    1030             :                             lookup(
    1031             :                                 static_cast< Bootstrap_Impl * >(
    1032       38744 :                                     rtl::Bootstrap(seg[0]).getHandle()),
    1033       19372 :                                 mode, false, seg[1], requestStack));
    1034             :                     } else {
    1035             :                         // Going through osl::Profile, this code erroneously
    1036             :                         // does not recursively expand macros in the resulting
    1037             :                         // replacement text (and if it did, it would fail to
    1038             :                         // detect cycles that pass through here):
    1039             :                         buf.append(
    1040             :                             rtl::OStringToOUString(
    1041             :                                 osl::Profile(seg[0]).readString(
    1042             :                                     rtl::OUStringToOString(
    1043             :                                         seg[1], RTL_TEXTENCODING_UTF8),
    1044             :                                     rtl::OUStringToOString(
    1045             :                                         seg[2], RTL_TEXTENCODING_UTF8),
    1046             :                                     rtl::OString()),
    1047          34 :                                 RTL_TEXTENCODING_UTF8));
    1048             :                     }
    1049      237036 :                 }
    1050             :             } else {
    1051       67666 :                 rtl::OUStringBuffer kbuf;
    1052       67666 :                 for (; i < text.getLength();) {
    1053      980363 :                     sal_Int32 j = i;
    1054      980363 :                     c = read(text, &j, &escaped);
    1055      980363 :                     if (!escaped &&
    1056      980363 :                         (c == ' ' || c == '$' || c == '-' || c == '/' ||
    1057      915336 :                          c == ';' || c == '\\'))
    1058             :                     {
    1059             :                         break;
    1060             :                     }
    1061      915336 :                     kbuf.append(c);
    1062      915336 :                     i = j;
    1063             :                 }
    1064             :                 buf.append(
    1065             :                     lookup(
    1066             :                         file, mode, false, kbuf.makeStringAndClear(),
    1067       67666 :                         requestStack));
    1068             :             }
    1069             :         }
    1070             :     }
    1071      209239 :     return buf.makeStringAndClear();
    1072             : }
    1073             : 
    1074             : }
    1075             : 
    1076             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10