Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / pyuno / source / loader / pyuno_loader.cxx
blob375ea21d4562258ba2248a6f11202859eea8a61d
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 <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
36 #ifndef PATH_MAX
37 #ifdef _MAX_PATH
38 #define PATH_MAX _MAX_PATH
39 #else
40 #ifdef MAX_PATH
41 #define PATH_MAX MAX_PATH
42 #else
43 #error no PATH_MAX
44 #endif
45 #endif
46 #endif
49 using pyuno::PyRef;
50 using pyuno::Runtime;
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);
69 Runtime runtime;
70 com::sun::star::uno::Any a = runtime.extractUnoException( excType, excValue, excTraceback );
71 OUStringBuffer buf;
72 buf.appendAscii( "python-loader:" );
73 if( a.hasValue() )
74 buf.append( ((com::sun::star::uno::Exception *)a.getValue())->Message );
75 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface> () );
79 static PyRef getLoaderModule() throw( RuntimeException )
81 PyRef module(
82 PyImport_ImportModule( "pythonloader" ),
83 SAL_NO_ACQUIRE );
84 raiseRuntimeExceptionWhenNeeded();
85 if( !module.is() )
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 ) );
98 if( !object.is() )
100 OUStringBuffer buf;
101 buf.appendAscii( "pythonloader: couldn't find core element pythonloader." );
102 buf.appendAscii( func );
103 throw RuntimeException(buf.makeStringAndClear(),Reference< XInterface >());
105 return object;
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");
131 return;
133 if(len == PATH_MAX + 1)
135 PyErr_SetString(PyExc_SystemError, "python home path is too long");
136 return;
138 Py_SetPythonHome(wide);
139 #else
140 rtl_string_acquire(o.pData); // increase reference count
141 Py_SetPythonHome(o.pData->buffer);
142 #endif
145 static void prependPythonPath( const OUString & pythonPathBootstrap )
147 OUStringBuffer bufPYTHONPATH( 256 );
148 sal_Int32 nIndex = 0;
149 while( 1 )
151 sal_Int32 nNew = pythonPathBootstrap.indexOf( ' ', nIndex );
152 OUString fileUrl;
153 if( nNew == -1 )
155 fileUrl = pythonPathBootstrap.copy(nIndex);
157 else
159 fileUrl = pythonPathBootstrap.copy(nIndex, nNew - nIndex);
161 OUString systemPath;
162 osl_getSystemPathFromFileURL( fileUrl.pData, &(systemPath.pData) );
163 bufPYTHONPATH.append( systemPath );
164 bufPYTHONPATH.append( static_cast<sal_Unicode>(SAL_PATHSEPARATOR) );
165 if( nNew == -1 )
166 break;
167 nIndex = nNew + 1;
169 const char * oldEnv = getenv( "PYTHONPATH");
170 if( oldEnv )
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() )
184 OUString pythonPath;
185 OUString pythonHome;
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 );
202 #ifdef WNT
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");
206 OUString sPath;
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);
215 #endif
217 #if PY_MAJOR_VERSION >= 3
218 PyImport_AppendInittab( (char*)"pyuno", PyInit_pyuno );
219 #else
220 PyImport_AppendInittab( (char*)"pyuno", initpyuno );
221 #endif
222 // initialize python
223 Py_Initialize();
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 );
240 Runtime runtime;
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;
251 return ret;
257 static const struct cppu::ImplementationEntry g_entries[] =
260 pyuno_loader::CreateInstance, pyuno_loader::getImplementationName,
261 pyuno_loader::getSupportedServiceNames, cppu::createSingleComponentFactory,
262 0 , 0
264 { 0, 0, 0, 0, 0, 0 }
267 extern "C"
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: */