##// END OF EJS Templates
path: unify path creation in `get_pull_paths`...
path: unify path creation in `get_pull_paths` This remove a special case and will make it possible to return `path` instance directly. Differential Revision: https://phab.mercurial-scm.org/D11672

File last commit:

r48993:67d14d4e default
r49053:08630dd7 default
Show More
exewrapper.c
303 lines | 7.4 KiB | text/x-c | CLexer
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 /*
exewrapper.c - wrapper for calling a python script on Windows
Copyright 2012 Adrian Buehlmann <adrian@cadifra.com> and others
This software may be used and distributed according to the terms of the
GNU General Public License version 2 or any later version.
*/
Matt Harbison
py3: enable legacy stdio mode in exewrapper...
r41012 #include <Python.h>
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 #include <stdio.h>
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 #include <tchar.h>
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 #include <windows.h>
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 #include "hgpythonlib.h"
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058
#ifdef __GNUC__
int strcat_s(char *d, size_t n, const char *s)
{
return !strncat(d, s, n);
}
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 int strcpy_s(char *d, size_t n, const char *s)
{
return !strncpy(d, s, n);
}
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432
#define _tcscpy_s strcpy_s
#define _tcscat_s strcat_s
Yuya Nishihara
exewrapper: apply clang-format to silence test-check-clang-format.t
r40452 #define _countof(array) (sizeof(array) / sizeof(array[0]))
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 #endif
Matt Harbison
exewrapper: find the proper python3X.dll in the registry...
r48993 #if PY_MAJOR_VERSION >= 3
#pragma comment(lib, "Advapi32.lib")
/* python.org installations */
#define CORE_PATH L"SOFTWARE\\Python\\PythonCore"
/* Microsoft Store installations */
#define LOOKASIDE_PATH \
L"SOFTWARE\\Microsoft\\AppModel\\Lookaside\\user\\Software\\Python\\" \
L"PythonCore"
static wchar_t *_locate_python_for_key(HKEY root, LPCWSTR subkey, size_t *size)
{
wchar_t installPathKey[512];
wchar_t *executable = NULL;
DWORD type;
DWORD sz = 0;
HKEY ip_key;
LSTATUS status;
_snwprintf_s(installPathKey, sizeof(installPathKey), _TRUNCATE,
L"%ls\\%d.%d\\InstallPath", subkey, PY_MAJOR_VERSION,
PY_MINOR_VERSION);
status =
RegOpenKeyExW(root, installPathKey, 0, KEY_QUERY_VALUE, &ip_key);
if (status != ERROR_SUCCESS)
return NULL;
status = RegQueryValueExW(ip_key, L"ExecutablePath", NULL, &type,
(LPBYTE)executable, &sz);
if (status == ERROR_SUCCESS) {
/* Allocate extra space so path\to\python.exe can be converted
* to path\to\python39.dll + NUL.
*/
*size = sz + sizeof(_T(HGPYTHONLIB ".dll")) + sizeof(wchar_t);
executable = malloc(*size);
if (executable) {
status =
RegQueryValueExW(ip_key, L"ExecutablePath", NULL,
&type, (LPBYTE)executable, &sz);
if (status != ERROR_SUCCESS) {
free(executable);
executable = NULL;
} else {
/* Not all values are stored NUL terminated */
executable[sz] = L'\0';
}
}
}
RegCloseKey(ip_key);
return executable;
}
static HMODULE load_system_py3(void)
{
wchar_t *subkeys[] = {CORE_PATH, LOOKASIDE_PATH};
HKEY roots[] = {HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER};
/* Give priority to python.org installs, because MS Store installs can
* break with user profile corruption, and also use some NTFS feature
* that MSYS doesn't understand.
*/
for (int s = 0; s < _countof(subkeys); s++) {
for (int r = 0; r < _countof(roots); r++) {
size_t size = 0;
wchar_t *py =
_locate_python_for_key(roots[r], subkeys[s], &size);
wchar_t *cut = NULL;
HMODULE pydll;
if (!py) {
continue;
}
/* Cut off the python executable component */
cut = wcsrchr(py, L'\\');
if (cut == NULL) {
free(py);
continue;
}
*cut = 0;
wcscat_s(py, size, _T("\\" HGPYTHONLIB ".dll"));
pydll = LoadLibrary(py);
/* Also load python3.dll, so we don't pick up a random
* one on PATH. We don't search {sys.prefix}\DLLs like
* python.exe because this is commented as "not been a
* normal install layout for a while", and don't search
* LOAD_LIBRARY_SEARCH_APPLICATION_DIR because it's not
* clear what the use case is.
*/
if (pydll != NULL) {
HANDLE py3dll = NULL;
*cut = 0;
wcscat_s(py, size, L"\\python3.dll");
py3dll = LoadLibrary(py);
if (py3dll == NULL) {
const char *err;
err = "failed to load python3.dll "
"for " HGPYTHONLIB ".dll";
fprintf(stderr, "abort: %s (0x%X)\n",
err, GetLastError());
exit(255);
}
}
free(py);
if (pydll != NULL) {
return pydll;
}
}
}
return NULL;
}
#endif
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 static TCHAR pyscript[MAX_PATH + 10];
static TCHAR pyhome[MAX_PATH + 10];
static TCHAR pydllfile[MAX_PATH + 10];
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 int _tmain(int argc, TCHAR *argv[])
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 {
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 TCHAR *p;
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 int ret;
int i;
int n;
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 TCHAR **pyargv;
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 WIN32_FIND_DATA fdata;
HANDLE hfind;
const char *err;
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 HMODULE pydll;
Yuya Nishihara
exewrapper: apply clang-format to silence test-check-clang-format.t
r40452 void(__cdecl * Py_SetPythonHome)(TCHAR * home);
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 int(__cdecl * Py_Main)(int argc, TCHAR *argv[]);
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058
Matt Harbison
py3: enable legacy stdio mode in exewrapper...
r41012 #if PY_MAJOR_VERSION >= 3
Matt Harbison
exewrapper: avoid directly linking against python3X.dll...
r48096 _wputenv(L"PYTHONLEGACYWINDOWSSTDIO=1");
Matt Harbison
py3: enable legacy stdio mode in exewrapper...
r41012 #endif
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 if (GetModuleFileName(NULL, pyscript, _countof(pyscript)) == 0) {
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 err = "GetModuleFileName failed";
goto bail;
}
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 p = _tcsrchr(pyscript, '.');
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 if (p == NULL) {
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 err = "malformed module filename";
goto bail;
}
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 *p = 0; /* cut trailing ".exe" */
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 _tcscpy_s(pyhome, _countof(pyhome), pyscript);
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058
hfind = FindFirstFile(pyscript, &fdata);
if (hfind != INVALID_HANDLE_VALUE) {
/* pyscript exists, close handle */
FindClose(hfind);
} else {
/* file pyscript isn't there, take <pyscript>exe.py */
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 _tcscat_s(pyscript, _countof(pyscript), _T("exe.py"));
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 }
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 pydll = NULL;
Kostia Balytskyi
exewrapper: prefer HackableMercurial python if availbale...
r31443
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 p = _tcsrchr(pyhome, _T('\\'));
Kostia Balytskyi
exewrapper: prefer HackableMercurial python if availbale...
r31443 if (p == NULL) {
err = "can't find backslash in module filename";
goto bail;
}
*p = 0; /* cut at directory */
/* check for private Python of HackableMercurial */
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 _tcscat_s(pyhome, _countof(pyhome), _T("\\hg-python"));
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732
Kostia Balytskyi
exewrapper: prefer HackableMercurial python if availbale...
r31443 hfind = FindFirstFile(pyhome, &fdata);
if (hfind != INVALID_HANDLE_VALUE) {
/* Path .\hg-python exists. We are probably in HackableMercurial
scenario, so let's load python dll from this dir. */
FindClose(hfind);
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 _tcscpy_s(pydllfile, _countof(pydllfile), pyhome);
Yuya Nishihara
exewrapper: apply clang-format to silence test-check-clang-format.t
r40452 _tcscat_s(pydllfile, _countof(pydllfile),
_T("\\") _T(HGPYTHONLIB) _T(".dll"));
Kostia Balytskyi
exewrapper: prefer HackableMercurial python if availbale...
r31443 pydll = LoadLibrary(pydllfile);
if (pydll == NULL) {
Yuya Nishihara
exewrapper: apply clang-format to silence test-check-clang-format.t
r40452 err = "failed to load private Python DLL " HGPYTHONLIB
".dll";
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 goto bail;
}
Augie Fackler
exewrapper: format with clang-format...
r34637 Py_SetPythonHome =
(void *)GetProcAddress(pydll, "Py_SetPythonHome");
Kostia Balytskyi
exewrapper: prefer HackableMercurial python if availbale...
r31443 if (Py_SetPythonHome == NULL) {
err = "failed to get Py_SetPythonHome";
goto bail;
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 }
Kostia Balytskyi
exewrapper: prefer HackableMercurial python if availbale...
r31443 Py_SetPythonHome(pyhome);
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 }
Matt Harbison
exewrapper: find the proper python3X.dll in the registry...
r48993 #if PY_MAJOR_VERSION >= 3
if (pydll == NULL) {
pydll = load_system_py3();
}
#endif
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 if (pydll == NULL) {
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 pydll = LoadLibrary(_T(HGPYTHONLIB) _T(".dll"));
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 if (pydll == NULL) {
Adrian Buehlmann
exewrapper: report name of failed DLL in error message...
r26662 err = "failed to load Python DLL " HGPYTHONLIB ".dll";
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 goto bail;
}
}
Augie Fackler
exewrapper: format with clang-format...
r34637 Py_Main = (void *)GetProcAddress(pydll, "Py_Main");
Adrian Buehlmann
exewrapper: adapt for legacy HackableMercurial...
r17732 if (Py_Main == NULL) {
err = "failed to get Py_Main";
goto bail;
}
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 /*
Only add the pyscript to the args, if it's not already there. It may
Adrian Buehlmann
exewrapper: use generic term script...
r17063 already be there, if the script spawned a child process of itself, in
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 the same way as it got called, that is, with the pyscript already in
place. So we optionally accept the pyscript as the first argument
(argv[1]), letting our exe taking the role of the python interpreter.
*/
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 if (argc >= 2 && _tcscmp(argv[1], pyscript) == 0) {
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 /*
pyscript is already in the args, so there is no need to copy
the args and we can directly call the python interpreter with
the original args.
*/
return Py_Main(argc, argv);
}
/*
Start assembling the args for the Python interpreter call. We put the
name of our exe (argv[0]) in the position where the python.exe
canonically is, and insert the pyscript next.
*/
Matt Harbison
exewrapper: convert to _tcsxxx functions for Unicode compatability...
r40432 pyargv = malloc((argc + 5) * sizeof(TCHAR *));
Adrian Buehlmann
exewrapper: adding new exewrapper.c
r17058 if (pyargv == NULL) {
err = "not enough memory";
goto bail;
}
n = 0;
pyargv[n++] = argv[0];
pyargv[n++] = pyscript;
/* copy remaining args from the command line */
for (i = 1; i < argc; i++)
pyargv[n++] = argv[i];
/* argv[argc] is guaranteed to be NULL, so we forward that guarantee */
pyargv[n] = NULL;
ret = Py_Main(n, pyargv); /* The Python interpreter call */
free(pyargv);
return ret;
bail:
fprintf(stderr, "abort: %s\n", err);
return 255;
}