1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bootstrap.cxx,v $
10 * $Revision: 1.43.20.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sal.hxx"
34 #include "rtl/bootstrap.h"
35 #include "rtl/bootstrap.hxx"
36 #include <osl/diagnose.h>
37 #include <osl/module.h>
38 #include <osl/process.h>
39 #include <osl/file.hxx>
40 #include <osl/mutex.hxx>
41 #include <osl/profile.hxx>
42 #include <osl/security.hxx>
43 #include <rtl/alloc.h>
44 #include <rtl/string.hxx>
45 #include <rtl/ustrbuf.hxx>
46 #include <rtl/ustring.hxx>
47 #include <rtl/byteseq.hxx>
48 #include <rtl/instance.hxx>
49 #include <rtl/malformeduriexception.hxx>
50 #include <rtl/uri.hxx>
51 #include "rtl/allocator.hxx"
58 #define MY_STRING_(x) # x
59 #define MY_STRING(x) MY_STRING_(x)
61 //----------------------------------------------------------------------------
63 using osl::DirectoryItem
;
64 using osl::FileStatus
;
68 using rtl::OUStringToOString
;
70 struct Bootstrap_Impl
;
74 static char const VND_SUN_STAR_PATHNAME
[] = "vnd.sun.star.pathname:";
76 bool isPathnameUrl(rtl::OUString
const & url
) {
77 return url
.matchIgnoreAsciiCaseAsciiL(
78 RTL_CONSTASCII_STRINGPARAM(VND_SUN_STAR_PATHNAME
));
81 bool resolvePathnameUrl(rtl::OUString
* url
) {
82 OSL_ASSERT(url
!= NULL
);
83 if (!isPathnameUrl(*url
) ||
84 (osl::FileBase::getFileURLFromSystemPath(
85 url
->copy(RTL_CONSTASCII_LENGTH(VND_SUN_STAR_PATHNAME
)), *url
) ==
86 osl::FileBase::E_None
))
90 *url
= rtl::OUString();
96 LOOKUP_MODE_NORMAL
, LOOKUP_MODE_URE_BOOTSTRAP
,
97 LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION
};
99 struct ExpandRequestLink
{
100 ExpandRequestLink
const * next
;
101 Bootstrap_Impl
const * file
;
105 rtl::OUString
expandMacros(
106 Bootstrap_Impl
const * file
, rtl::OUString
const & text
, LookupMode mode
,
107 ExpandRequestLink
const * requestStack
);
109 rtl::OUString
recursivelyExpandMacros(
110 Bootstrap_Impl
const * file
, rtl::OUString
const & text
, LookupMode mode
,
111 Bootstrap_Impl
const * requestFile
, rtl::OUString
const & requestKey
,
112 ExpandRequestLink
const * requestStack
)
114 for (; requestStack
!= NULL
; requestStack
= requestStack
->next
) {
115 if (requestStack
->file
== requestFile
&&
116 requestStack
->key
== requestKey
)
118 return rtl::OUString(
119 RTL_CONSTASCII_USTRINGPARAM("***RECURSION DETECTED***"));
122 ExpandRequestLink link
= { requestStack
, requestFile
, requestKey
};
123 return expandMacros(file
, text
, mode
, &link
);
128 //----------------------------------------------------------------------------
130 struct rtl_bootstrap_NameValue
135 inline rtl_bootstrap_NameValue() SAL_THROW( () )
137 inline rtl_bootstrap_NameValue(
138 OUString
const & name
, OUString
const & value
) SAL_THROW( () )
145 rtl_bootstrap_NameValue
,
146 rtl::Allocator
< rtl_bootstrap_NameValue
>
150 NameValueList
const & list
, rtl::OUString
const & key
,
151 rtl::OUString
* value
)
153 OSL_ASSERT(value
!= NULL
);
154 for (NameValueList::const_iterator
i(list
.begin()); i
!= list
.end(); ++i
) {
155 if (i
->sName
== key
) {
164 struct rtl_bootstrap_set_list
:
165 public rtl::Static
< NameValueList
, rtl_bootstrap_set_list
> {};
168 //----------------------------------------------------------------------------
170 static sal_Bool
getFromCommandLineArgs(
171 rtl::OUString
const & key
, rtl::OUString
* value
)
173 OSL_ASSERT(value
!= NULL
);
174 static NameValueList
*pNameValueList
= 0;
175 if( ! pNameValueList
)
177 static NameValueList nameValueList
;
179 sal_Int32 nArgCount
= osl_getCommandArgCount();
180 for(sal_Int32 i
= 0; i
< nArgCount
; ++ i
)
182 rtl_uString
*pArg
= 0;
183 osl_getCommandArg( i
, &pArg
);
184 if( ('-' == pArg
->buffer
[0] || '/' == pArg
->buffer
[0] ) &&
185 'e' == pArg
->buffer
[1] &&
186 'n' == pArg
->buffer
[2] &&
187 'v' == pArg
->buffer
[3] &&
188 ':' == pArg
->buffer
[4] )
190 sal_Int32 nIndex
= rtl_ustr_indexOfChar( pArg
->buffer
, '=' );
194 rtl_bootstrap_NameValue nameValue
;
195 nameValue
.sName
= OUString( &(pArg
->buffer
[5]), nIndex
- 5 );
196 nameValue
.sValue
= OUString( &(pArg
->buffer
[nIndex
+1]) );
197 if( i
== nArgCount
-1 &&
198 nameValue
.sValue
.getLength() &&
199 nameValue
.sValue
[nameValue
.sValue
.getLength()-1] == 13 )
201 // avoid the 13 linefeed for the last argument,
202 // when the executable is started from a script,
203 // that was edited on windows
204 nameValue
.sValue
= nameValue
.sValue
.copy(0,nameValue
.sValue
.getLength()-1);
206 nameValueList
.push_back( nameValue
);
209 rtl_uString_release( pArg
);
211 pNameValueList
= &nameValueList
;
214 sal_Bool found
= sal_False
;
216 for( NameValueList::iterator ii
= pNameValueList
->begin() ;
217 ii
!= pNameValueList
->end() ;
220 if( (*ii
).sName
.equals(key
) )
222 *value
= (*ii
).sValue
;
231 //----------------------------------------------------------------------------
233 extern "C" oslProcessError SAL_CALL
osl_bootstrap_getExecutableFile_Impl (
234 rtl_uString
** ppFileURL
) SAL_THROW_EXTERN_C();
236 inline void getExecutableFile_Impl (rtl_uString
** ppFileURL
)
238 osl_bootstrap_getExecutableFile_Impl (ppFileURL
);
241 //----------------------------------------------------------------------------
243 static void getExecutableDirectory_Impl (rtl_uString
** ppDirURL
)
246 getExecutableFile_Impl (&(fileName
.pData
));
248 sal_Int32 nDirEnd
= fileName
.lastIndexOf('/');
249 OSL_ENSURE(nDirEnd
>= 0, "Cannot locate executable directory");
251 rtl_uString_newFromStr_WithLength(ppDirURL
,fileName
.getStr(),nDirEnd
);
254 //----------------------------------------------------------------------------
256 static OUString
& getIniFileName_Impl()
258 static OUString
*pStaticName
= 0;
263 if(getFromCommandLineArgs(
264 OUString(RTL_CONSTASCII_USTRINGPARAM("INIFILENAME")), &fileName
))
266 resolvePathnameUrl(&fileName
);
270 getExecutableFile_Impl (&(fileName
.pData
));
272 // get rid of a potential executable extension
273 OUString
progExt (RTL_CONSTASCII_USTRINGPARAM(".bin"));
274 if(fileName
.getLength() > progExt
.getLength()
275 && fileName
.copy(fileName
.getLength() - progExt
.getLength()).equalsIgnoreAsciiCase(progExt
))
276 fileName
= fileName
.copy(0, fileName
.getLength() - progExt
.getLength());
278 progExt
= OUString::createFromAscii(".exe");
279 if(fileName
.getLength() > progExt
.getLength()
280 && fileName
.copy(fileName
.getLength() - progExt
.getLength()).equalsIgnoreAsciiCase(progExt
))
281 fileName
= fileName
.copy(0, fileName
.getLength() - progExt
.getLength());
283 // append config file suffix
284 fileName
+= OUString(RTL_CONSTASCII_USTRINGPARAM(SAL_CONFIGFILE("")));
288 osl_getProcessWorkingDir(&workDir
.pData
);
289 osl::FileBase::getAbsoluteFileURL(workDir
, fileName
, fileName
);
291 static OUString theFileName
;
292 if(fileName
.getLength())
293 theFileName
= fileName
;
295 pStaticName
= &theFileName
;
301 //----------------------------------------------------------------------------
303 static inline bool path_exists( OUString
const & path
)
305 DirectoryItem dirItem
;
306 return (DirectoryItem::E_None
== DirectoryItem::get( path
, dirItem
));
309 //----------------------------------------------------------------------------
311 // ensure the given file url has no final slash
313 inline void EnsureNoFinalSlash (rtl::OUString
& url
)
315 sal_Int32 i
= url
.getLength();
316 if (i
> 0 && url
[i
- 1] == '/') {
317 url
= url
.copy(0, i
- 1);
321 //----------------------------------------------------------------------------
322 //----------------------------------------------------------------------------
324 struct Bootstrap_Impl
326 sal_Int32 _nRefCount
;
327 Bootstrap_Impl
* _base_ini
;
329 NameValueList _nameValueList
;
332 explicit Bootstrap_Impl (OUString
const & rIniName
);
335 static void * operator new (std::size_t n
) SAL_THROW(())
336 { return rtl_allocateMemory (sal_uInt32(n
)); }
337 static void operator delete (void * p
, std::size_t) SAL_THROW(())
338 { rtl_freeMemory (p
); }
341 rtl::OUString
const & key
, rtl_uString
** value
,
342 rtl_uString
* defaultValue
, LookupMode mode
, bool override
,
343 ExpandRequestLink
const * requestStack
) const;
345 rtl::OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
346 ExpandRequestLink
const * requestStack
) const;
347 bool getAmbienceValue(
348 rtl::OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
349 ExpandRequestLink
const * requestStack
) const;
351 rtl_uString
** value
, rtl::OUString
const & text
, LookupMode mode
,
352 Bootstrap_Impl
const * requestFile
, rtl::OUString
const & requestKey
,
353 ExpandRequestLink
const * requestStack
) const;
356 //----------------------------------------------------------------------------
358 Bootstrap_Impl::Bootstrap_Impl( OUString
const & rIniName
)
363 OUString
base_ini( getIniFileName_Impl() );
365 FileStatus
status( FileStatusMask_FileURL
);
366 DirectoryItem dirItem
;
367 if (DirectoryItem::E_None
== DirectoryItem::get( base_ini
, dirItem
) &&
368 DirectoryItem::E_None
== dirItem
.getFileStatus( status
))
370 base_ini
= status
.getFileURL();
371 if (! rIniName
.equals( base_ini
))
373 _base_ini
= static_cast< Bootstrap_Impl
* >(
374 rtl_bootstrap_args_open( base_ini
.pData
) );
378 #if OSL_DEBUG_LEVEL > 1
379 OString sFile
= OUStringToOString(_iniName
, RTL_TEXTENCODING_ASCII_US
);
380 OSL_TRACE(__FILE__
" -- Bootstrap_Impl() - %s\n", sFile
.getStr());
381 #endif /* OSL_DEBUG_LEVEL > 1 */
383 oslFileHandle handle
;
384 if (_iniName
.getLength() &&
385 osl_File_E_None
== osl_openFile(_iniName
.pData
, &handle
, osl_File_OpenFlag_Read
))
387 rtl::ByteSequence seq
;
389 while (osl_File_E_None
== osl_readLine(handle
, (sal_Sequence
**)&seq
))
391 OString
line( (const sal_Char
*) seq
.getConstArray(), seq
.getLength() );
392 sal_Int32 nIndex
= line
.indexOf('=');
395 struct rtl_bootstrap_NameValue nameValue
;
396 nameValue
.sName
= OStringToOUString(
397 line
.copy(0,nIndex
).trim(), RTL_TEXTENCODING_ASCII_US
);
398 nameValue
.sValue
= OStringToOUString(
399 line
.copy(nIndex
+1).trim(), RTL_TEXTENCODING_UTF8
);
401 #if OSL_DEBUG_LEVEL > 1
402 OString name_tmp
= OUStringToOString(nameValue
.sName
, RTL_TEXTENCODING_ASCII_US
);
403 OString value_tmp
= OUStringToOString(nameValue
.sValue
, RTL_TEXTENCODING_UTF8
);
405 __FILE__
" -- pushing: name=%s value=%s\n",
406 name_tmp
.getStr(), value_tmp
.getStr() );
407 #endif /* OSL_DEBUG_LEVEL > 1 */
409 _nameValueList
.push_back(nameValue
);
412 osl_closeFile(handle
);
414 #if OSL_DEBUG_LEVEL > 1
417 OString file_tmp
= OUStringToOString(_iniName
, RTL_TEXTENCODING_ASCII_US
);
418 OSL_TRACE( __FILE__
" -- couldn't open file: %s", file_tmp
.getStr() );
420 #endif /* OSL_DEBUG_LEVEL > 1 */
423 //----------------------------------------------------------------------------
425 Bootstrap_Impl::~Bootstrap_Impl()
428 rtl_bootstrap_args_close( _base_ini
);
431 //----------------------------------------------------------------------------
435 Bootstrap_Impl
* get_static_bootstrap_handle() SAL_THROW(())
437 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
438 static Bootstrap_Impl
* s_handle
= 0;
441 OUString
iniName (getIniFileName_Impl());
442 s_handle
= static_cast< Bootstrap_Impl
* >(
443 rtl_bootstrap_args_open( iniName
.pData
) );
446 Bootstrap_Impl
* that
= new Bootstrap_Impl( iniName
);
454 struct FundamentalIniData
{
455 rtlBootstrapHandle ini
;
457 FundamentalIniData() {
460 ((static_cast< Bootstrap_Impl
* >(get_static_bootstrap_handle())->
463 RTL_CONSTASCII_USTRINGPARAM("URE_BOOTSTRAP")),
464 &uri
.pData
, 0, LOOKUP_MODE_NORMAL
, false, 0)) &&
465 resolvePathnameUrl(&uri
))
466 ? rtl_bootstrap_args_open(uri
.pData
) : NULL
;
469 ~FundamentalIniData() { rtl_bootstrap_args_close(ini
); }
472 FundamentalIniData(FundamentalIniData
&); // not defined
473 void operator =(FundamentalIniData
&); // not defined
476 struct FundamentalIni
: public rtl::Static
< FundamentalIniData
, FundamentalIni
>
481 bool Bootstrap_Impl::getValue(
482 rtl::OUString
const & key
, rtl_uString
** value
, rtl_uString
* defaultValue
,
483 LookupMode mode
, bool override
, ExpandRequestLink
const * requestStack
)
486 if (mode
== LOOKUP_MODE_NORMAL
&&
487 key
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("URE_BOOTSTRAP")))
489 mode
= LOOKUP_MODE_URE_BOOTSTRAP
;
491 if (override
&& getDirectValue(key
, value
, mode
, requestStack
)) {
494 if (key
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_OS"))) {
496 value
, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(THIS_OS
)).pData
);
499 if (key
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_ARCH"))) {
501 value
, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(THIS_ARCH
)).pData
);
504 if (key
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("_CPPU_ENV"))) {
507 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(MY_STRING(CPPU_ENV
))).
511 if (key
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("ORIGIN"))) {
515 0, std::max
<sal_Int32
>(0, _iniName
.lastIndexOf('/'))).pData
);
518 if (getAmbienceValue(key
, value
, mode
, requestStack
)) {
521 if (key
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSUSERCONFIG"))) {
523 bool b
= osl::Security().getConfigDir(v
);
524 EnsureNoFinalSlash(v
);
525 rtl_uString_assign(value
, v
.pData
);
528 if (key
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSUSERHOME"))) {
530 bool b
= osl::Security().getHomeDir(v
);
531 EnsureNoFinalSlash(v
);
532 rtl_uString_assign(value
, v
.pData
);
535 if (key
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SYSBINDIR"))) {
536 getExecutableDirectory_Impl(value
);
539 if (_base_ini
!= NULL
&&
540 _base_ini
->getDirectValue(key
, value
, mode
, requestStack
))
544 if (!override
&& getDirectValue(key
, value
, mode
, requestStack
)) {
547 if (mode
== LOOKUP_MODE_NORMAL
) {
548 FundamentalIniData
const & d
= FundamentalIni::get();
549 Bootstrap_Impl
const * b
= static_cast<Bootstrap_Impl
const *>(d
.ini
);
550 if (b
!= NULL
&& b
!= this &&
551 b
->getDirectValue(key
, value
, mode
, requestStack
))
556 if (defaultValue
!= NULL
) {
557 rtl_uString_assign(value
, defaultValue
);
560 rtl_uString_new(value
);
564 bool Bootstrap_Impl::getDirectValue(
565 rtl::OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
566 ExpandRequestLink
const * requestStack
) const
569 if (find(_nameValueList
, key
, &v
)) {
570 expandValue(value
, v
, mode
, this, key
, requestStack
);
577 bool Bootstrap_Impl::getAmbienceValue(
578 rtl::OUString
const & key
, rtl_uString
** value
, LookupMode mode
,
579 ExpandRequestLink
const * requestStack
) const
584 osl::MutexGuard
g(osl::Mutex::getGlobalMutex());
585 f
= find(rtl_bootstrap_set_list::get(), key
, &v
);
587 if (f
|| getFromCommandLineArgs(key
, &v
) ||
588 osl_getEnvironment(key
.pData
, &v
.pData
) == osl_Process_E_None
)
590 expandValue(value
, v
, mode
, NULL
, key
, requestStack
);
597 void Bootstrap_Impl::expandValue(
598 rtl_uString
** value
, rtl::OUString
const & text
, LookupMode mode
,
599 Bootstrap_Impl
const * requestFile
, rtl::OUString
const & requestKey
,
600 ExpandRequestLink
const * requestStack
) const
604 (mode
== LOOKUP_MODE_URE_BOOTSTRAP
&& isPathnameUrl(text
) ?
606 recursivelyExpandMacros(
608 (mode
== LOOKUP_MODE_URE_BOOTSTRAP
?
609 LOOKUP_MODE_URE_BOOTSTRAP_EXPANSION
: mode
),
610 requestFile
, requestKey
, requestStack
)).pData
);
613 //----------------------------------------------------------------------------
614 //----------------------------------------------------------------------------
618 struct bootstrap_map
{
619 // map<> may be preferred here, but hash_map<> is implemented fully inline,
620 // thus there is no need to link against the stlport:
621 typedef std::hash_map
<
622 rtl::OUString
, Bootstrap_Impl
*,
623 rtl::OUStringHash
, std::equal_to
< rtl::OUString
>,
624 rtl::Allocator
< OUString
> > t
;
626 // get and release must only be called properly synchronized via some mutex
627 // (e.g., osl::Mutex::getGlobalMutex()):
636 static void release() {
637 if (m_map
!= NULL
&& m_map
->empty()) {
644 bootstrap_map(); // not defined
649 bootstrap_map::t
* bootstrap_map::m_map
= NULL
;
653 //----------------------------------------------------------------------------
655 rtlBootstrapHandle SAL_CALL
rtl_bootstrap_args_open (
656 rtl_uString
* pIniName
657 ) SAL_THROW_EXTERN_C()
660 OUString
iniName( pIniName
);
662 osl_getProcessWorkingDir( &workDir
.pData
);
663 osl::FileBase::getAbsoluteFileURL( workDir
, iniName
, iniName
);
666 FileStatus
status( FileStatusMask_FileURL
);
667 DirectoryItem dirItem
;
668 if (DirectoryItem::E_None
!= DirectoryItem::get( iniName
, dirItem
) ||
669 DirectoryItem::E_None
!= dirItem
.getFileStatus( status
))
673 iniName
= status
.getFileURL();
675 Bootstrap_Impl
* that
;
676 osl::ResettableMutexGuard
guard( osl::Mutex::getGlobalMutex() );
677 bootstrap_map::t
* p_bootstrap_map
= bootstrap_map::get();
678 bootstrap_map::t::const_iterator
iFind( p_bootstrap_map
->find( iniName
) );
679 if (iFind
== p_bootstrap_map
->end())
681 bootstrap_map::release();
683 that
= new Bootstrap_Impl( iniName
);
685 p_bootstrap_map
= bootstrap_map::get();
686 iFind
= p_bootstrap_map
->find( iniName
);
687 if (iFind
== p_bootstrap_map
->end())
690 ::std::pair
< bootstrap_map::t::iterator
, bool > insertion(
691 p_bootstrap_map
->insert(
692 bootstrap_map::t::value_type( iniName
, that
) ) );
693 OSL_ASSERT( insertion
.second
);
697 Bootstrap_Impl
* obsolete
= that
;
698 that
= iFind
->second
;
706 that
= iFind
->second
;
709 return static_cast< rtlBootstrapHandle
>( that
);
712 //----------------------------------------------------------------------------
714 void SAL_CALL
rtl_bootstrap_args_close (
715 rtlBootstrapHandle handle
716 ) SAL_THROW_EXTERN_C()
720 Bootstrap_Impl
* that
= static_cast< Bootstrap_Impl
* >( handle
);
722 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
723 bootstrap_map::t
* p_bootstrap_map
= bootstrap_map::get();
725 p_bootstrap_map
->find( that
->_iniName
)->second
== that
);
727 if (that
->_nRefCount
== 0)
729 ::std::size_t nLeaking
= 8; // only hold up to 8 files statically
731 #if OSL_DEBUG_LEVEL == 1 // nonpro
733 #elif OSL_DEBUG_LEVEL > 1 // debug
735 #endif /* OSL_DEBUG_LEVEL */
737 if (p_bootstrap_map
->size() > nLeaking
)
739 ::std::size_t erased
= p_bootstrap_map
->erase( that
->_iniName
);
745 bootstrap_map::release();
749 //----------------------------------------------------------------------------
751 sal_Bool SAL_CALL
rtl_bootstrap_get_from_handle(
752 rtlBootstrapHandle handle
,
754 rtl_uString
** ppValue
,
755 rtl_uString
* pDefault
756 ) SAL_THROW_EXTERN_C()
758 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
760 sal_Bool found
= sal_False
;
764 handle
= get_static_bootstrap_handle();
765 found
= static_cast< Bootstrap_Impl
* >( handle
)->getValue(
766 pName
, ppValue
, pDefault
, LOOKUP_MODE_NORMAL
, false, NULL
);
772 //----------------------------------------------------------------------------
774 void SAL_CALL
rtl_bootstrap_get_iniName_from_handle (
775 rtlBootstrapHandle handle
,
776 rtl_uString
** ppIniName
777 ) SAL_THROW_EXTERN_C()
783 Bootstrap_Impl
* pImpl
= static_cast<Bootstrap_Impl
*>(handle
);
784 rtl_uString_assign(ppIniName
, pImpl
->_iniName
.pData
);
788 const OUString
& iniName
= getIniFileName_Impl();
789 rtl_uString_assign(ppIniName
, iniName
.pData
);
794 //----------------------------------------------------------------------------
796 void SAL_CALL
rtl_bootstrap_setIniFileName (
798 ) SAL_THROW_EXTERN_C()
800 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
801 OUString
& file
= getIniFileName_Impl();
805 //----------------------------------------------------------------------------
807 sal_Bool SAL_CALL
rtl_bootstrap_get (
809 rtl_uString
** ppValue
,
810 rtl_uString
* pDefault
811 ) SAL_THROW_EXTERN_C()
813 return rtl_bootstrap_get_from_handle(0, pName
, ppValue
, pDefault
);
816 //----------------------------------------------------------------------------
818 void SAL_CALL
rtl_bootstrap_set (
821 ) SAL_THROW_EXTERN_C()
823 OUString
const & name
= *reinterpret_cast< OUString
const * >( &pName
);
824 OUString
const & value
= *reinterpret_cast< OUString
const * >( &pValue
);
826 osl::MutexGuard
guard( osl::Mutex::getGlobalMutex() );
828 NameValueList
& r_rtl_bootstrap_set_list
= rtl_bootstrap_set_list::get();
829 NameValueList::iterator
iPos( r_rtl_bootstrap_set_list
.begin() );
830 NameValueList::iterator
iEnd( r_rtl_bootstrap_set_list
.end() );
831 for ( ; iPos
!= iEnd
; ++iPos
)
833 if (iPos
->sName
.equals( name
))
835 iPos
->sValue
= value
;
840 #if OSL_DEBUG_LEVEL > 1
841 OString
cstr_name( OUStringToOString( name
, RTL_TEXTENCODING_ASCII_US
) );
842 OString
cstr_value( OUStringToOString( value
, RTL_TEXTENCODING_ASCII_US
) );
844 "bootstrap.cxx: explicitly setting: name=%s value=%s\n",
845 cstr_name
.getStr(), cstr_value
.getStr() );
846 #endif /* OSL_DEBUG_LEVEL > 1 */
848 r_rtl_bootstrap_set_list
.push_back( rtl_bootstrap_NameValue( name
, value
) );
851 //----------------------------------------------------------------------------
853 void SAL_CALL
rtl_bootstrap_expandMacros_from_handle (
854 rtlBootstrapHandle handle
,
856 ) SAL_THROW_EXTERN_C()
858 if (handle
== NULL
) {
859 handle
= get_static_bootstrap_handle();
861 OUString
expanded( expandMacros( static_cast< Bootstrap_Impl
* >( handle
),
862 * reinterpret_cast< OUString
const * >( macro
),
863 LOOKUP_MODE_NORMAL
, NULL
) );
864 rtl_uString_assign( macro
, expanded
.pData
);
867 //----------------------------------------------------------------------------
869 void SAL_CALL
rtl_bootstrap_expandMacros(
870 rtl_uString
** macro
)
873 rtl_bootstrap_expandMacros_from_handle(NULL
, macro
);
876 void rtl_bootstrap_encode( rtl_uString
const * value
, rtl_uString
** encoded
)
879 OSL_ASSERT(value
!= NULL
);
880 rtl::OUStringBuffer b
;
881 for (sal_Int32 i
= 0; i
< value
->length
; ++i
) {
882 sal_Unicode c
= value
->buffer
[i
];
883 if (c
== '$' || c
== '\\') {
884 b
.append(sal_Unicode('\\'));
888 rtl_uString_assign(encoded
, b
.makeStringAndClear().pData
);
893 int hex(sal_Unicode c
) {
895 c
>= '0' && c
<= '9' ? c
- '0' :
896 c
>= 'A' && c
<= 'F' ? c
- 'A' + 10 :
897 c
>= 'a' && c
<= 'f' ? c
- 'a' + 10 : -1;
900 sal_Unicode
read(rtl::OUString
const & text
, sal_Int32
* pos
, bool * escaped
) {
902 pos
!= NULL
&& *pos
>= 0 && *pos
< text
.getLength() && escaped
!= NULL
);
903 sal_Unicode c
= text
[(*pos
)++];
906 if (*pos
< text
.getLength() - 4 && text
[*pos
] == 'u' &&
907 ((n1
= hex(text
[*pos
+ 1])) >= 0) &&
908 ((n2
= hex(text
[*pos
+ 2])) >= 0) &&
909 ((n3
= hex(text
[*pos
+ 3])) >= 0) &&
910 ((n4
= hex(text
[*pos
+ 4])) >= 0))
914 return static_cast< sal_Unicode
>(
915 (n1
<< 12) | (n2
<< 8) | (n3
<< 4) | n4
);
916 } else if (*pos
< text
.getLength()) {
918 return text
[(*pos
)++];
925 rtl::OUString
lookup(
926 Bootstrap_Impl
const * file
, LookupMode mode
, bool override
,
927 rtl::OUString
const & key
, ExpandRequestLink
const * requestStack
)
930 (file
== NULL
? get_static_bootstrap_handle() : file
)->getValue(
931 key
, &v
.pData
, NULL
, mode
, override
, requestStack
);
935 rtl::OUString
expandMacros(
936 Bootstrap_Impl
const * file
, rtl::OUString
const & text
, LookupMode mode
,
937 ExpandRequestLink
const * requestStack
)
939 rtl::OUStringBuffer buf
;
940 for (sal_Int32 i
= 0; i
< text
.getLength();) {
942 sal_Unicode c
= read(text
, &i
, &escaped
);
943 if (escaped
|| c
!= '$') {
946 if (i
< text
.getLength() && text
[i
] == '{') {
949 sal_Int32 nesting
= 0;
950 rtl::OUString seg
[3];
952 while (i
< text
.getLength()) {
954 c
= read(text
, &i
, &escaped
);
962 seg
[n
++] = text
.copy(p
, j
- p
);
969 if (nesting
== 0 && n
< 2) {
970 seg
[n
++] = text
.copy(p
, j
- p
);
978 for (int j
= 0; j
< n
; ++j
) {
979 seg
[j
] = expandMacros(file
, seg
[j
], mode
, requestStack
);
981 if (n
== 3 && seg
[1].getLength() == 0) {
982 // For backward compatibility, treat ${file::key} the same
983 // as just ${file:key}:
988 buf
.append(lookup(file
, mode
, false, seg
[0], requestStack
));
990 if (seg
[0].equalsAsciiL(
991 RTL_CONSTASCII_STRINGPARAM(".link")))
994 rtl::ByteSequence seq
;
997 // Silently ignore any errors (is that good?):
998 if (f
.open(OpenFlag_Read
) == osl::FileBase::E_None
&&
999 f
.readLine(seq
) == osl::FileBase::E_None
&&
1000 rtl_convertStringToUString(
1002 reinterpret_cast< char const * >(
1003 seq
.getConstArray()),
1004 seq
.getLength(), RTL_TEXTENCODING_UTF8
,
1005 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
1006 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
1007 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)) &&
1008 (osl::File::getFileURLFromSystemPath(line
, url
) ==
1009 osl::FileBase::E_None
))
1013 rtl::Uri::convertRelToAbs(seg
[1], url
));
1014 } catch (rtl::MalformedUriException
&) {}
1019 static_cast< Bootstrap_Impl
* >(
1020 rtl::Bootstrap(seg
[0]).getHandle()),
1021 mode
, false, seg
[1], requestStack
));
1023 } else if (seg
[0].equalsAsciiL(
1024 RTL_CONSTASCII_STRINGPARAM(".override")))
1026 rtl::Bootstrap
b(seg
[1]);
1027 Bootstrap_Impl
* f
= static_cast< Bootstrap_Impl
* >(
1030 lookup(f
, mode
, f
!= NULL
, seg
[2], requestStack
));
1032 // Going through osl::Profile, this code erroneously does
1033 // not recursively expand macros in the resulting
1034 // replacement text (and if it did, it would fail to detect
1035 // cycles that pass through here):
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
),
1044 RTL_TEXTENCODING_UTF8
));
1047 rtl::OUStringBuffer kbuf
;
1048 for (; i
< text
.getLength();) {
1050 c
= read(text
, &j
, &escaped
);
1052 (c
== ' ' || c
== '$' || c
== '-' || c
== '/' ||
1053 c
== ';' || c
== '\\'))
1062 file
, mode
, false, kbuf
.makeStringAndClear(),
1067 return buf
.makeStringAndClear();