1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
;
49 struct SAL_DLLPRIVATE oslThreadIdentifier_hash
51 size_t operator()(oslThreadIdentifier s1
) const;
54 size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1
) const
59 typedef ::boost::unordered_map
<oslThreadIdentifier
,
61 oslThreadIdentifier_hash
,
62 oslThreadIdentifier_equal
> ThreadMap
;
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();
78 rThreadMap
[threadId
] = pEnv
;
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())
104 extern "C" CPPU_DLLPUBLIC
void SAL_CALL
uno_getCurrentEnvironment(uno_Environment
** ppEnv
, rtl_uString
* pTypeName
)
109 (*ppEnv
)->release(*ppEnv
);
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
);
131 (*ppEnv
)->acquire(*ppEnv
);
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;
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
;
163 result
= str1
.copy(0, sim
- 1);
168 static int s_getNextEnv(uno_Environment
** ppEnv
, uno_Environment
* pCurrEnv
, uno_Environment
* pTargetEnv
)
172 rtl::OUString nextPurpose
;
174 rtl::OUString currPurpose
;
176 currPurpose
= cppu::EnvDcp::getPurpose(pCurrEnv
->pTypeName
);
178 rtl::OUString targetPurpose
;
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
);
190 else if (intermPurpose
.getLength() < targetPurpose
.getLength())
192 sal_Int32 idx
= targetPurpose
.indexOf(':', intermPurpose
.getLength() + 1);
194 nextPurpose
= targetPurpose
;
197 nextPurpose
= targetPurpose
.copy(0, idx
);
202 if (!nextPurpose
.isEmpty())
204 rtl::OUString
next_envDcp(UNO_LB_UNO
);
205 next_envDcp
+= nextPurpose
;
207 uno_getEnvironment(ppEnv
, next_envDcp
.pData
, NULL
);
212 (*ppEnv
)->release(*ppEnv
);
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 *);
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
);
232 pEnterable
->callInto(s_pull
, pCallee
, pParam
);
238 static void s_callInto(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...)
242 va_start(param
, pCallee
);
243 s_callInto_v(pEnv
, pCallee
, ¶m
);
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
);
251 pEnterable
->callOut_v(pCallee
, pParam
);
257 static void s_callOut(uno_Environment
* pEnv
, uno_EnvCallee
* pCallee
, ...)
261 va_start(param
, pCallee
);
262 s_callOut_v(pEnv
, pCallee
, ¶m
);
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
))
284 s_setCurrent(pNextEnv
);
285 s_callOut(pCurrEnv
, s_environment_invoke_vv
, pNextEnv
, pTargetEnv
, pCallee
, pParam
);
286 s_setCurrent(pCurrEnv
);
290 uno_Environment
* hld
= s_getCurrent();
291 s_setCurrent(pCurrEnv
);
298 s_setCurrent(pNextEnv
);
299 s_callInto(pNextEnv
, s_environment_invoke_vv
, pNextEnv
, pTargetEnv
, pCallee
, pParam
);
300 s_setCurrent(pCurrEnv
);
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
)
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
, ...)
319 va_start(param
, pCallee
);
320 uno_Environment_invoke_v(pEnv
, pCallee
, ¶m
);
324 extern "C" CPPU_DLLPUBLIC
void SAL_CALL
uno_Environment_enter(uno_Environment
* pTargetEnv
)
327 uno_Environment
* pNextEnv
= NULL
;
328 uno_Environment
* pCurrEnv
= s_getCurrent();
331 while ( (res
= s_getNextEnv(&pNextEnv
, pCurrEnv
, pTargetEnv
)) != 0)
333 cppu::Enterable
* pEnterable
;
338 pEnterable
= reinterpret_cast<cppu::Enterable
*>(pCurrEnv
->pReserved
);
341 pCurrEnv
->release(pCurrEnv
);
345 pNextEnv
->acquire(pNextEnv
);
346 pEnterable
= reinterpret_cast<cppu::Enterable
*>(pNextEnv
->pReserved
);
352 s_setCurrent(pNextEnv
);
357 CPPU_DLLPUBLIC
int SAL_CALL
uno_Environment_isValid(uno_Environment
* pEnv
, rtl_uString
** pReason
)
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
);
367 result
= pEnterable
->isValid((rtl::OUString
*)pReason
);
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
);
382 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */