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