xref: /AOO41X/main/pyuno/zipcore/python.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <cstddef>
29 #include <stdlib.h>
30 #include <wchar.h>
31 
32 #define WIN32_LEAN_AND_MEAN
33 #if defined _MSC_VER
34 #pragma warning(push, 1)
35 #endif
36 #include <windows.h>
37 #if defined _MSC_VER
38 #pragma warning(pop)
39 #endif
40 
41 #include "tools/pathutils.hxx"
42 
43 #include "pyversion.hxx"
44 
45 #define MY_LENGTH(s) (sizeof (s) / sizeof *(s) - 1)
46 #define MY_STRING(s) (s), MY_LENGTH(s)
47 
48 wchar_t * encode(wchar_t * buffer, wchar_t const * text) {
49     *buffer++ = L'"';
50     std::size_t n = 0;
51     for (;;) {
52         wchar_t c = *text++;
53         if (c == L'\0') {
54             break;
55         } else if (c == L'"') {
56             // Double any preceding backslashes as required by Windows:
57             for (std::size_t i = 0; i < n; ++i) {
58                 *buffer++ = L'\\';
59             }
60             *buffer++ = L'\\';
61             *buffer++ = L'"';
62             n = 0;
63         } else if (c == L'\\') {
64             *buffer++ = L'\\';
65             ++n;
66         } else {
67             *buffer++ = c;
68             n = 0;
69         }
70     }
71     // The command line will continue with a double quote, so double any
72     // preceding backslashes as required by Windows:
73     for (std::size_t i = 0; i < n; ++i) {
74         *buffer++ = L'\\';
75     }
76     *buffer++ = L'"';
77     return buffer;
78 }
79 
80 #ifdef __MINGW32__
81 int main(int argc, char ** argv, char **) {
82 #else
83 int wmain(int argc, wchar_t ** argv, wchar_t **) {
84 #endif
85     wchar_t path[MAX_PATH];
86     DWORD n = GetModuleFileNameW(NULL, path, MAX_PATH);
87     if (n == 0 || n >= MAX_PATH) {
88         exit(EXIT_FAILURE);
89     }
90     wchar_t * pathEnd = tools::filename(path);
91     *pathEnd = L'\0';
92     n = GetEnvironmentVariableW(L"UNO_PATH", NULL, 0);
93     if (n == 0) {
94         if (GetLastError() != ERROR_ENVVAR_NOT_FOUND ||
95             !SetEnvironmentVariableW(L"UNO_PATH", path))
96         {
97             exit(EXIT_FAILURE);
98         }
99     }
100     wchar_t bootstrap[MY_LENGTH(L"vnd.sun.star.pathname:") + MAX_PATH] =
101         L"vnd.sun.star.pathname:"; //TODO: overflow
102     wchar_t * bootstrapEnd = tools::buildPath(
103         bootstrap + MY_LENGTH(L"vnd.sun.star.pathname:"), path, pathEnd,
104         MY_STRING(L"fundamental.ini"));
105     if (bootstrapEnd == NULL ||
106         (tools::buildPath(path, path, pathEnd, MY_STRING(L"..\\basis-link"))
107          == NULL))
108     {
109         exit(EXIT_FAILURE);
110     }
111     pathEnd = tools::resolveLink(path);
112     wchar_t path1[MAX_PATH];
113     wchar_t * path1End = tools::buildPath(
114         path1, path, pathEnd, MY_STRING(L"\\program"));
115     if (path1End == NULL) {
116         exit(EXIT_FAILURE);
117     }
118     wchar_t pythonpath2[MAX_PATH];
119     wchar_t * pythonpath2End = tools::buildPath(
120         pythonpath2, path, pathEnd,
121         MY_STRING(L"\\program\\python-core-" MY_PYVERSION L"\\lib"));
122     if (pythonpath2End == NULL) {
123         exit(EXIT_FAILURE);
124     }
125     wchar_t pythonpath3[MAX_PATH];
126     wchar_t * pythonpath3End = tools::buildPath(
127         pythonpath3, path, pathEnd,
128         MY_STRING(
129             L"\\program\\python-core-" MY_PYVERSION L"\\lib\\site-packages"));
130     if (pythonpath3End == NULL) {
131         exit(EXIT_FAILURE);
132     }
133 #ifdef __MINGW32__
134     wchar_t pythonpath4[MAX_PATH];
135     wchar_t * pythonpath4End = tools::buildPath(
136         pythonpath4, path, pathEnd,
137         MY_STRING(L"\\program\\python-core-" MY_PYVERSION L"\\lib\\lib-dynload"));
138     if (pythonpath4End == NULL) {
139         exit(EXIT_FAILURE);
140     }
141     wchar_t pythonpath5[MAX_PATH];
142     wchar_t * pythonpath5End = tools::buildPath(
143         pythonpath5, path, pathEnd,
144         MY_STRING(L"\\program\\python-core-" MY_PYVERSION L"\\lib\\lib-dynload"));
145     if (pythonpath5End == NULL) {
146         exit(EXIT_FAILURE);
147     }
148 #endif
149     wchar_t pythonhome[MAX_PATH];
150     wchar_t * pythonhomeEnd = tools::buildPath(
151         pythonhome, path, pathEnd,
152         MY_STRING(L"\\program\\python-core-" MY_PYVERSION));
153     if (pythonhomeEnd == NULL) {
154         exit(EXIT_FAILURE);
155     }
156     wchar_t pythonexe[MAX_PATH];
157     wchar_t * pythonexeEnd = tools::buildPath(
158         pythonexe, path, pathEnd,
159 #ifdef __MINGW32__
160         MY_STRING(
161             L"\\program\\python-core-" MY_PYVERSION L"\\bin\\python.bin"));
162 #else
163         MY_STRING(
164             L"\\program\\python-core-" MY_PYVERSION L"\\bin\\python.exe"));
165 #endif
166     if (pythonexeEnd == NULL) {
167         exit(EXIT_FAILURE);
168     }
169     if (tools::buildPath(path, path, pathEnd, MY_STRING(L"\\ure-link")) == NULL)
170     {
171         exit(EXIT_FAILURE);
172     }
173     pathEnd = tools::resolveLink(path);
174     if (pathEnd == NULL) {
175         exit(EXIT_FAILURE);
176     }
177     pathEnd = tools::buildPath(path, path, pathEnd, MY_STRING(L"\\bin"));
178     if (pathEnd == NULL) {
179         exit(EXIT_FAILURE);
180     }
181     std::size_t clSize = MY_LENGTH(L"\"") + 4 * (pythonexeEnd - pythonexe) +
182         MY_LENGTH(L"\"\0"); //TODO: overflow
183         // 4 * len: each char preceded by backslash, each trailing backslash
184         // doubled
185     for (int i = 1; i < argc; ++i) {
186 #ifdef __MINGW32__
187         clSize += MY_LENGTH(L" \"") + 4 * strlen(argv[i]) +
188 #else
189         clSize += MY_LENGTH(L" \"") + 4 * wcslen(argv[i]) +
190 #endif
191             MY_LENGTH(L"\""); //TODO: overflow
192     }
193     wchar_t * cl = new wchar_t[clSize];
194     if (cl == NULL) {
195         exit(EXIT_FAILURE);
196     }
197     wchar_t * cp = encode(cl, pythonhome);
198     for (int i = 1; i < argc; ++i) {
199         *cp++ = L' ';
200 #ifdef __MINGW32__
201         int nNeededWStrBuffSize = MultiByteToWideChar(CP_ACP, 0, argv[i], -1, NULL, 0);
202         WCHAR *buff = new WCHAR[nNeededWStrBuffSize+1];
203         MultiByteToWideChar(CP_ACP, 0, argv[i], -1, buff, nNeededWStrBuffSize);
204         buff[nNeededWStrBuffSize] = 0;
205         cp = encode(cp, buff);
206         delete [] buff;
207 #else
208         cp = encode(cp, argv[i]);
209 #endif
210     }
211     *cp = L'\0';
212     n = GetEnvironmentVariableW(L"PATH", NULL, 0);
213     wchar_t * orig;
214     if (n == 0) {
215         if (GetLastError() != ERROR_ENVVAR_NOT_FOUND) {
216             exit(EXIT_FAILURE);
217         }
218         orig = L"";
219     } else {
220         orig = new wchar_t[n];
221         if (orig == NULL ||
222             GetEnvironmentVariableW(L"PATH", orig, n) != n - 1)
223         {
224             exit(EXIT_FAILURE);
225         }
226     }
227     wchar_t * value = new wchar_t[
228         (pathEnd - path) + MY_LENGTH(L";") + (path1End - path1) +
229         (n == 0 ? 0 : MY_LENGTH(L";") + (n - 1)) + 1]; //TODO: overflow
230     wsprintfW(value, L"%s;%s%s%s", path, path1, n == 0 ? L"" : L";", orig);
231     if (!SetEnvironmentVariableW(L"PATH", value)) {
232         exit(EXIT_FAILURE);
233     }
234     if (n != 0) {
235         delete [] orig;
236     }
237     delete [] value;
238     n = GetEnvironmentVariableW(L"PYTHONPATH", NULL, 0);
239     if (n == 0) {
240         if (GetLastError() != ERROR_ENVVAR_NOT_FOUND) {
241             exit(EXIT_FAILURE);
242         }
243         orig = L"";
244     } else {
245         orig = new wchar_t[n];
246         if (orig == NULL ||
247             GetEnvironmentVariableW(L"PYTHONPATH", orig, n) != n - 1)
248         {
249             exit(EXIT_FAILURE);
250         }
251     }
252 #ifdef __MINGW32__
253     value = new wchar_t[
254         (path1End - path1) + MY_LENGTH(L";") + (pythonpath2End - pythonpath2) +
255         MY_LENGTH(L";") + (pythonpath4End - pythonpath4) +
256         MY_LENGTH(L";") + (pythonpath5End - pythonpath5) +
257         MY_LENGTH(L";") + (pythonpath3End - pythonpath3) +
258         (n == 0 ? 0 : MY_LENGTH(L";") + (n - 1)) + 1]; //TODO: overflow
259     wsprintfW(
260         value, L"%s;%s;%s;%s;%s%s%s", path1, pythonpath2, pythonpath4,
261         pythonpath5, pythonpath3,
262         n == 0 ? L"" : L";", orig);
263 #else
264     value = new wchar_t[
265         (path1End - path1) + MY_LENGTH(L";") + (pythonpath2End - pythonpath2) +
266         MY_LENGTH(L";") + (pythonpath3End - pythonpath3) +
267         (n == 0 ? 0 : MY_LENGTH(L";") + (n - 1)) + 1]; //TODO: overflow
268     wsprintfW(
269         value, L"%s;%s;%s%s%s", path1, pythonpath2, pythonpath3,
270         n == 0 ? L"" : L";", orig);
271 #endif
272     if (!SetEnvironmentVariableW(L"PYTHONPATH", value)) {
273         exit(EXIT_FAILURE);
274     }
275     if (n != 0) {
276         delete [] orig;
277     }
278     delete [] value;
279     if (!SetEnvironmentVariableW(L"PYTHONHOME", pythonhome)) {
280         exit(EXIT_FAILURE);
281     }
282     n = GetEnvironmentVariableW(L"URE_BOOTSTRAP", NULL, 0);
283     if (n == 0) {
284         if (GetLastError() != ERROR_ENVVAR_NOT_FOUND ||
285             !SetEnvironmentVariableW(L"URE_BOOTSTRAP", bootstrap))
286         {
287             exit(EXIT_FAILURE);
288         }
289     }
290     STARTUPINFOW startinfo;
291     ZeroMemory(&startinfo, sizeof (STARTUPINFOW));
292     startinfo.cb = sizeof (STARTUPINFOW);
293     PROCESS_INFORMATION procinfo;
294     if (!CreateProcessW(
295             pythonexe, cl, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, NULL,
296             NULL, &startinfo, &procinfo)) {
297         exit(EXIT_FAILURE);
298     }
299     WaitForSingleObject(procinfo.hProcess,INFINITE);
300     DWORD exitStatus;
301     GetExitCodeProcess(procinfo.hProcess,&exitStatus);
302     exit(exitStatus);
303 }
304