bump product version to 4.1.6.2
[LibreOffice.git] / cppu / source / uno / EnvStack.cxx
blob22d7bd99290949b1863195c5ee4cc8e3f9e0ebd7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "uno/environment.hxx"
22 #include "cppu/EnvDcp.hxx"
23 #include "cppu/Enterable.hxx"
25 #include "rtl/instance.hxx"
27 #include "osl/thread.h"
28 #include "osl/mutex.hxx"
30 #include <boost/unordered_map.hpp>
33 using namespace com::sun::star;
36 struct SAL_DLLPRIVATE oslThreadIdentifier_equal
38 bool operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const;
41 bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const
43 bool result = s1 == s2;
45 return result;
49 struct SAL_DLLPRIVATE oslThreadIdentifier_hash
51 size_t operator()(oslThreadIdentifier s1) const;
54 size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const
56 return s1;
59 typedef ::boost::unordered_map<oslThreadIdentifier,
60 uno_Environment *,
61 oslThreadIdentifier_hash,
62 oslThreadIdentifier_equal> ThreadMap;
64 namespace
66 struct s_threadMap_mutex : public rtl::Static< osl::Mutex, s_threadMap_mutex > {};
67 struct s_threadMap : public rtl::Static< ThreadMap, s_threadMap > {};
70 static void s_setCurrent(uno_Environment * pEnv)
72 oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL);
74 osl::MutexGuard guard(s_threadMap_mutex::get());
75 ThreadMap &rThreadMap = s_threadMap::get();
76 if (pEnv)
78 rThreadMap[threadId] = pEnv;
80 else
82 ThreadMap::iterator iEnv = rThreadMap.find(threadId);
83 if( iEnv != rThreadMap.end())
84 rThreadMap.erase(iEnv);
88 static uno_Environment * s_getCurrent(void)
90 uno_Environment * pEnv = NULL;
92 oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL);
94 osl::MutexGuard guard(s_threadMap_mutex::get());
95 ThreadMap &rThreadMap = s_threadMap::get();
96 ThreadMap::iterator iEnv = rThreadMap.find(threadId);
97 if(iEnv != rThreadMap.end())
98 pEnv = iEnv->second;
100 return pEnv;
104 extern "C" CPPU_DLLPUBLIC void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName)
105 SAL_THROW_EXTERN_C()
107 if (*ppEnv)
109 (*ppEnv)->release(*ppEnv);
110 *ppEnv = NULL;
113 rtl::OUString currPurpose;
115 uno_Environment * pCurrEnv = s_getCurrent();
116 if (pCurrEnv) // no environment means no purpose
117 currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
119 if (pTypeName && rtl_uString_getLength(pTypeName))
121 rtl::OUString envDcp(pTypeName);
122 envDcp += currPurpose;
124 uno_getEnvironment(ppEnv, envDcp.pData, NULL);
126 else
128 if (pCurrEnv)
130 *ppEnv = pCurrEnv;
131 (*ppEnv)->acquire(*ppEnv);
133 else
135 rtl::OUString uno_envDcp(UNO_LB_UNO);
136 uno_getEnvironment(ppEnv, uno_envDcp.pData, NULL);
141 static rtl::OUString s_getPrefix(rtl::OUString const & str1, rtl::OUString const & str2)
143 sal_Int32 nIndex1 = 0;
144 sal_Int32 nIndex2 = 0;
145 sal_Int32 sim = 0;
147 rtl::OUString token1;
148 rtl::OUString token2;
152 token1 = str1.getToken(0, ':', nIndex1);
153 token2 = str2.getToken(0, ':', nIndex2);
155 if (token1.equals(token2))
156 sim += token1.getLength() + 1;
158 while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1.equals(token2));
160 rtl::OUString result;
162 if (sim)
163 result = str1.copy(0, sim - 1);
165 return result;
168 static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv)
170 int res = 0;
172 rtl::OUString nextPurpose;
174 rtl::OUString currPurpose;
175 if (pCurrEnv)
176 currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
178 rtl::OUString targetPurpose;
179 if (pTargetEnv)
180 targetPurpose = cppu::EnvDcp::getPurpose(pTargetEnv->pTypeName);
182 rtl::OUString intermPurpose(s_getPrefix(currPurpose, targetPurpose));
183 if (currPurpose.getLength() > intermPurpose.getLength())
185 sal_Int32 idx = currPurpose.lastIndexOf(':');
186 nextPurpose = currPurpose.copy(0, idx);
188 res = -1;
190 else if (intermPurpose.getLength() < targetPurpose.getLength())
192 sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1);
193 if (idx == -1)
194 nextPurpose = targetPurpose;
196 else
197 nextPurpose = targetPurpose.copy(0, idx);
199 res = 1;
202 if (!nextPurpose.isEmpty())
204 rtl::OUString next_envDcp(UNO_LB_UNO);
205 next_envDcp += nextPurpose;
207 uno_getEnvironment(ppEnv, next_envDcp.pData, NULL);
209 else
211 if (*ppEnv)
212 (*ppEnv)->release(*ppEnv);
214 *ppEnv = NULL;
217 return res;
220 extern "C" { static void s_pull(va_list * pParam)
222 uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *);
223 va_list * pXparam = va_arg(*pParam, va_list *);
225 pCallee(pXparam);
228 static void s_callInto_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
230 cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
231 if (pEnterable)
232 pEnterable->callInto(s_pull, pCallee, pParam);
234 else
235 pCallee(pParam);
238 static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
240 va_list param;
242 va_start(param, pCallee);
243 s_callInto_v(pEnv, pCallee, &param);
244 va_end(param);
247 static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
249 cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
250 if (pEnterable)
251 pEnterable->callOut_v(pCallee, pParam);
253 else
254 pCallee(pParam);
257 static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
259 va_list param;
261 va_start(param, pCallee);
262 s_callOut_v(pEnv, pCallee, &param);
263 va_end(param);
266 static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list *);
268 extern "C" { static void s_environment_invoke_vv(va_list * pParam)
270 uno_Environment * pCurrEnv = va_arg(*pParam, uno_Environment *);
271 uno_Environment * pTargetEnv = va_arg(*pParam, uno_Environment *);
272 uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *);
273 va_list * pXparam = va_arg(*pParam, va_list *);
275 s_environment_invoke_v(pCurrEnv, pTargetEnv, pCallee, pXparam);
278 static void s_environment_invoke_v(uno_Environment * pCurrEnv, uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
280 uno_Environment * pNextEnv = NULL;
281 switch(s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv))
283 case -1:
284 s_setCurrent(pNextEnv);
285 s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
286 s_setCurrent(pCurrEnv);
287 break;
289 case 0: {
290 uno_Environment * hld = s_getCurrent();
291 s_setCurrent(pCurrEnv);
292 pCallee(pParam);
293 s_setCurrent(hld);
295 break;
297 case 1:
298 s_setCurrent(pNextEnv);
299 s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
300 s_setCurrent(pCurrEnv);
301 break;
304 if (pNextEnv)
305 pNextEnv->release(pNextEnv);
308 extern "C" CPPU_DLLPUBLIC void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
309 SAL_THROW_EXTERN_C()
311 s_environment_invoke_v(s_getCurrent(), pTargetEnv, pCallee, pParam);
314 extern "C" CPPU_DLLPUBLIC void SAL_CALL uno_Environment_invoke(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
315 SAL_THROW_EXTERN_C()
317 va_list param;
319 va_start(param, pCallee);
320 uno_Environment_invoke_v(pEnv, pCallee, &param);
321 va_end(param);
324 extern "C" CPPU_DLLPUBLIC void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv)
325 SAL_THROW_EXTERN_C()
327 uno_Environment * pNextEnv = NULL;
328 uno_Environment * pCurrEnv = s_getCurrent();
330 int res;
331 while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0)
333 cppu::Enterable * pEnterable;
335 switch(res)
337 case -1:
338 pEnterable = reinterpret_cast<cppu::Enterable *>(pCurrEnv->pReserved);
339 if (pEnterable)
340 pEnterable->leave();
341 pCurrEnv->release(pCurrEnv);
342 break;
344 case 1:
345 pNextEnv->acquire(pNextEnv);
346 pEnterable = reinterpret_cast<cppu::Enterable *>(pNextEnv->pReserved);
347 if (pEnterable)
348 pEnterable->enter();
349 break;
352 s_setCurrent(pNextEnv);
353 pCurrEnv = pNextEnv;
357 CPPU_DLLPUBLIC int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason)
358 SAL_THROW_EXTERN_C()
360 int result = 1;
362 rtl::OUString typeName(cppu::EnvDcp::getTypeName(pEnv->pTypeName));
363 if (typeName == UNO_LB_UNO)
365 cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
366 if (pEnterable)
367 result = pEnterable->isValid((rtl::OUString *)pReason);
369 else
371 rtl::OUString envDcp(UNO_LB_UNO);
372 envDcp += cppu::EnvDcp::getPurpose(pEnv->pTypeName);
374 uno::Environment env(envDcp);
376 result = env.isValid((rtl::OUString *)pReason);
379 return result;
382 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */