update dev300-m58
[ooovba.git] / cppu / source / uno / EnvStack.cxx
blob7205aa93667543cb872cd7530b02d660dee8e21d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: EnvStack.cxx,v $
10 * $Revision: 1.5 $
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"
39 #include <hash_map>
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;
54 return result;
58 struct SAL_DLLPRIVATE oslThreadIdentifier_hash
60 size_t operator()(oslThreadIdentifier s1) const;
63 size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const
65 return s1;
68 typedef ::std::hash_map<oslThreadIdentifier,
69 uno_Environment *,
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);
84 if (pEnv)
85 s_threadMap[threadId] = pEnv;
87 else
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())
103 pEnv = iEnv->second;
105 return pEnv;
109 extern "C" void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName)
110 SAL_THROW_EXTERN_C()
112 if (*ppEnv)
114 (*ppEnv)->release(*ppEnv);
115 *ppEnv = NULL;
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);
131 else
133 if (pCurrEnv)
135 *ppEnv = pCurrEnv;
136 (*ppEnv)->acquire(*ppEnv);
138 else
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;
148 sal_Int32 sim = 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;
165 if (sim)
166 result = str1.copy(0, sim - 1);
168 return result;
171 static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv)
173 int res = 0;
175 rtl::OUString nextPurpose;
177 rtl::OUString currPurpose;
178 if (pCurrEnv)
179 currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
181 rtl::OUString targetPurpose;
182 if (pTargetEnv)
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);
191 res = -1;
193 else if (intermPurpose.getLength() < targetPurpose.getLength())
195 sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1);
196 if (idx == -1)
197 nextPurpose = targetPurpose;
199 else
200 nextPurpose = targetPurpose.copy(0, idx);
202 res = 1;
205 if (nextPurpose.getLength())
207 rtl::OUString next_envDcp(s_uno_envDcp);
208 next_envDcp += nextPurpose;
210 uno_getEnvironment(ppEnv, next_envDcp.pData, NULL);
212 else
214 if (*ppEnv)
215 (*ppEnv)->release(*ppEnv);
217 *ppEnv = NULL;
220 return res;
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 *);
228 pCallee(pXparam);
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);
234 if (pEnterable)
235 pEnterable->callInto(s_pull, pCallee, pParam);
237 else
238 pCallee(pParam);
241 static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
243 va_list param;
245 va_start(param, pCallee);
246 s_callInto_v(pEnv, pCallee, &param);
247 va_end(param);
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);
253 if (pEnterable)
254 pEnterable->callOut_v(pCallee, pParam);
256 else
257 pCallee(pParam);
260 static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
262 va_list param;
264 va_start(param, pCallee);
265 s_callOut_v(pEnv, pCallee, &param);
266 va_end(param);
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))
286 case -1:
287 s_setCurrent(pNextEnv);
288 s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
289 s_setCurrent(pCurrEnv);
290 break;
292 case 0: {
293 uno_Environment * hld = s_getCurrent();
294 s_setCurrent(pCurrEnv);
295 pCallee(pParam);
296 s_setCurrent(hld);
298 break;
300 case 1:
301 s_setCurrent(pNextEnv);
302 s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
303 s_setCurrent(pCurrEnv);
304 break;
307 if (pNextEnv)
308 pNextEnv->release(pNextEnv);
311 extern "C" void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
312 SAL_THROW_EXTERN_C()
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, ...)
318 SAL_THROW_EXTERN_C()
320 va_list param;
322 va_start(param, pCallee);
323 uno_Environment_invoke_v(pEnv, pCallee, &param);
324 va_end(param);
327 extern "C" void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv)
328 SAL_THROW_EXTERN_C()
330 uno_Environment * pNextEnv = NULL;
331 uno_Environment * pCurrEnv = s_getCurrent();
333 int res;
334 while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0)
336 cppu::Enterable * pEnterable;
338 switch(res)
340 case -1:
341 pEnterable = reinterpret_cast<cppu::Enterable *>(pCurrEnv->pReserved);
342 if (pEnterable)
343 pEnterable->leave();
344 pCurrEnv->release(pCurrEnv);
345 break;
347 case 1:
348 pNextEnv->acquire(pNextEnv);
349 pEnterable = reinterpret_cast<cppu::Enterable *>(pNextEnv->pReserved);
350 if (pEnterable)
351 pEnterable->enter();
352 break;
355 s_setCurrent(pNextEnv);
356 pCurrEnv = pNextEnv;
360 int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason)
361 SAL_THROW_EXTERN_C()
363 int result = 1;
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);
369 if (pEnterable)
370 result = pEnterable->isValid((rtl::OUString *)pReason);
372 else
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);
382 return result;