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: EnvStack.cxx,v $
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 #include "uno/environment.hxx"
33 #include "cppu/EnvDcp.hxx"
34 #include "cppu/Enterable.hxx"
36 #include "osl/thread.h"
37 #include "osl/mutex.hxx"
42 using namespace com::sun::star
;
45 struct SAL_DLLPRIVATE oslThreadIdentifier_equal
47 bool operator()(oslThreadIdentifier s1
, oslThreadIdentifier s2
) const;
50 bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1
, oslThreadIdentifier s2
) const
52 bool result
= s1
== s2
;
58 struct SAL_DLLPRIVATE oslThreadIdentifier_hash
60 size_t operator()(oslThreadIdentifier s1
) const;
63 size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1
) const
68 typedef ::std::hash_map
<oslThreadIdentifier
,
70 oslThreadIdentifier_hash
,
71 oslThreadIdentifier_equal
> ThreadMap
;
73 static osl::Mutex s_threadMap_mutex
;
74 static ThreadMap s_threadMap
;
77 static rtl::OUString
s_uno_envDcp(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO
));
79 static void s_setCurrent(uno_Environment
* pEnv
)
81 oslThreadIdentifier threadId
= osl_getThreadIdentifier(NULL
);
83 osl::MutexGuard
guard(s_threadMap_mutex
);
85 s_threadMap
[threadId
] = pEnv
;
89 ThreadMap::iterator iEnv
= s_threadMap
.find(threadId
);
90 s_threadMap
.erase(iEnv
);
94 static uno_Environment
* s_getCurrent(void)
96 uno_Environment
* pEnv
= NULL
;
98 oslThreadIdentifier threadId
= osl_getThreadIdentifier(NULL
);
100 osl::MutexGuard
guard(s_threadMap_mutex
);
101 ThreadMap::iterator iEnv
= s_threadMap
.find(threadId
);
102 if(iEnv
!= s_threadMap
.end())
109 extern "C" void SAL_CALL
uno_getCurrentEnvironment(uno_Environment
** ppEnv
, rtl_uString
* pTypeName
)
114 (*ppEnv
)->release(*ppEnv
);
118 rtl::OUString currPurpose
;
120 uno_Environment
* pCurrEnv
= s_getCurrent();
121 if (pCurrEnv
) // no environment means no purpose
122 currPurpose
= cppu::EnvDcp::getPurpose(pCurrEnv
->pTypeName
);
124 if (pTypeName
&& rtl_uString_getLength(pTypeName
))
126 rtl::OUString
envDcp(pTypeName
);
127 envDcp
+= currPurpose
;
129 uno_getEnvironment(ppEnv
, envDcp
.pData
, NULL
);
136 (*ppEnv
)->acquire(*ppEnv
);
139 uno_getEnvironment(ppEnv
, s_uno_envDcp
.pData
, NULL
);
144 static rtl::OUString
s_getPrefix(rtl::OUString
const & str1
, rtl::OUString
const & str2
)
146 sal_Int32 nIndex1
= 0;
147 sal_Int32 nIndex2
= 0;
150 rtl::OUString token1
;
151 rtl::OUString token2
;
155 token1
= str1
.getToken(0, ':', nIndex1
);
156 token2
= str2
.getToken(0, ':', nIndex2
);
158 if (token1
.equals(token2
))
159 sim
+= token1
.getLength() + 1;
161 while(nIndex1
== nIndex2
&& nIndex1
>= 0 && token1
.equals(token2
));
163 rtl::OUString result
;
166 result
= str1
.copy(0, sim
- 1);
171 static int s_getNextEnv(uno_Environment
** ppEnv
, uno_Environment
* pCurrEnv
, uno_Environment
* pTargetEnv
)
175 rtl::OUString nextPurpose
;
177 rtl::OUString currPurpose
;
179 currPurpose
= cppu::EnvDcp::getPurpose(pCurrEnv
->pTypeName
);
181 rtl::OUString targetPurpose
;
183 targetPurpose
= cppu::EnvDcp::getPurpose(pTargetEnv
->pTypeName
);
185 rtl::OUString
intermPurpose(s_getPrefix(currPurpose
, targetPurpose
));
186 if (currPurpose
.getLength() > intermPurpose
.getLength())
188 sal_Int32 idx
= currPurpose
.lastIndexOf(':');
189 nextPurpose
= currPurpose
.copy(0, idx
);
193 else if (intermPurpose
.getLength() < targetPurpose
.getLength())
195 sal_Int32 idx
= targetPurpose
.indexOf(':', intermPurpose
.getLength() + 1);
197 nextPurpose
= targetPurpose
;
200 nextPurpose
= targetPurpose
.copy(0, idx
);
205 if (nextPurpose
.getLength())
207 rtl::OUString
next_envDcp(s_uno_envDcp
);
208 next_envDcp
+= nextPurpose
;
210 uno_getEnvironment(ppEnv
, next_envDcp
.pData
, NULL
);
215 (*ppEnv
)->release(*ppEnv
);
223 extern "C" { static void s_pull(va_list * pParam
)
225 uno_EnvCallee
* pCallee
= va_arg(*pParam
, uno_EnvCallee
*);
226 va_list * pXparam
= va_arg(*pParam
, va_list *);
231 static void s_callInto_v(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
233 cppu::Enterable
* pEnterable
= reinterpret_cast<cppu::Enterable
*>(pEnv
->pReserved
);
235 pEnterable
->callInto(s_pull
, pCallee
, pParam
);
241 static void s_callInto(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...)
245 va_start(param
, pCallee
);
246 s_callInto_v(pEnv
, pCallee
, ¶m
);
250 static void s_callOut_v(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
252 cppu::Enterable
* pEnterable
= reinterpret_cast<cppu::Enterable
*>(pEnv
->pReserved
);
254 pEnterable
->callOut_v(pCallee
, pParam
);
260 static void s_callOut(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...)
264 va_start(param
, pCallee
);
265 s_callOut_v(pEnv
, pCallee
, ¶m
);
269 static void s_environment_invoke_v(uno_Environment
*, uno_Environment
*, uno_EnvCallee
*, va_list *);
271 extern "C" { static void s_environment_invoke_vv(va_list * pParam
)
273 uno_Environment
* pCurrEnv
= va_arg(*pParam
, uno_Environment
*);
274 uno_Environment
* pTargetEnv
= va_arg(*pParam
, uno_Environment
*);
275 uno_EnvCallee
* pCallee
= va_arg(*pParam
, uno_EnvCallee
*);
276 va_list * pXparam
= va_arg(*pParam
, va_list *);
278 s_environment_invoke_v(pCurrEnv
, pTargetEnv
, pCallee
, pXparam
);
281 static void s_environment_invoke_v(uno_Environment
* pCurrEnv
, uno_Environment
* pTargetEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
283 uno_Environment
* pNextEnv
= NULL
;
284 switch(s_getNextEnv(&pNextEnv
, pCurrEnv
, pTargetEnv
))
287 s_setCurrent(pNextEnv
);
288 s_callOut(pCurrEnv
, s_environment_invoke_vv
, pNextEnv
, pTargetEnv
, pCallee
, pParam
);
289 s_setCurrent(pCurrEnv
);
293 uno_Environment
* hld
= s_getCurrent();
294 s_setCurrent(pCurrEnv
);
301 s_setCurrent(pNextEnv
);
302 s_callInto(pNextEnv
, s_environment_invoke_vv
, pNextEnv
, pTargetEnv
, pCallee
, pParam
);
303 s_setCurrent(pCurrEnv
);
308 pNextEnv
->release(pNextEnv
);
311 extern "C" void SAL_CALL
uno_Environment_invoke_v(uno_Environment
* pTargetEnv
, uno_EnvCallee
* pCallee
, va_list * pParam
)
314 s_environment_invoke_v(s_getCurrent(), pTargetEnv
, pCallee
, pParam
);
317 extern "C" void SAL_CALL
uno_Environment_invoke(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...)
322 va_start(param
, pCallee
);
323 uno_Environment_invoke_v(pEnv
, pCallee
, ¶m
);
327 extern "C" void SAL_CALL
uno_Environment_enter(uno_Environment
* pTargetEnv
)
330 uno_Environment
* pNextEnv
= NULL
;
331 uno_Environment
* pCurrEnv
= s_getCurrent();
334 while ( (res
= s_getNextEnv(&pNextEnv
, pCurrEnv
, pTargetEnv
)) != 0)
336 cppu::Enterable
* pEnterable
;
341 pEnterable
= reinterpret_cast<cppu::Enterable
*>(pCurrEnv
->pReserved
);
344 pCurrEnv
->release(pCurrEnv
);
348 pNextEnv
->acquire(pNextEnv
);
349 pEnterable
= reinterpret_cast<cppu::Enterable
*>(pNextEnv
->pReserved
);
355 s_setCurrent(pNextEnv
);
360 int SAL_CALL
uno_Environment_isValid(uno_Environment
* pEnv
, rtl_uString
** pReason
)
365 rtl::OUString
typeName(cppu::EnvDcp::getTypeName(pEnv
->pTypeName
));
366 if (typeName
.equals(s_uno_envDcp
))
368 cppu::Enterable
* pEnterable
= reinterpret_cast<cppu::Enterable
*>(pEnv
->pReserved
);
370 result
= pEnterable
->isValid((rtl::OUString
*)pReason
);
374 rtl::OUString
envDcp(s_uno_envDcp
);
375 envDcp
+= cppu::EnvDcp::getPurpose(pEnv
->pTypeName
);
377 uno::Environment
env(envDcp
);
379 result
= env
.isValid((rtl::OUString
*)pReason
);