bump product version to 4.1.6.2
[LibreOffice.git] / pyuno / source / loader / pyuno_loader.cxx
blob718edc744b46678df50011954fddc79099ac7005
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 <pyuno/pyuno.hxx>
22 #include <osl/process.h>
23 #include <osl/file.hxx>
24 #include <osl/thread.h>
26 #include <rtl/ustrbuf.hxx>
27 #include <rtl/strbuf.hxx>
28 #include <rtl/bootstrap.hxx>
30 #include <cppuhelper/implementationentry.hxx>
31 #include <cppuhelper/factory.hxx>
33 // apparently PATH_MAX is not standard and not defined by MSVC
34 #ifndef PATH_MAX
35 #ifdef _MAX_PATH
36 #define PATH_MAX _MAX_PATH
37 #else
38 #ifdef MAX_PATH
39 #define PATH_MAX MAX_PATH
40 #else
41 #error no PATH_MAX
42 #endif
43 #endif
44 #endif
47 using pyuno::PyRef;
48 using pyuno::Runtime;
49 using pyuno::PyThreadAttach;
51 using com::sun::star::registry::XRegistryKey;
52 using com::sun::star::uno::Reference;
53 using com::sun::star::uno::XInterface;
54 using com::sun::star::uno::Sequence;
55 using com::sun::star::uno::XComponentContext;
56 using com::sun::star::uno::RuntimeException;
58 namespace pyuno_loader
61 static void raiseRuntimeExceptionWhenNeeded() throw ( RuntimeException )
63 if( PyErr_Occurred() )
65 PyRef excType, excValue, excTraceback;
66 PyErr_Fetch( (PyObject **)&excType, (PyObject**)&excValue,(PyObject**)&excTraceback);
67 Runtime runtime;
68 com::sun::star::uno::Any a = runtime.extractUnoException( excType, excValue, excTraceback );
69 OUStringBuffer buf;
70 buf.appendAscii( "python-loader:" );
71 if( a.hasValue() )
72 buf.append( ((com::sun::star::uno::Exception *)a.getValue())->Message );
73 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface> () );
77 static PyRef getLoaderModule() throw( RuntimeException )
79 PyRef module(
80 PyImport_ImportModule( "pythonloader" ),
81 SAL_NO_ACQUIRE );
82 raiseRuntimeExceptionWhenNeeded();
83 if( !module.is() )
85 throw RuntimeException(
86 OUString( "pythonloader: Couldn't load pythonloader module" ),
87 Reference< XInterface > () );
89 return PyRef( PyModule_GetDict( module.get() ));
92 static PyRef getObjectFromLoaderModule( const char * func )
93 throw ( RuntimeException )
95 PyRef object( PyDict_GetItemString(getLoaderModule().get(), (char*)func ) );
96 if( !object.is() )
98 OUStringBuffer buf;
99 buf.appendAscii( "pythonloader: couldn't find core element pythonloader." );
100 buf.appendAscii( func );
101 throw RuntimeException(buf.makeStringAndClear(),Reference< XInterface >());
103 return object;
106 OUString getImplementationName()
108 return OUString( "org.openoffice.comp.pyuno.Loader" );
111 Sequence< OUString > getSupportedServiceNames()
113 OUString serviceName( "com.sun.star.loader.Python" );
114 return Sequence< OUString > ( &serviceName, 1 );
117 static void setPythonHome ( const OUString & pythonHome )
119 OUString systemPythonHome;
120 osl_getSystemPathFromFileURL( pythonHome.pData, &(systemPythonHome.pData) );
121 OString o = OUStringToOString( systemPythonHome, osl_getThreadTextEncoding() );
122 #if PY_MAJOR_VERSION >= 3
123 // static because Py_SetPythonHome just copies the "wide" pointer
124 static wchar_t wide[PATH_MAX + 1];
125 size_t len = mbstowcs(wide, o.pData->buffer, PATH_MAX + 1);
126 if(len == (size_t)-1)
128 PyErr_SetString(PyExc_SystemError, "invalid multibyte sequence in python home path");
129 return;
131 if(len == PATH_MAX + 1)
133 PyErr_SetString(PyExc_SystemError, "python home path is too long");
134 return;
136 Py_SetPythonHome(wide);
137 #else
138 rtl_string_acquire(o.pData); // increase reference count
139 Py_SetPythonHome(o.pData->buffer);
140 #endif
143 static void prependPythonPath( const OUString & pythonPathBootstrap )
145 OUStringBuffer bufPYTHONPATH( 256 );
146 sal_Int32 nIndex = 0;
147 while( 1 )
149 sal_Int32 nNew = pythonPathBootstrap.indexOf( ' ', nIndex );
150 OUString fileUrl;
151 if( nNew == -1 )
153 fileUrl = pythonPathBootstrap.copy(nIndex);
155 else
157 fileUrl = pythonPathBootstrap.copy(nIndex, nNew - nIndex);
159 OUString systemPath;
160 osl_getSystemPathFromFileURL( fileUrl.pData, &(systemPath.pData) );
161 bufPYTHONPATH.append( systemPath );
162 bufPYTHONPATH.append( static_cast<sal_Unicode>(SAL_PATHSEPARATOR) );
163 if( nNew == -1 )
164 break;
165 nIndex = nNew + 1;
167 const char * oldEnv = getenv( "PYTHONPATH");
168 if( oldEnv )
169 bufPYTHONPATH.append( OUString(oldEnv, strlen(oldEnv), osl_getThreadTextEncoding()) );
171 OUString envVar("PYTHONPATH");
172 OUString envValue(bufPYTHONPATH.makeStringAndClear());
173 osl_setEnvironment(envVar.pData, envValue.pData);
176 Reference< XInterface > CreateInstance( const Reference< XComponentContext > & ctx )
178 Reference< XInterface > ret;
180 if( ! Py_IsInitialized() )
182 OUString pythonPath;
183 OUString pythonHome;
184 OUString path( "$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("pythonloader.uno" ));
185 rtl::Bootstrap::expandMacros(path); //TODO: detect failure
186 rtl::Bootstrap bootstrap(path);
188 // look for pythonhome
189 bootstrap.getFrom( OUString( "PYUNO_LOADER_PYTHONHOME"), pythonHome );
190 bootstrap.getFrom( OUString( "PYUNO_LOADER_PYTHONPATH" ) , pythonPath );
192 // pythonhome+pythonpath must be set before Py_Initialize(), otherwise there appear warning on the console
193 // sadly, there is no api for setting the pythonpath, we have to use the environment variable
194 if( !pythonHome.isEmpty() )
195 setPythonHome( pythonHome );
197 if( !pythonPath.isEmpty() )
198 prependPythonPath( pythonPath );
200 #ifdef WNT
201 //extend PATH under windows to include the branddir/program so ssl libs will be found
202 //for use by terminal mailmerge dependency _ssl.pyd
203 OUString sEnvName("PATH");
204 OUString sPath;
205 osl_getEnvironment(sEnvName.pData, &sPath.pData);
206 OUString sBrandLocation("$BRAND_BASE_DIR/program");
207 rtl::Bootstrap::expandMacros(sBrandLocation);
208 osl::FileBase::getSystemPathFromFileURL(sBrandLocation, sBrandLocation);
209 sPath = OUStringBuffer(sPath).
210 append(static_cast<sal_Unicode>(SAL_PATHSEPARATOR)).
211 append(sBrandLocation).makeStringAndClear();
212 osl_setEnvironment(sEnvName.pData, sPath.pData);
213 #endif
215 #if PY_MAJOR_VERSION >= 3
216 PyImport_AppendInittab( (char*)"pyuno", PyInit_pyuno );
217 #else
218 PyImport_AppendInittab( (char*)"pyuno", initpyuno );
219 #endif
220 // initialize python
221 Py_Initialize();
222 PyEval_InitThreads();
224 PyThreadState *tstate = PyThreadState_Get();
225 PyEval_ReleaseThread( tstate );
226 // This tstate is never used again, so delete it here.
227 // This prevents an assertion in PyThreadState_Swap on the
228 // PyThreadAttach below.
229 PyThreadState_Delete(tstate);
232 PyThreadAttach attach( PyInterpreterState_Head() );
234 if( ! Runtime::isInitialized() )
236 Runtime::initialize( ctx );
238 Runtime runtime;
240 PyRef pyCtx = runtime.any2PyObject(
241 com::sun::star::uno::makeAny( ctx ) );
243 PyRef clazz = getObjectFromLoaderModule( "Loader" );
244 PyRef args ( PyTuple_New( 1 ), SAL_NO_ACQUIRE );
245 PyTuple_SetItem( args.get(), 0 , pyCtx.getAcquired() );
246 PyRef pyInstance( PyObject_CallObject( clazz.get() , args.get() ), SAL_NO_ACQUIRE );
247 runtime.pyObject2Any( pyInstance ) >>= ret;
249 return ret;
255 static struct cppu::ImplementationEntry g_entries[] =
258 pyuno_loader::CreateInstance, pyuno_loader::getImplementationName,
259 pyuno_loader::getSupportedServiceNames, cppu::createSingleComponentFactory,
260 0 , 0
262 { 0, 0, 0, 0, 0, 0 }
265 extern "C"
268 SAL_DLLPUBLIC_EXPORT void * SAL_CALL pythonloader_component_getFactory(
269 const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
271 return cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries );
276 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */