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

Generated by: LCOV version 1.10