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 <config_folders.h>
22 #include <pyuno/pyuno.hxx>
24 #include <osl/process.h>
25 #include <osl/file.hxx>
26 #include <osl/thread.h>
28 #include <rtl/ustrbuf.hxx>
29 #include <rtl/strbuf.hxx>
30 #include <rtl/bootstrap.hxx>
32 #include <cppuhelper/implementationentry.hxx>
33 #include <cppuhelper/factory.hxx>
35 // apparently PATH_MAX is not standard and not defined by MSVC
38 #define PATH_MAX _MAX_PATH
41 #define PATH_MAX MAX_PATH
51 using pyuno::PyThreadAttach
;
53 using com::sun::star::registry::XRegistryKey
;
54 using com::sun::star::uno::Reference
;
55 using com::sun::star::uno::XInterface
;
56 using com::sun::star::uno::Sequence
;
57 using com::sun::star::uno::XComponentContext
;
58 using com::sun::star::uno::RuntimeException
;
60 namespace pyuno_loader
63 static void raiseRuntimeExceptionWhenNeeded() throw ( RuntimeException
)
65 if( PyErr_Occurred() )
67 PyRef excType
, excValue
, excTraceback
;
68 PyErr_Fetch( (PyObject
**)&excType
, (PyObject
**)&excValue
,(PyObject
**)&excTraceback
);
70 com::sun::star::uno::Any a
= runtime
.extractUnoException( excType
, excValue
, excTraceback
);
72 buf
.appendAscii( "python-loader:" );
74 buf
.append( ((com::sun::star::uno::Exception
*)a
.getValue())->Message
);
75 throw RuntimeException( buf
.makeStringAndClear(), Reference
< XInterface
> () );
79 static PyRef
getLoaderModule() throw( RuntimeException
)
82 PyImport_ImportModule( "pythonloader" ),
84 raiseRuntimeExceptionWhenNeeded();
87 throw RuntimeException(
88 OUString( "pythonloader: Couldn't load pythonloader module" ),
89 Reference
< XInterface
> () );
91 return PyRef( PyModule_GetDict( module
.get() ));
94 static PyRef
getObjectFromLoaderModule( const char * func
)
95 throw ( RuntimeException
)
97 PyRef
object( PyDict_GetItemString(getLoaderModule().get(), (char*)func
) );
101 buf
.appendAscii( "pythonloader: couldn't find core element pythonloader." );
102 buf
.appendAscii( func
);
103 throw RuntimeException(buf
.makeStringAndClear(),Reference
< XInterface
>());
108 OUString
getImplementationName()
110 return OUString( "org.openoffice.comp.pyuno.Loader" );
113 Sequence
< OUString
> getSupportedServiceNames()
115 OUString
serviceName( "com.sun.star.loader.Python" );
116 return Sequence
< OUString
> ( &serviceName
, 1 );
119 static void setPythonHome ( const OUString
& pythonHome
)
121 OUString systemPythonHome
;
122 osl_getSystemPathFromFileURL( pythonHome
.pData
, &(systemPythonHome
.pData
) );
123 OString o
= OUStringToOString( systemPythonHome
, osl_getThreadTextEncoding() );
124 #if PY_MAJOR_VERSION >= 3
125 // static because Py_SetPythonHome just copies the "wide" pointer
126 static wchar_t wide
[PATH_MAX
+ 1];
127 size_t len
= mbstowcs(wide
, o
.pData
->buffer
, PATH_MAX
+ 1);
128 if(len
== (size_t)-1)
130 PyErr_SetString(PyExc_SystemError
, "invalid multibyte sequence in python home path");
133 if(len
== PATH_MAX
+ 1)
135 PyErr_SetString(PyExc_SystemError
, "python home path is too long");
138 Py_SetPythonHome(wide
);
140 rtl_string_acquire(o
.pData
); // increase reference count
141 Py_SetPythonHome(o
.pData
->buffer
);
145 static void prependPythonPath( const OUString
& pythonPathBootstrap
)
147 OUStringBuffer
bufPYTHONPATH( 256 );
148 sal_Int32 nIndex
= 0;
151 sal_Int32 nNew
= pythonPathBootstrap
.indexOf( ' ', nIndex
);
155 fileUrl
= pythonPathBootstrap
.copy(nIndex
);
159 fileUrl
= pythonPathBootstrap
.copy(nIndex
, nNew
- nIndex
);
162 osl_getSystemPathFromFileURL( fileUrl
.pData
, &(systemPath
.pData
) );
163 bufPYTHONPATH
.append( systemPath
);
164 bufPYTHONPATH
.append( static_cast<sal_Unicode
>(SAL_PATHSEPARATOR
) );
169 const char * oldEnv
= getenv( "PYTHONPATH");
171 bufPYTHONPATH
.append( OUString(oldEnv
, strlen(oldEnv
), osl_getThreadTextEncoding()) );
173 OUString
envVar("PYTHONPATH");
174 OUString
envValue(bufPYTHONPATH
.makeStringAndClear());
175 osl_setEnvironment(envVar
.pData
, envValue
.pData
);
178 Reference
< XInterface
> CreateInstance( const Reference
< XComponentContext
> & ctx
)
180 Reference
< XInterface
> ret
;
182 if( ! Py_IsInitialized() )
186 OUString
path( "$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("pythonloader.uno" ));
187 rtl::Bootstrap::expandMacros(path
); //TODO: detect failure
188 rtl::Bootstrap
bootstrap(path
);
190 // look for pythonhome
191 bootstrap
.getFrom( OUString( "PYUNO_LOADER_PYTHONHOME"), pythonHome
);
192 bootstrap
.getFrom( OUString( "PYUNO_LOADER_PYTHONPATH" ) , pythonPath
);
194 // pythonhome+pythonpath must be set before Py_Initialize(), otherwise there appear warning on the console
195 // sadly, there is no api for setting the pythonpath, we have to use the environment variable
196 if( !pythonHome
.isEmpty() )
197 setPythonHome( pythonHome
);
199 if( !pythonPath
.isEmpty() )
200 prependPythonPath( pythonPath
);
203 //extend PATH under windows to include the branddir/program so ssl libs will be found
204 //for use by terminal mailmerge dependency _ssl.pyd
205 OUString
sEnvName("PATH");
207 osl_getEnvironment(sEnvName
.pData
, &sPath
.pData
);
208 OUString
sBrandLocation("$BRAND_BASE_DIR/program");
209 rtl::Bootstrap::expandMacros(sBrandLocation
);
210 osl::FileBase::getSystemPathFromFileURL(sBrandLocation
, sBrandLocation
);
211 sPath
= OUStringBuffer(sPath
).
212 append(static_cast<sal_Unicode
>(SAL_PATHSEPARATOR
)).
213 append(sBrandLocation
).makeStringAndClear();
214 osl_setEnvironment(sEnvName
.pData
, sPath
.pData
);
217 #if PY_MAJOR_VERSION >= 3
218 PyImport_AppendInittab( (char*)"pyuno", PyInit_pyuno
);
220 PyImport_AppendInittab( (char*)"pyuno", initpyuno
);
224 PyEval_InitThreads();
226 PyThreadState
*tstate
= PyThreadState_Get();
227 PyEval_ReleaseThread( tstate
);
228 // This tstate is never used again, so delete it here.
229 // This prevents an assertion in PyThreadState_Swap on the
230 // PyThreadAttach below.
231 PyThreadState_Delete(tstate
);
234 PyThreadAttach
attach( PyInterpreterState_Head() );
236 if( ! Runtime::isInitialized() )
238 Runtime::initialize( ctx
);
242 PyRef pyCtx
= runtime
.any2PyObject(
243 com::sun::star::uno::makeAny( ctx
) );
245 PyRef clazz
= getObjectFromLoaderModule( "Loader" );
246 PyRef
args ( PyTuple_New( 1 ), SAL_NO_ACQUIRE
);
247 PyTuple_SetItem( args
.get(), 0 , pyCtx
.getAcquired() );
248 PyRef
pyInstance( PyObject_CallObject( clazz
.get() , args
.get() ), SAL_NO_ACQUIRE
);
249 runtime
.pyObject2Any( pyInstance
) >>= ret
;
257 static const struct cppu::ImplementationEntry g_entries
[] =
260 pyuno_loader::CreateInstance
, pyuno_loader::getImplementationName
,
261 pyuno_loader::getSupportedServiceNames
, cppu::createSingleComponentFactory
,
270 SAL_DLLPUBLIC_EXPORT
void * SAL_CALL
pythonloader_component_getFactory(
271 const sal_Char
* pImplName
, void * pServiceManager
, void * pRegistryKey
)
273 return cppu::component_getFactoryHelper( pImplName
, pServiceManager
, pRegistryKey
, g_entries
);
278 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */