bump product version to 5.0.4.1
[LibreOffice.git] / cppu / source / uno / EnvStack.cxx
blob5fefaa85640a1a39e5b0d6d2e3af0ed0f45180ae
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"
21 #include <uno/lbnames.h>
23 #include "cppu/EnvDcp.hxx"
24 #include "cppu/Enterable.hxx"
26 #include "rtl/instance.hxx"
28 #include "osl/thread.h"
29 #include "osl/thread.hxx"
30 #include "osl/mutex.hxx"
32 #include <unordered_map>
34 using namespace com::sun::star;
37 struct oslThreadIdentifier_equal
39 bool operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const;
42 bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const
44 bool result = s1 == s2;
46 return result;
50 struct oslThreadIdentifier_hash
52 size_t operator()(oslThreadIdentifier s1) const;
55 size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const
57 return s1;
60 typedef std::unordered_map<oslThreadIdentifier,
61 uno_Environment *,
62 oslThreadIdentifier_hash,
63 oslThreadIdentifier_equal> ThreadMap;
65 namespace
67 struct s_threadMap_mutex : public rtl::Static< osl::Mutex, s_threadMap_mutex > {};
68 struct s_threadMap : public rtl::Static< ThreadMap, s_threadMap > {};
71 static void s_setCurrent(uno_Environment * pEnv)
73 oslThreadIdentifier threadId = osl::Thread::getCurrentIdentifier();
75 osl::MutexGuard guard(s_threadMap_mutex::get());
76 ThreadMap &rThreadMap = s_threadMap::get();
77 if (pEnv)
79 rThreadMap[threadId] = pEnv;
81 else
83 ThreadMap::iterator iEnv = rThreadMap.find(threadId);
84 if( iEnv != rThreadMap.end())
85 rThreadMap.erase(iEnv);
89 static uno_Environment * s_getCurrent()
91 uno_Environment * pEnv = NULL;
93 oslThreadIdentifier threadId = osl::Thread::getCurrentIdentifier();
95 osl::MutexGuard guard(s_threadMap_mutex::get());
96 ThreadMap &rThreadMap = s_threadMap::get();
97 ThreadMap::iterator iEnv = rThreadMap.find(threadId);
98 if(iEnv != rThreadMap.end())
99 pEnv = iEnv->second;
101 return pEnv;
105 extern "C" void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName)
106 SAL_THROW_EXTERN_C()
108 if (*ppEnv)
110 (*ppEnv)->release(*ppEnv);
111 *ppEnv = NULL;
114 rtl::OUString currPurpose;
116 uno_Environment * pCurrEnv = s_getCurrent();
117 if (pCurrEnv) // no environment means no purpose
118 currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
120 if (pTypeName && rtl_uString_getLength(pTypeName))
122 rtl::OUString envDcp(pTypeName);
123 envDcp += currPurpose;
125 uno_getEnvironment(ppEnv, envDcp.pData, NULL);
127 else
129 if (pCurrEnv)
131 *ppEnv = pCurrEnv;
132 (*ppEnv)->acquire(*ppEnv);
134 else
136 rtl::OUString uno_envDcp(UNO_LB_UNO);
137 uno_getEnvironment(ppEnv, uno_envDcp.pData, NULL);
142 static rtl::OUString s_getPrefix(rtl::OUString const & str1, rtl::OUString const & str2)
144 sal_Int32 nIndex1 = 0;
145 sal_Int32 nIndex2 = 0;
146 sal_Int32 sim = 0;
148 rtl::OUString token1;
149 rtl::OUString token2;
153 token1 = str1.getToken(0, ':', nIndex1);
154 token2 = str2.getToken(0, ':', nIndex2);
156 if (token1.equals(token2))
157 sim += token1.getLength() + 1;
159 while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1.equals(token2));
161 rtl::OUString result;
163 if (sim)
164 result = str1.copy(0, sim - 1);
166 return result;
169 static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv)
171 int res = 0;
173 rtl::OUString nextPurpose;
175 rtl::OUString currPurpose;
176 if (pCurrEnv)
177 currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);
179 rtl::OUString targetPurpose;
180 if (pTargetEnv)
181 targetPurpose = cppu::EnvDcp::getPurpose(pTargetEnv->pTypeName);
183 rtl::OUString intermPurpose(s_getPrefix(currPurpose, targetPurpose));
184 if (currPurpose.getLength() > intermPurpose.getLength())
186 sal_Int32 idx = currPurpose.lastIndexOf(':');
187 nextPurpose = currPurpose.copy(0, idx);
189 res = -1;
191 else if (intermPurpose.getLength() < targetPurpose.getLength())
193 sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1);
194 if (idx == -1)
195 nextPurpose = targetPurpose;
197 else
198 nextPurpose = targetPurpose.copy(0, idx);
200 res = 1;
203 if (!nextPurpose.isEmpty())
205 rtl::OUString next_envDcp(UNO_LB_UNO);
206 next_envDcp += nextPurpose;
208 uno_getEnvironment(ppEnv, next_envDcp.pData, NULL);
210 else
212 if (*ppEnv)
213 (*ppEnv)->release(*ppEnv);
215 *ppEnv = NULL;
218 return res;
221 extern "C" { static void s_pull(va_list * pParam)
223 uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *);
224 va_list * pXparam = va_arg(*pParam, va_list *);
226 pCallee(pXparam);
229 static void s_callInto_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
231 cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved);
232 if (pEnterable)
233 pEnterable->callInto(s_pull, pCallee, pParam);
235 else
236 pCallee(pParam);
239 static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
241 va_list param;
243 va_start(param, pCallee);
244 s_callInto_v(pEnv, pCallee, &param);
245 va_end(param);
248 static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam)
250 cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved);
251 if (pEnterable)
252 pEnterable->callOut_v(pCallee, pParam);
254 else
255 pCallee(pParam);
258 static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
260 va_list param;
262 va_start(param, pCallee);
263 s_callOut_v(pEnv, pCallee, &param);
264 va_end(param);
267 static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list *);
269 extern "C" { static void s_environment_invoke_vv(va_list * pParam)
271 uno_Environment * pCurrEnv = va_arg(*pParam, uno_Environment *);
272 uno_Environment * pTargetEnv = va_arg(*pParam, uno_Environment *);
273 uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *);
274 va_list * pXparam = va_arg(*pParam, va_list *);
276 s_environment_invoke_v(pCurrEnv, pTargetEnv, pCallee, pXparam);
279 static void s_environment_invoke_v(uno_Environment * pCurrEnv, uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
281 uno_Environment * pNextEnv = NULL;
282 switch(s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv))
284 case -1:
285 s_setCurrent(pNextEnv);
286 s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
287 s_setCurrent(pCurrEnv);
288 break;
290 case 0: {
291 uno_Environment * hld = s_getCurrent();
292 s_setCurrent(pCurrEnv);
293 pCallee(pParam);
294 s_setCurrent(hld);
296 break;
298 case 1:
299 s_setCurrent(pNextEnv);
300 s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam);
301 s_setCurrent(pCurrEnv);
302 break;
305 if (pNextEnv)
306 pNextEnv->release(pNextEnv);
309 extern "C" void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam)
310 SAL_THROW_EXTERN_C()
312 s_environment_invoke_v(s_getCurrent(), pTargetEnv, pCallee, pParam);
315 extern "C" void SAL_CALL uno_Environment_invoke(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
316 SAL_THROW_EXTERN_C()
318 va_list param;
320 va_start(param, pCallee);
321 uno_Environment_invoke_v(pEnv, pCallee, &param);
322 va_end(param);
325 extern "C" void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv)
326 SAL_THROW_EXTERN_C()
328 uno_Environment * pNextEnv = NULL;
329 uno_Environment * pCurrEnv = s_getCurrent();
331 int res;
332 while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0)
334 cppu::Enterable * pEnterable;
336 switch(res)
338 case -1:
339 pEnterable = static_cast<cppu::Enterable *>(pCurrEnv->pReserved);
340 if (pEnterable)
341 pEnterable->leave();
342 pCurrEnv->release(pCurrEnv);
343 break;
345 case 1:
346 pNextEnv->acquire(pNextEnv);
347 pEnterable = static_cast<cppu::Enterable *>(pNextEnv->pReserved);
348 if (pEnterable)
349 pEnterable->enter();
350 break;
353 s_setCurrent(pNextEnv);
354 pCurrEnv = pNextEnv;
358 int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason)
359 SAL_THROW_EXTERN_C()
361 int result = 1;
363 rtl::OUString typeName(cppu::EnvDcp::getTypeName(pEnv->pTypeName));
364 if (typeName == UNO_LB_UNO)
366 cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved);
367 if (pEnterable)
368 result = pEnterable->isValid(reinterpret_cast<rtl::OUString *>(pReason));
370 else
372 rtl::OUString envDcp(UNO_LB_UNO);
373 envDcp += cppu::EnvDcp::getPurpose(pEnv->pTypeName);
375 uno::Environment env(envDcp);
377 result = env.isValid(reinterpret_cast<rtl::OUString *>(pReason));
380 return result;
383 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */