diff options
| author | nkozlovskiy <[email protected]> | 2023-09-29 12:24:06 +0300 |
|---|---|---|
| committer | nkozlovskiy <[email protected]> | 2023-09-29 12:41:34 +0300 |
| commit | e0e3e1717e3d33762ce61950504f9637a6e669ed (patch) | |
| tree | bca3ff6939b10ed60c3d5c12439963a1146b9711 /contrib/tools/python/src/PC | |
| parent | 38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff) | |
add ydb deps
Diffstat (limited to 'contrib/tools/python/src/PC')
| -rw-r--r-- | contrib/tools/python/src/PC/_subprocess.c | 822 | ||||
| -rw-r--r-- | contrib/tools/python/src/PC/_winreg.c | 1872 | ||||
| -rw-r--r-- | contrib/tools/python/src/PC/dl_nt.c | 106 | ||||
| -rw-r--r-- | contrib/tools/python/src/PC/errmap.h | 78 | ||||
| -rw-r--r-- | contrib/tools/python/src/PC/getpathp.c | 715 | ||||
| -rw-r--r-- | contrib/tools/python/src/PC/import_nt.c | 86 | ||||
| -rw-r--r-- | contrib/tools/python/src/PC/msvcrtmodule.c | 430 |
7 files changed, 4109 insertions, 0 deletions
diff --git a/contrib/tools/python/src/PC/_subprocess.c b/contrib/tools/python/src/PC/_subprocess.c new file mode 100644 index 00000000000..5d0665d564a --- /dev/null +++ b/contrib/tools/python/src/PC/_subprocess.c @@ -0,0 +1,822 @@ +/* + * support routines for subprocess module + * + * Currently, this extension module is only required when using the + * subprocess module on Windows, but in the future, stubs for other + * platforms might be added here as well. + * + * Copyright (c) 2004 by Fredrik Lundh <[email protected]> + * Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com + * Copyright (c) 2004 by Peter Astrand <[email protected]> + * + * By obtaining, using, and/or copying this software and/or its + * associated documentation, you agree that you have read, understood, + * and will comply with the following terms and conditions: + * + * Permission to use, copy, modify, and distribute this software and + * its associated documentation for any purpose and without fee is + * hereby granted, provided that the above copyright notice appears in + * all copies, and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of the + * authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. + * + * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* Licensed to PSF under a Contributor Agreement. */ +/* See http://www.python.org/2.4/license for licensing details. */ + +/* TODO: handle unicode command lines? */ +/* TODO: handle unicode environment? */ + +#include "Python.h" + +#define WINDOWS_LEAN_AND_MEAN +#include "windows.h" + +/* -------------------------------------------------------------------- */ +/* handle wrapper. note that this library uses integers when passing + handles to a function, and handle wrappers when returning handles. + the wrapper is used to provide Detach and Close methods */ + +typedef struct { + PyObject_HEAD + HANDLE handle; +} sp_handle_object; + +staticforward PyTypeObject sp_handle_type; + +static PyObject* +sp_handle_new(HANDLE handle) +{ + sp_handle_object* self; + + self = PyObject_NEW(sp_handle_object, &sp_handle_type); + if (self == NULL) + return NULL; + + self->handle = handle; + + return (PyObject*) self; +} + +#if defined(MS_WIN32) && !defined(MS_WIN64) +#define HANDLE_TO_PYNUM(handle) PyInt_FromLong((long) handle) +#define PY_HANDLE_PARAM "l" +#else +#define HANDLE_TO_PYNUM(handle) PyLong_FromLongLong((long long) handle) +#define PY_HANDLE_PARAM "L" +#endif + +static PyObject* +sp_handle_detach(sp_handle_object* self, PyObject* args) +{ + HANDLE handle; + + if (! PyArg_ParseTuple(args, ":Detach")) + return NULL; + + handle = self->handle; + + self->handle = INVALID_HANDLE_VALUE; + + /* note: return the current handle, as an integer */ + return HANDLE_TO_PYNUM(handle); +} + +static PyObject* +sp_handle_close(sp_handle_object* self, PyObject* args) +{ + if (! PyArg_ParseTuple(args, ":Close")) + return NULL; + + if (self->handle != INVALID_HANDLE_VALUE) { + CloseHandle(self->handle); + self->handle = INVALID_HANDLE_VALUE; + } + Py_INCREF(Py_None); + return Py_None; +} + +static void +sp_handle_dealloc(sp_handle_object* self) +{ + if (self->handle != INVALID_HANDLE_VALUE) + CloseHandle(self->handle); + PyObject_FREE(self); +} + +static PyMethodDef sp_handle_methods[] = { + {"Detach", (PyCFunction) sp_handle_detach, METH_VARARGS}, + {"Close", (PyCFunction) sp_handle_close, METH_VARARGS}, + {NULL, NULL} +}; + +static PyObject* +sp_handle_getattr(sp_handle_object* self, char* name) +{ + return Py_FindMethod(sp_handle_methods, (PyObject*) self, name); +} + +static PyObject* +sp_handle_as_int(sp_handle_object* self) +{ + return HANDLE_TO_PYNUM(self->handle); +} + +static PyNumberMethods sp_handle_as_number; + +statichere PyTypeObject sp_handle_type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_subprocess_handle", sizeof(sp_handle_object), 0, + (destructor) sp_handle_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc) sp_handle_getattr,/*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + &sp_handle_as_number, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0 /*tp_hash*/ +}; + +/* -------------------------------------------------------------------- */ +/* windows API functions */ + +PyDoc_STRVAR(GetStdHandle_doc, +"GetStdHandle(handle) -> integer\n\ +\n\ +Return a handle to the specified standard device\n\ +(STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE).\n\ +The integer associated with the handle object is returned."); + +static PyObject * +sp_GetStdHandle(PyObject* self, PyObject* args) +{ + HANDLE handle; + int std_handle; + + if (! PyArg_ParseTuple(args, "i:GetStdHandle", &std_handle)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + handle = GetStdHandle((DWORD) std_handle); + Py_END_ALLOW_THREADS + + if (handle == INVALID_HANDLE_VALUE) + return PyErr_SetFromWindowsErr(GetLastError()); + + if (! handle) { + Py_INCREF(Py_None); + return Py_None; + } + + /* note: returns integer, not handle object */ + return HANDLE_TO_PYNUM(handle); +} + +PyDoc_STRVAR(GetCurrentProcess_doc, +"GetCurrentProcess() -> handle\n\ +\n\ +Return a handle object for the current process."); + +static PyObject * +sp_GetCurrentProcess(PyObject* self, PyObject* args) +{ + if (! PyArg_ParseTuple(args, ":GetCurrentProcess")) + return NULL; + + return sp_handle_new(GetCurrentProcess()); +} + +PyDoc_STRVAR(DuplicateHandle_doc, +"DuplicateHandle(source_proc_handle, source_handle,\n\ + target_proc_handle, target_handle, access,\n\ + inherit[, options]) -> handle\n\ +\n\ +Return a duplicate handle object.\n\ +\n\ +The duplicate handle refers to the same object as the original\n\ +handle. Therefore, any changes to the object are reflected\n\ +through both handles."); + +static PyObject * +sp_DuplicateHandle(PyObject* self, PyObject* args) +{ + HANDLE target_handle; + BOOL result; + + HANDLE source_process_handle; + HANDLE source_handle; + HANDLE target_process_handle; + int desired_access; + int inherit_handle; + int options = 0; + + if (! PyArg_ParseTuple(args, + PY_HANDLE_PARAM PY_HANDLE_PARAM PY_HANDLE_PARAM + "ii|i:DuplicateHandle", + &source_process_handle, + &source_handle, + &target_process_handle, + &desired_access, + &inherit_handle, + &options)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + result = DuplicateHandle( + source_process_handle, + source_handle, + target_process_handle, + &target_handle, + desired_access, + inherit_handle, + options + ); + Py_END_ALLOW_THREADS + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return sp_handle_new(target_handle); +} + +PyDoc_STRVAR(CreatePipe_doc, +"CreatePipe(pipe_attrs, size) -> (read_handle, write_handle)\n\ +\n\ +Create an anonymous pipe, and return handles to the read and\n\ +write ends of the pipe.\n\ +\n\ +pipe_attrs is ignored internally and can be None."); + +static PyObject * +sp_CreatePipe(PyObject* self, PyObject* args) +{ + HANDLE read_pipe; + HANDLE write_pipe; + BOOL result; + + PyObject* pipe_attributes; /* ignored */ + int size; + + if (! PyArg_ParseTuple(args, "Oi:CreatePipe", &pipe_attributes, &size)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + result = CreatePipe(&read_pipe, &write_pipe, NULL, size); + Py_END_ALLOW_THREADS + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return Py_BuildValue( + "NN", sp_handle_new(read_pipe), sp_handle_new(write_pipe)); +} + +/* helpers for createprocess */ + +static int +getint(PyObject* obj, char* name) +{ + PyObject* value; + int ret; + + value = PyObject_GetAttrString(obj, name); + if (! value) { + PyErr_Clear(); /* FIXME: propagate error? */ + return 0; + } + ret = (int) PyInt_AsLong(value); + Py_DECREF(value); + return ret; +} + +static HANDLE +gethandle(PyObject* obj, char* name) +{ + sp_handle_object* value; + HANDLE ret; + + value = (sp_handle_object*) PyObject_GetAttrString(obj, name); + if (! value) { + PyErr_Clear(); /* FIXME: propagate error? */ + return NULL; + } + if (value->ob_type != &sp_handle_type) + ret = NULL; + else + ret = value->handle; + Py_DECREF(value); + return ret; +} + +// DEVTOOLS-1825 +static char* ResizeEnv(char* envEnd, PyObject** env, int addSize) { + int newSize = (envEnd - PyString_AS_STRING(*env)) + addSize + 2; + if (newSize > PyString_GET_SIZE(*env)) { + int offset = envEnd - PyString_AS_STRING(*env); + _PyString_Resize(env, newSize + 1024); + /* In Python 2.7.11: + if (_PyString_Resize(&out, totalsize + 1024)) + goto exit; + */ + envEnd = PyString_AS_STRING(*env) + offset; + } + return envEnd; +} + +// DEVTOOLS-1825 +static char* AddEnvKeyValue(char* envEnd, PyObject** env, const char* key, int keySize, const char* value, int valueSize) { + envEnd = ResizeEnv(envEnd, env, keySize + valueSize + 1); + memcpy(envEnd, key, keySize); + envEnd += keySize; + *envEnd++ = '='; + memcpy(envEnd, value, valueSize); + envEnd += valueSize; + *envEnd++ = '\0'; + return envEnd; +} + +// DEVTOOLS-1825 +static char* AddEnvVar(char* envEnd, PyObject** env, const char* var, int size) { + envEnd = ResizeEnv(envEnd, env, size); + memcpy(envEnd, var, size); + envEnd += size; + *envEnd++ = '\0'; + return envEnd; +} + +// DEVTOOLS-1825: env data types +enum EEnvDataType { + EDT_REGULAR = 0x1, // regular env vars + EDT_SPECIAL = 0x2, // special env vars that start with '=' +}; + +// DEVTOOLS-1825: construct curdir env variable +// Returns TRUE if variable is based on real current drive, synthetic empty =C: variable is used instead +// Buffer for variable must have MAX_PATH + 4 size +// TODO: when CRT is patched this code should be removed +static int ConstructCurDirVar(char* var) { + memcpy(var, "=C:=", 4); + DWORD valueSize = GetCurrentDirectoryA(MAX_PATH, var + 4); + if (!valueSize || (valueSize > MAX_PATH - 1)) { +#ifdef _DEBUG + fprintf(stderr, "[devtools] Warn: can't get current directory to construct curdir env var\n"); +#endif + return 4; + } + if (!IsCharAlpha(var[4])) { +#ifdef _DEBUG + fprintf(stderr, "[devtools] Warn: can't determine current drive to construct curdir env var\n"); +#endif + return 4; + } + var[1] = var[4]; + return valueSize + 4; +} + +// DEVTOOLS-1825: add to env parent environment data +// dataType: type of data to copy, special +// constructCurDirVar: if enabled code tries to reconstruct curdir env var for current drive (=X:=PATH) if it's not in the parent env +// TODO: when CRT is patched regular data copying and curdir vat construction should be removed +static char* AddParentEnvData(char* envEnd, PyObject** env, enum EEnvDataType dataType, BOOL constructCurDirVar) { + const char* parentEnv = NULL; + const char* var = NULL; + int size = 0; + char curDirVar[MAX_PATH + 4]; + int curDirVarSize = 0; + BOOL curDirVarAdded = FALSE; + if (constructCurDirVar) { + curDirVarSize = ConstructCurDirVar(curDirVar); + } + parentEnv = GetEnvironmentStringsA(); + if (dataType & EDT_SPECIAL) { + for (var = parentEnv; *var; var += size + 1) { + size = strlen(var); + if (var[0] != '=') { + continue; + } + if (constructCurDirVar && !curDirVarAdded && !strncmp(var, curDirVar, 4)) { + curDirVarAdded = TRUE; + } + envEnd = AddEnvVar(envEnd, env, var, size); + } + } + if (constructCurDirVar && !curDirVarAdded) { +#ifdef _DEBUG + curDirVar[curDirVarSize] = '\0'; + fprintf(stderr, "[devtools] No curdir env data found, constructing on the fly: %s\n", curDirVar); +#endif + envEnd = AddEnvVar(envEnd, env, curDirVar, curDirVarSize); + } + if (dataType & EDT_REGULAR) { + for (var = parentEnv; *var; var += size + 1) { + size = strlen(var); + if (var[0] == '=') { + continue; + } + envEnd = AddEnvVar(envEnd, env, var, size); + } + } + FreeEnvironmentStringsA(parentEnv); + return envEnd; +} + +static PyObject* +getenvironment(PyObject* environment) +{ + int i, envsize; + PyObject* out = NULL; + PyObject* keys; + PyObject* values; + char* p; + + /* convert environment dictionary to windows environment string */ + if (! PyMapping_Check(environment)) { + PyErr_SetString( + PyExc_TypeError, "environment must be dictionary or None"); + return NULL; + } + + envsize = PyMapping_Length(environment); + + keys = PyMapping_Keys(environment); + if (!keys) { + return NULL; + } + values = PyMapping_Values(environment); + if (!values) { + goto error; + } + + out = PyString_FromStringAndSize(NULL, 2048); + if (! out) + goto error; + + p = PyString_AS_STRING(out); + + // DEVTOOLS-1825: copy special env data: it contains curdir per drive info (=X:=PATH) + // TODO: when CRT is patched disable constructCurDirVar + p = AddParentEnvData(p, &out, EDT_SPECIAL, TRUE); + + for (i = 0; i < envsize; i++) { + size_t ksize, vsize, totalsize; + PyObject* key = PyList_GET_ITEM(keys, i); + PyObject* value = PyList_GET_ITEM(values, i); + + if (! PyString_Check(key) || ! PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "environment can only contain strings"); + goto error; + } + ksize = PyString_GET_SIZE(key); + vsize = PyString_GET_SIZE(value); + if (strlen(PyString_AS_STRING(key)) != ksize || + strlen(PyString_AS_STRING(value)) != vsize) + { + PyErr_SetString(PyExc_TypeError, "embedded null character"); + goto error; + } + /* Search from index 1 because on Windows starting '=' is allowed for + defining hidden environment variables. */ + if (ksize == 0 || strchr(PyString_AS_STRING(key) + 1, '=') != NULL) { + PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); + goto error; + } + totalsize = (p - PyString_AS_STRING(out)) + ksize + 1 + + vsize + 1 + 1; + if (totalsize > (size_t)PyString_GET_SIZE(out)) { + size_t offset = p - PyString_AS_STRING(out); + if (_PyString_Resize(&out, totalsize + 1024)) + goto exit; + p = PyString_AS_STRING(out) + offset; + } + memcpy(p, PyString_AS_STRING(key), ksize); + p += ksize; + *p++ = '='; + memcpy(p, PyString_AS_STRING(value), vsize); + p += vsize; + *p++ = '\0'; + } + + /* add trailing null byte */ + *p++ = '\0'; + _PyString_Resize(&out, p - PyString_AS_STRING(out)); + + /* PyObject_Print(out, stdout, 0); */ +exit: + Py_XDECREF(keys); + Py_XDECREF(values); + + return out; + + error: + Py_XDECREF(out); + Py_XDECREF(keys); + Py_XDECREF(values); + return NULL; +} + +static PyObject* ReconstructEnvironment() { + PyObject* env = PyString_FromStringAndSize(NULL, 2048); + if (!env) { + return NULL; + } + char* p = PyString_AS_STRING(env); + p = AddParentEnvData(p, &env, EDT_REGULAR | EDT_SPECIAL, TRUE); + *p++ = '\0'; + _PyString_Resize(&env, p - PyString_AS_STRING(env)); + return env; +} + +PyDoc_STRVAR(CreateProcess_doc, +"CreateProcess(app_name, cmd_line, proc_attrs, thread_attrs,\n\ + inherit, flags, env_mapping, curdir,\n\ + startup_info) -> (proc_handle, thread_handle,\n\ + pid, tid)\n\ +\n\ +Create a new process and its primary thread. The return\n\ +value is a tuple of the process handle, thread handle,\n\ +process ID, and thread ID.\n\ +\n\ +proc_attrs and thread_attrs are ignored internally and can be None."); + +static PyObject * +sp_CreateProcess(PyObject* self, PyObject* args) +{ + BOOL result; + PROCESS_INFORMATION pi; + STARTUPINFO si; + PyObject* environment; + + char* application_name; + char* command_line; + PyObject* process_attributes; /* ignored */ + PyObject* thread_attributes; /* ignored */ + int inherit_handles; + int creation_flags; + PyObject* env_mapping; + char* current_directory; + PyObject* startup_info; + + if (! PyArg_ParseTuple(args, "zzOOiiOzO:CreateProcess", + &application_name, + &command_line, + &process_attributes, + &thread_attributes, + &inherit_handles, + &creation_flags, + &env_mapping, + ¤t_directory, + &startup_info)) + return NULL; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + + /* note: we only support a small subset of all SI attributes */ + si.dwFlags = getint(startup_info, "dwFlags"); + si.wShowWindow = getint(startup_info, "wShowWindow"); + si.hStdInput = gethandle(startup_info, "hStdInput"); + si.hStdOutput = gethandle(startup_info, "hStdOutput"); + si.hStdError = gethandle(startup_info, "hStdError"); + + if (PyErr_Occurred()) + return NULL; + + if (env_mapping == Py_None) + // DEVTOOLS-1825 + // TODO: restore original code when CRT is patched + //environment = NULL; + environment = ReconstructEnvironment(); + else { + environment = getenvironment(env_mapping); + if (! environment) + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + result = CreateProcess(application_name, + command_line, + NULL, + NULL, + inherit_handles, + creation_flags, + environment ? PyString_AS_STRING(environment) : NULL, + current_directory, + &si, + &pi); + Py_END_ALLOW_THREADS + + Py_XDECREF(environment); + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return Py_BuildValue("NNii", + sp_handle_new(pi.hProcess), + sp_handle_new(pi.hThread), + pi.dwProcessId, + pi.dwThreadId); +} + +PyDoc_STRVAR(TerminateProcess_doc, +"TerminateProcess(handle, exit_code) -> None\n\ +\n\ +Terminate the specified process and all of its threads."); + +static PyObject * +sp_TerminateProcess(PyObject* self, PyObject* args) +{ + BOOL result; + + HANDLE process; + int exit_code; + if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:TerminateProcess", + &process, &exit_code)) + return NULL; + + result = TerminateProcess(process, exit_code); + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(GetExitCodeProcess_doc, +"GetExitCodeProcess(handle) -> Exit code\n\ +\n\ +Return the termination status of the specified process."); + +static PyObject * +sp_GetExitCodeProcess(PyObject* self, PyObject* args) +{ + DWORD exit_code; + BOOL result; + + HANDLE process; + if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM ":GetExitCodeProcess", &process)) + return NULL; + + result = GetExitCodeProcess(process, &exit_code); + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return PyInt_FromLong(exit_code); +} + +PyDoc_STRVAR(WaitForSingleObject_doc, +"WaitForSingleObject(handle, timeout) -> result\n\ +\n\ +Wait until the specified object is in the signaled state or\n\ +the time-out interval elapses. The timeout value is specified\n\ +in milliseconds."); + +static PyObject * +sp_WaitForSingleObject(PyObject* self, PyObject* args) +{ + DWORD result; + + HANDLE handle; + int milliseconds; + if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:WaitForSingleObject", + &handle, + &milliseconds)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + result = WaitForSingleObject(handle, (DWORD) milliseconds); + Py_END_ALLOW_THREADS + + if (result == WAIT_FAILED) + return PyErr_SetFromWindowsErr(GetLastError()); + + return PyInt_FromLong((int) result); +} + +PyDoc_STRVAR(GetVersion_doc, +"GetVersion() -> version\n\ +\n\ +Return the version number of the current operating system."); + +static PyObject * +sp_GetVersion(PyObject* self, PyObject* args) +{ + if (! PyArg_ParseTuple(args, ":GetVersion")) + return NULL; + + return PyInt_FromLong((int) GetVersion()); +} + +PyDoc_STRVAR(GetModuleFileName_doc, +"GetModuleFileName(module) -> path\n\ +\n\ +Return the fully-qualified path for the file that contains\n\ +the specified module. The module must have been loaded by the\n\ +current process.\n\ +\n\ +The module parameter should be a handle to the loaded module\n\ +whose path is being requested. If this parameter is 0, \n\ +GetModuleFileName retrieves the path of the executable file\n\ +of the current process."); + +static PyObject * +sp_GetModuleFileName(PyObject* self, PyObject* args) +{ + BOOL result; + HMODULE module; + TCHAR filename[MAX_PATH]; + + if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM ":GetModuleFileName", + &module)) + return NULL; + + result = GetModuleFileName(module, filename, MAX_PATH); + filename[MAX_PATH-1] = '\0'; + + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return PyString_FromString(filename); +} + +static PyMethodDef sp_functions[] = { + {"GetStdHandle", sp_GetStdHandle, METH_VARARGS, GetStdHandle_doc}, + {"GetCurrentProcess", sp_GetCurrentProcess, METH_VARARGS, + GetCurrentProcess_doc}, + {"DuplicateHandle", sp_DuplicateHandle, METH_VARARGS, + DuplicateHandle_doc}, + {"CreatePipe", sp_CreatePipe, METH_VARARGS, CreatePipe_doc}, + {"CreateProcess", sp_CreateProcess, METH_VARARGS, CreateProcess_doc}, + {"TerminateProcess", sp_TerminateProcess, METH_VARARGS, + TerminateProcess_doc}, + {"GetExitCodeProcess", sp_GetExitCodeProcess, METH_VARARGS, + GetExitCodeProcess_doc}, + {"WaitForSingleObject", sp_WaitForSingleObject, METH_VARARGS, + WaitForSingleObject_doc}, + {"GetVersion", sp_GetVersion, METH_VARARGS, GetVersion_doc}, + {"GetModuleFileName", sp_GetModuleFileName, METH_VARARGS, + GetModuleFileName_doc}, + {NULL, NULL} +}; + +/* -------------------------------------------------------------------- */ + +static void +defint(PyObject* d, const char* name, int value) +{ + PyObject* v = PyInt_FromLong((long) value); + if (v) { + PyDict_SetItemString(d, (char*) name, v); + Py_DECREF(v); + } +} + +#if PY_VERSION_HEX >= 0x02030000 +PyMODINIT_FUNC +#else +DL_EXPORT(void) +#endif +init_subprocess() +{ + PyObject *d; + PyObject *m; + + /* patch up object descriptors */ + sp_handle_type.ob_type = &PyType_Type; + sp_handle_as_number.nb_int = (unaryfunc) sp_handle_as_int; + + m = Py_InitModule("_subprocess", sp_functions); + if (m == NULL) + return; + d = PyModule_GetDict(m); + + /* constants */ + defint(d, "STD_INPUT_HANDLE", STD_INPUT_HANDLE); + defint(d, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE); + defint(d, "STD_ERROR_HANDLE", STD_ERROR_HANDLE); + defint(d, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS); + defint(d, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES); + defint(d, "STARTF_USESHOWWINDOW", STARTF_USESHOWWINDOW); + defint(d, "SW_HIDE", SW_HIDE); + defint(d, "INFINITE", INFINITE); + defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0); + defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE); + defint(d, "CREATE_NEW_PROCESS_GROUP", CREATE_NEW_PROCESS_GROUP); + defint(d, "STILL_ACTIVE", STILL_ACTIVE); +} diff --git a/contrib/tools/python/src/PC/_winreg.c b/contrib/tools/python/src/PC/_winreg.c new file mode 100644 index 00000000000..720f7988d32 --- /dev/null +++ b/contrib/tools/python/src/PC/_winreg.c @@ -0,0 +1,1872 @@ +/* + _winreg.c + + Windows Registry access module for Python. + + * Simple registry access written by Mark Hammond in win32api + module circa 1995. + * Bill Tutt expanded the support significantly not long after. + * Numerous other people have submitted patches since then. + * Ripped from win32api module 03-Feb-2000 by Mark Hammond, and + basic Unicode support added. + +*/ + +#include "Python.h" +#include "structmember.h" +#include "malloc.h" /* for alloca */ +#include "windows.h" + +static BOOL PyHKEY_AsHKEY(PyObject *ob, HKEY *pRes, BOOL bNoneOK); +static PyObject *PyHKEY_FromHKEY(HKEY h); +static BOOL PyHKEY_Close(PyObject *obHandle); + +static char errNotAHandle[] = "Object is not a handle"; + +/* The win32api module reports the function name that failed, + but this concept is not in the Python core. + Hopefully it will one day, and in the meantime I don't + want to lose this info... +*/ +#define PyErr_SetFromWindowsErrWithFunction(rc, fnname) \ + PyErr_SetFromWindowsErr(rc) + +/* Forward declares */ + +/* Doc strings */ +PyDoc_STRVAR(module_doc, +"This module provides access to the Windows registry API.\n" +"\n" +"Functions:\n" +"\n" +"CloseKey() - Closes a registry key.\n" +"ConnectRegistry() - Establishes a connection to a predefined registry handle\n" +" on another computer.\n" +"CreateKey() - Creates the specified key, or opens it if it already exists.\n" +"DeleteKey() - Deletes the specified key.\n" +"DeleteValue() - Removes a named value from the specified registry key.\n" +"EnumKey() - Enumerates subkeys of the specified open registry key.\n" +"EnumValue() - Enumerates values of the specified open registry key.\n" +"ExpandEnvironmentStrings() - Expand the env strings in a REG_EXPAND_SZ string.\n" +"FlushKey() - Writes all the attributes of the specified key to the registry.\n" +"LoadKey() - Creates a subkey under HKEY_USER or HKEY_LOCAL_MACHINE and stores\n" +" registration information from a specified file into that subkey.\n" +"OpenKey() - Alias for <om win32api.RegOpenKeyEx>\n" +"OpenKeyEx() - Opens the specified key.\n" +"QueryValue() - Retrieves the value associated with the unnamed value for a\n" +" specified key in the registry.\n" +"QueryValueEx() - Retrieves the type and data for a specified value name\n" +" associated with an open registry key.\n" +"QueryInfoKey() - Returns information about the specified key.\n" +"SaveKey() - Saves the specified key, and all its subkeys a file.\n" +"SetValue() - Associates a value with a specified key.\n" +"SetValueEx() - Stores data in the value field of an open registry key.\n" +"\n" +"Special objects:\n" +"\n" +"HKEYType -- type object for HKEY objects\n" +"error -- exception raised for Win32 errors\n" +"\n" +"Integer constants:\n" +"Many constants are defined - see the documentation for each function\n" +"to see what constants are used, and where."); + + +PyDoc_STRVAR(CloseKey_doc, +"CloseKey(hkey) - Closes a previously opened registry key.\n" +"\n" +"The hkey argument specifies a previously opened key.\n" +"\n" +"Note that if the key is not closed using this method, it will be\n" +"closed when the hkey object is destroyed by Python."); + +PyDoc_STRVAR(ConnectRegistry_doc, +"key = ConnectRegistry(computer_name, key) - " +"Establishes a connection to a predefined registry handle on another computer.\n" +"\n" +"computer_name is the name of the remote computer, of the form \\\\computername.\n" +" If None, the local computer is used.\n" +"key is the predefined handle to connect to.\n" +"\n" +"The return value is the handle of the opened key.\n" +"If the function fails, a WindowsError exception is raised."); + +PyDoc_STRVAR(CreateKey_doc, +"key = CreateKey(key, sub_key) - Creates or opens the specified key.\n" +"\n" +"key is an already open key, or one of the predefined HKEY_* constants\n" +"sub_key is a string that names the key this method opens or creates.\n" +" If key is one of the predefined keys, sub_key may be None. In that case,\n" +" the handle returned is the same key handle passed in to the function.\n" +"\n" +"If the key already exists, this function opens the existing key\n" +"\n" +"The return value is the handle of the opened key.\n" +"If the function fails, an exception is raised."); + +PyDoc_STRVAR(CreateKeyEx_doc, +"key = CreateKeyEx(key, sub_key, res, sam) - Creates or opens the specified key.\n" +"\n" +"key is an already open key, or one of the predefined HKEY_* constants\n" +"sub_key is a string that names the key this method opens or creates.\n" +"res is a reserved integer, and must be zero. Default is zero.\n" +"sam is an integer that specifies an access mask that describes the desired\n" +" If key is one of the predefined keys, sub_key may be None. In that case,\n" +" the handle returned is the same key handle passed in to the function.\n" +"\n" +"If the key already exists, this function opens the existing key\n" +"\n" +"The return value is the handle of the opened key.\n" +"If the function fails, an exception is raised."); + +PyDoc_STRVAR(DeleteKey_doc, +"DeleteKey(key, sub_key) - Deletes the specified key.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"sub_key is a string that must be a subkey of the key identified by the key parameter.\n" +" This value must not be None, and the key may not have subkeys.\n" +"\n" +"This method can not delete keys with subkeys.\n" +"\n" +"If the method succeeds, the entire key, including all of its values,\n" +"is removed. If the method fails, a WindowsError exception is raised."); + +PyDoc_STRVAR(DeleteKeyEx_doc, +"DeleteKeyEx(key, sub_key, sam, res) - Deletes the specified key.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"sub_key is a string that must be a subkey of the key identified by the key parameter.\n" +"res is a reserved integer, and must be zero. Default is zero.\n" +"sam is an integer that specifies an access mask that describes the desired\n" +" This value must not be None, and the key may not have subkeys.\n" +"\n" +"This method can not delete keys with subkeys.\n" +"\n" +"If the method succeeds, the entire key, including all of its values,\n" +"is removed. If the method fails, a WindowsError exception is raised.\n" +"On unsupported Windows versions, NotImplementedError is raised."); + +PyDoc_STRVAR(DeleteValue_doc, +"DeleteValue(key, value) - Removes a named value from a registry key.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"value is a string that identifies the value to remove."); + +PyDoc_STRVAR(EnumKey_doc, +"string = EnumKey(key, index) - Enumerates subkeys of an open registry key.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"index is an integer that identifies the index of the key to retrieve.\n" +"\n" +"The function retrieves the name of one subkey each time it is called.\n" +"It is typically called repeatedly until a WindowsError exception is\n" +"raised, indicating no more values are available."); + +PyDoc_STRVAR(EnumValue_doc, +"tuple = EnumValue(key, index) - Enumerates values of an open registry key.\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"index is an integer that identifies the index of the value to retrieve.\n" +"\n" +"The function retrieves the name of one subkey each time it is called.\n" +"It is typically called repeatedly, until a WindowsError exception\n" +"is raised, indicating no more values.\n" +"\n" +"The result is a tuple of 3 items:\n" +"value_name is a string that identifies the value.\n" +"value_data is an object that holds the value data, and whose type depends\n" +" on the underlying registry type.\n" +"data_type is an integer that identifies the type of the value data."); + +PyDoc_STRVAR(ExpandEnvironmentStrings_doc, +"string = ExpandEnvironmentStrings(string) - Expand environment vars.\n"); + +PyDoc_STRVAR(FlushKey_doc, +"FlushKey(key) - Writes all the attributes of a key to the registry.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"\n" +"It is not necessary to call RegFlushKey to change a key.\n" +"Registry changes are flushed to disk by the registry using its lazy flusher.\n" +"Registry changes are also flushed to disk at system shutdown.\n" +"Unlike CloseKey(), the FlushKey() method returns only when all the data has\n" +"been written to the registry.\n" +"An application should only call FlushKey() if it requires absolute certainty that registry changes are on disk.\n" +"If you don't know whether a FlushKey() call is required, it probably isn't."); + +PyDoc_STRVAR(LoadKey_doc, +"LoadKey(key, sub_key, file_name) - Creates a subkey under the specified key\n" +"and stores registration information from a specified file into that subkey.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"sub_key is a string that identifies the sub_key to load\n" +"file_name is the name of the file to load registry data from.\n" +" This file must have been created with the SaveKey() function.\n" +" Under the file allocation table (FAT) file system, the filename may not\n" +"have an extension.\n" +"\n" +"A call to LoadKey() fails if the calling process does not have the\n" +"SE_RESTORE_PRIVILEGE privilege.\n" +"\n" +"If key is a handle returned by ConnectRegistry(), then the path specified\n" +"in fileName is relative to the remote computer.\n" +"\n" +"The docs imply key must be in the HKEY_USER or HKEY_LOCAL_MACHINE tree"); + +PyDoc_STRVAR(OpenKey_doc, +"key = OpenKey(key, sub_key, res = 0, sam = KEY_READ) - Opens the specified key.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"sub_key is a string that identifies the sub_key to open\n" +"res is a reserved integer, and must be zero. Default is zero.\n" +"sam is an integer that specifies an access mask that describes the desired\n" +" security access for the key. Default is KEY_READ\n" +"\n" +"The result is a new handle to the specified key\n" +"If the function fails, a WindowsError exception is raised."); + +PyDoc_STRVAR(OpenKeyEx_doc, "See OpenKey()"); + +PyDoc_STRVAR(QueryInfoKey_doc, +"tuple = QueryInfoKey(key) - Returns information about a key.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"\n" +"The result is a tuple of 3 items:" +"An integer that identifies the number of sub keys this key has.\n" +"An integer that identifies the number of values this key has.\n" +"A long integer that identifies when the key was last modified (if available)\n" +" as 100's of nanoseconds since Jan 1, 1600."); + +PyDoc_STRVAR(QueryValue_doc, +"string = QueryValue(key, sub_key) - retrieves the unnamed value for a key.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"sub_key is a string that holds the name of the subkey with which the value\n" +" is associated. If this parameter is None or empty, the function retrieves\n" +" the value set by the SetValue() method for the key identified by key." +"\n" +"Values in the registry have name, type, and data components. This method\n" +"retrieves the data for a key's first value that has a NULL name.\n" +"But the underlying API call doesn't return the type, Lame Lame Lame, DONT USE THIS!!!"); + +PyDoc_STRVAR(QueryValueEx_doc, +"value,type_id = QueryValueEx(key, value_name) - Retrieves the type and data for a specified value name associated with an open registry key.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"value_name is a string indicating the value to query"); + +PyDoc_STRVAR(SaveKey_doc, +"SaveKey(key, file_name) - Saves the specified key, and all its subkeys to the specified file.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"file_name is the name of the file to save registry data to.\n" +" This file cannot already exist. If this filename includes an extension,\n" +" it cannot be used on file allocation table (FAT) file systems by the\n" +" LoadKey(), ReplaceKey() or RestoreKey() methods.\n" +"\n" +"If key represents a key on a remote computer, the path described by\n" +"file_name is relative to the remote computer.\n" +"The caller of this method must possess the SeBackupPrivilege security privilege.\n" +"This function passes NULL for security_attributes to the API."); + +PyDoc_STRVAR(SetValue_doc, +"SetValue(key, sub_key, type, value) - Associates a value with a specified key.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"sub_key is a string that names the subkey with which the value is associated.\n" +"type is an integer that specifies the type of the data. Currently this\n" +" must be REG_SZ, meaning only strings are supported.\n" +"value is a string that specifies the new value.\n" +"\n" +"If the key specified by the sub_key parameter does not exist, the SetValue\n" +"function creates it.\n" +"\n" +"Value lengths are limited by available memory. Long values (more than\n" +"2048 bytes) should be stored as files with the filenames stored in \n" +"the configuration registry. This helps the registry perform efficiently.\n" +"\n" +"The key identified by the key parameter must have been opened with\n" +"KEY_SET_VALUE access."); + +PyDoc_STRVAR(SetValueEx_doc, +"SetValueEx(key, value_name, reserved, type, value) - Stores data in the value field of an open registry key.\n" +"\n" +"key is an already open key, or any one of the predefined HKEY_* constants.\n" +"value_name is a string containing the name of the value to set, or None\n" +"type is an integer that specifies the type of the data. This should be one of:\n" +" REG_BINARY -- Binary data in any form.\n" +" REG_DWORD -- A 32-bit number.\n" +" REG_DWORD_LITTLE_ENDIAN -- A 32-bit number in little-endian format.\n" +" REG_DWORD_BIG_ENDIAN -- A 32-bit number in big-endian format.\n" +" REG_EXPAND_SZ -- A null-terminated string that contains unexpanded references\n" +" to environment variables (for example, %PATH%).\n" +" REG_LINK -- A Unicode symbolic link.\n" +" REG_MULTI_SZ -- A sequence of null-terminated strings, terminated by\n" +" two null characters. Note that Python handles this\n" +" termination automatically.\n" +" REG_NONE -- No defined value type.\n" +" REG_RESOURCE_LIST -- A device-driver resource list.\n" +" REG_SZ -- A null-terminated string.\n" +"reserved can be anything - zero is always passed to the API.\n" +"value is a string that specifies the new value.\n" +"\n" +"This method can also set additional value and type information for the\n" +"specified key. The key identified by the key parameter must have been\n" +"opened with KEY_SET_VALUE access.\n" +"\n" +"To open the key, use the CreateKeyEx() or OpenKeyEx() methods.\n" +"\n" +"Value lengths are limited by available memory. Long values (more than\n" +"2048 bytes) should be stored as files with the filenames stored in \n" +"the configuration registry. This helps the registry perform efficiently."); + +PyDoc_STRVAR(DisableReflectionKey_doc, +"Disables registry reflection for 32-bit processes running on a 64-bit\n" +"Operating System. Will generally raise NotImplemented if executed on\n" +"a 32-bit Operating System.\n" +"If the key is not on the reflection list, the function succeeds but has no effect.\n" +"Disabling reflection for a key does not affect reflection of any subkeys."); + +PyDoc_STRVAR(EnableReflectionKey_doc, +"Restores registry reflection for the specified disabled key.\n" +"Will generally raise NotImplemented if executed on a 32-bit Operating System.\n" +"Restoring reflection for a key does not affect reflection of any subkeys."); + +PyDoc_STRVAR(QueryReflectionKey_doc, +"bool = QueryReflectionKey(hkey) - Determines the reflection state for the specified key.\n" +"Will generally raise NotImplemented if executed on a 32-bit Operating System.\n"); + +/* PyHKEY docstrings */ +PyDoc_STRVAR(PyHKEY_doc, +"PyHKEY Object - A Python object, representing a win32 registry key.\n" +"\n" +"This object wraps a Windows HKEY object, automatically closing it when\n" +"the object is destroyed. To guarantee cleanup, you can call either\n" +"the Close() method on the PyHKEY, or the CloseKey() method.\n" +"\n" +"All functions which accept a handle object also accept an integer - \n" +"however, use of the handle object is encouraged.\n" +"\n" +"Functions:\n" +"Close() - Closes the underlying handle.\n" +"Detach() - Returns the integer Win32 handle, detaching it from the object\n" +"\n" +"Properties:\n" +"handle - The integer Win32 handle.\n" +"\n" +"Operations:\n" +"__nonzero__ - Handles with an open object return true, otherwise false.\n" +"__int__ - Converting a handle to an integer returns the Win32 handle.\n" +"__cmp__ - Handle objects are compared using the handle value."); + + +PyDoc_STRVAR(PyHKEY_Close_doc, +"key.Close() - Closes the underlying Windows handle.\n" +"\n" +"If the handle is already closed, no error is raised."); + +PyDoc_STRVAR(PyHKEY_Detach_doc, +"int = key.Detach() - Detaches the Windows handle from the handle object.\n" +"\n" +"The result is the value of the handle before it is detached. If the\n" +"handle is already detached, this will return zero.\n" +"\n" +"After calling this function, the handle is effectively invalidated,\n" +"but the handle is not closed. You would call this function when you\n" +"need the underlying win32 handle to exist beyond the lifetime of the\n" +"handle object.\n" +"On 64 bit windows, the result of this function is a long integer"); + + +/************************************************************************ + + The PyHKEY object definition + +************************************************************************/ +typedef struct { + PyObject_VAR_HEAD + HKEY hkey; +} PyHKEYObject; + +#define PyHKEY_Check(op) ((op)->ob_type == &PyHKEY_Type) + +static char *failMsg = "bad operand type"; + +static PyObject * +PyHKEY_unaryFailureFunc(PyObject *ob) +{ + PyErr_SetString(PyExc_TypeError, failMsg); + return NULL; +} +static PyObject * +PyHKEY_binaryFailureFunc(PyObject *ob1, PyObject *ob2) +{ + PyErr_SetString(PyExc_TypeError, failMsg); + return NULL; +} +static PyObject * +PyHKEY_ternaryFailureFunc(PyObject *ob1, PyObject *ob2, PyObject *ob3) +{ + PyErr_SetString(PyExc_TypeError, failMsg); + return NULL; +} + +static void +PyHKEY_deallocFunc(PyObject *ob) +{ + /* Can not call PyHKEY_Close, as the ob->tp_type + has already been cleared, thus causing the type + check to fail! + */ + PyHKEYObject *obkey = (PyHKEYObject *)ob; + if (obkey->hkey) + RegCloseKey((HKEY)obkey->hkey); + PyObject_DEL(ob); +} + +static int +PyHKEY_nonzeroFunc(PyObject *ob) +{ + return ((PyHKEYObject *)ob)->hkey != 0; +} + +static PyObject * +PyHKEY_intFunc(PyObject *ob) +{ + PyHKEYObject *pyhkey = (PyHKEYObject *)ob; + return PyLong_FromVoidPtr(pyhkey->hkey); +} + +static int +PyHKEY_printFunc(PyObject *ob, FILE *fp, int flags) +{ + PyHKEYObject *pyhkey = (PyHKEYObject *)ob; + fprintf(fp, "<PyHKEY at %p (%p)>", + ob, pyhkey->hkey); + return 0; +} + +static PyObject * +PyHKEY_strFunc(PyObject *ob) +{ + PyHKEYObject *pyhkey = (PyHKEYObject *)ob; + return PyString_FromFormat("<PyHKEY:%p>", pyhkey->hkey); +} + +static int +PyHKEY_compareFunc(PyObject *ob1, PyObject *ob2) +{ + PyHKEYObject *pyhkey1 = (PyHKEYObject *)ob1; + PyHKEYObject *pyhkey2 = (PyHKEYObject *)ob2; + return pyhkey1 == pyhkey2 ? 0 : + (pyhkey1 < pyhkey2 ? -1 : 1); +} + +static long +PyHKEY_hashFunc(PyObject *ob) +{ + /* Just use the address. + XXX - should we use the handle value? + */ + return _Py_HashPointer(ob); +} + + +static PyNumberMethods PyHKEY_NumberMethods = +{ + PyHKEY_binaryFailureFunc, /* nb_add */ + PyHKEY_binaryFailureFunc, /* nb_subtract */ + PyHKEY_binaryFailureFunc, /* nb_multiply */ + PyHKEY_binaryFailureFunc, /* nb_divide */ + PyHKEY_binaryFailureFunc, /* nb_remainder */ + PyHKEY_binaryFailureFunc, /* nb_divmod */ + PyHKEY_ternaryFailureFunc, /* nb_power */ + PyHKEY_unaryFailureFunc, /* nb_negative */ + PyHKEY_unaryFailureFunc, /* nb_positive */ + PyHKEY_unaryFailureFunc, /* nb_absolute */ + PyHKEY_nonzeroFunc, /* nb_nonzero */ + PyHKEY_unaryFailureFunc, /* nb_invert */ + PyHKEY_binaryFailureFunc, /* nb_lshift */ + PyHKEY_binaryFailureFunc, /* nb_rshift */ + PyHKEY_binaryFailureFunc, /* nb_and */ + PyHKEY_binaryFailureFunc, /* nb_xor */ + PyHKEY_binaryFailureFunc, /* nb_or */ + 0, /* nb_coerce (allowed to be zero) */ + PyHKEY_intFunc, /* nb_int */ + PyHKEY_unaryFailureFunc, /* nb_long */ + PyHKEY_unaryFailureFunc, /* nb_float */ + PyHKEY_unaryFailureFunc, /* nb_oct */ + PyHKEY_unaryFailureFunc, /* nb_hex */ +}; + +static PyObject *PyHKEY_CloseMethod(PyObject *self, PyObject *args); +static PyObject *PyHKEY_DetachMethod(PyObject *self, PyObject *args); +static PyObject *PyHKEY_Enter(PyObject *self); +static PyObject *PyHKEY_Exit(PyObject *self, PyObject *args); + +static struct PyMethodDef PyHKEY_methods[] = { + {"Close", PyHKEY_CloseMethod, METH_VARARGS, PyHKEY_Close_doc}, + {"Detach", PyHKEY_DetachMethod, METH_VARARGS, PyHKEY_Detach_doc}, + {"__enter__", (PyCFunction)PyHKEY_Enter, METH_NOARGS, NULL}, + {"__exit__", PyHKEY_Exit, METH_VARARGS, NULL}, + {NULL} +}; + +static PyMemberDef PyHKEY_memberlist[] = { + {"handle", T_PYSSIZET, offsetof(PyHKEYObject, hkey), READONLY}, + {NULL} /* Sentinel */ +}; + +/* The type itself */ +PyTypeObject PyHKEY_Type = +{ + PyVarObject_HEAD_INIT(0, 0) /* fill in type at module init */ + "PyHKEY", + sizeof(PyHKEYObject), + 0, + PyHKEY_deallocFunc, /* tp_dealloc */ + PyHKEY_printFunc, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + PyHKEY_compareFunc, /* tp_compare */ + 0, /* tp_repr */ + &PyHKEY_NumberMethods, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + PyHKEY_hashFunc, /* tp_hash */ + 0, /* tp_call */ + PyHKEY_strFunc, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + PyHKEY_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PyHKEY_methods, /* tp_methods */ + PyHKEY_memberlist, /* tp_members */ +}; + +/************************************************************************ + + The PyHKEY object methods + +************************************************************************/ +static PyObject * +PyHKEY_CloseMethod(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":Close")) + return NULL; + if (!PyHKEY_Close(self)) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyHKEY_DetachMethod(PyObject *self, PyObject *args) +{ + void* ret; + PyHKEYObject *pThis = (PyHKEYObject *)self; + if (!PyArg_ParseTuple(args, ":Detach")) + return NULL; + ret = (void*)pThis->hkey; + pThis->hkey = 0; + return PyLong_FromVoidPtr(ret); +} + +static PyObject * +PyHKEY_Enter(PyObject *self) +{ + Py_XINCREF(self); + return self; +} + +static PyObject * +PyHKEY_Exit(PyObject *self, PyObject *args) +{ + if (!PyHKEY_Close(self)) + return NULL; + Py_RETURN_NONE; +} + + +/************************************************************************ + The public PyHKEY API (well, not public yet :-) +************************************************************************/ +PyObject * +PyHKEY_New(HKEY hInit) +{ + PyHKEYObject *key = PyObject_NEW(PyHKEYObject, &PyHKEY_Type); + if (key) + key->hkey = hInit; + return (PyObject *)key; +} + +BOOL +PyHKEY_Close(PyObject *ob_handle) +{ + LONG rc; + PyHKEYObject *key; + + if (!PyHKEY_Check(ob_handle)) { + PyErr_SetString(PyExc_TypeError, "bad operand type"); + return FALSE; + } + key = (PyHKEYObject *)ob_handle; + rc = key->hkey ? RegCloseKey((HKEY)key->hkey) : ERROR_SUCCESS; + key->hkey = 0; + if (rc != ERROR_SUCCESS) + PyErr_SetFromWindowsErrWithFunction(rc, "RegCloseKey"); + return rc == ERROR_SUCCESS; +} + +BOOL +PyHKEY_AsHKEY(PyObject *ob, HKEY *pHANDLE, BOOL bNoneOK) +{ + if (ob == Py_None) { + if (!bNoneOK) { + PyErr_SetString( + PyExc_TypeError, + "None is not a valid HKEY in this context"); + return FALSE; + } + *pHANDLE = (HKEY)0; + } + else if (PyHKEY_Check(ob)) { + PyHKEYObject *pH = (PyHKEYObject *)ob; + *pHANDLE = pH->hkey; + } + else if (_PyAnyInt_Check(ob)) { + /* We also support integers */ + PyErr_Clear(); + *pHANDLE = (HKEY)PyLong_AsVoidPtr(ob); + if (PyErr_Occurred()) + return FALSE; + } + else { + PyErr_SetString( + PyExc_TypeError, + "The object is not a PyHKEY object"); + return FALSE; + } + return TRUE; +} + +PyObject * +PyHKEY_FromHKEY(HKEY h) +{ + PyHKEYObject *op; + + /* Inline PyObject_New */ + op = (PyHKEYObject *) PyObject_MALLOC(sizeof(PyHKEYObject)); + if (op == NULL) + return PyErr_NoMemory(); + PyObject_INIT(op, &PyHKEY_Type); + op->hkey = h; + return (PyObject *)op; +} + + +/************************************************************************ + The module methods +************************************************************************/ +BOOL +PyWinObject_CloseHKEY(PyObject *obHandle) +{ + BOOL ok; + if (PyHKEY_Check(obHandle)) { + ok = PyHKEY_Close(obHandle); + } +#if SIZEOF_LONG >= SIZEOF_HKEY + else if (PyInt_Check(obHandle)) { + long rc = RegCloseKey((HKEY)PyInt_AsLong(obHandle)); + ok = (rc == ERROR_SUCCESS); + if (!ok) + PyErr_SetFromWindowsErrWithFunction(rc, "RegCloseKey"); + } +#else + else if (PyLong_Check(obHandle)) { + long rc = RegCloseKey((HKEY)PyLong_AsVoidPtr(obHandle)); + ok = (rc == ERROR_SUCCESS); + if (!ok) + PyErr_SetFromWindowsErrWithFunction(rc, "RegCloseKey"); + } +#endif + else { + PyErr_SetString( + PyExc_TypeError, + "A handle must be a HKEY object or an integer"); + return FALSE; + } + return ok; +} + + +/* + Private Helper functions for the registry interfaces + +** Note that fixupMultiSZ and countString have both had changes +** made to support "incorrect strings". The registry specification +** calls for strings to be terminated with 2 null bytes. It seems +** some commercial packages install strings which don't conform, +** causing this code to fail - however, "regedit" etc still work +** with these strings (ie only we don't!). +*/ +static void +fixupMultiSZ(char **str, char *data, int len) +{ + char *P; + int i; + char *Q; + + Q = data + len; + for (P = data, i = 0; P < Q && *P != '\0'; P++, i++) { + str[i] = P; + for(; *P != '\0'; P++) + ; + } +} + +static int +countStrings(char *data, int len) +{ + int strings; + char *P; + char *Q = data + len; + + for (P = data, strings = 0; P < Q && *P != '\0'; P++, strings++) + for (; P < Q && *P != '\0'; P++) + ; + return strings; +} + +/* Convert PyObject into Registry data. + Allocates space as needed. */ +static BOOL +Py2Reg(PyObject *value, DWORD typ, BYTE **retDataBuf, DWORD *retDataSize) +{ + Py_ssize_t i,j; + switch (typ) { + case REG_DWORD: + if (value != Py_None && !_PyAnyInt_Check(value)) + return FALSE; + *retDataBuf = (BYTE *)PyMem_NEW(DWORD, 1); + if (*retDataBuf==NULL){ + PyErr_NoMemory(); + return FALSE; + } + *retDataSize = sizeof(DWORD); + if (value == Py_None) { + DWORD zero = 0; + memcpy(*retDataBuf, &zero, sizeof(DWORD)); + } + else { + DWORD d = PyLong_AsUnsignedLong(value); + memcpy(*retDataBuf, &d, sizeof(DWORD)); + } + break; + case REG_SZ: + case REG_EXPAND_SZ: + { + int need_decref = 0; + if (value == Py_None) + *retDataSize = 1; + else { + if (PyUnicode_Check(value)) { + value = PyUnicode_AsEncodedString( + value, + "mbcs", + NULL); + if (value==NULL) + return FALSE; + need_decref = 1; + } + if (!PyString_Check(value)) + return FALSE; + *retDataSize = 1 + strlen( + PyString_AS_STRING( + (PyStringObject *)value)); + } + *retDataBuf = (BYTE *)PyMem_NEW(DWORD, *retDataSize); + if (*retDataBuf==NULL){ + PyErr_NoMemory(); + return FALSE; + } + if (value == Py_None) + strcpy((char *)*retDataBuf, ""); + else + strcpy((char *)*retDataBuf, + PyString_AS_STRING( + (PyStringObject *)value)); + if (need_decref) + Py_DECREF(value); + break; + } + case REG_MULTI_SZ: + { + DWORD size = 0; + char *P; + PyObject **obs = NULL; + + if (value == Py_None) + i = 0; + else { + if (!PyList_Check(value)) + return FALSE; + i = PyList_Size(value); + } + obs = (PyObject**)malloc(sizeof(PyObject *) * i); + memset(obs, 0, sizeof(PyObject *) * i); + for (j = 0; j < i; j++) + { + PyObject *t; + t = PyList_GET_ITEM( + (PyListObject *)value,j); + if (PyString_Check(t)) { + obs[j] = t; + Py_INCREF(t); + } else if (PyUnicode_Check(t)) { + obs[j] = PyUnicode_AsEncodedString( + t, + "mbcs", + NULL); + if (obs[j]==NULL) + goto reg_multi_fail; + } else + goto reg_multi_fail; + size += 1 + strlen( + PyString_AS_STRING( + (PyStringObject *)obs[j])); + } + + *retDataSize = size + 1; + *retDataBuf = (BYTE *)PyMem_NEW(char, + *retDataSize); + if (*retDataBuf==NULL){ + PyErr_NoMemory(); + goto reg_multi_fail; + } + P = (char *)*retDataBuf; + + for (j = 0; j < i; j++) + { + PyObject *t; + t = obs[j]; + strcpy(P, + PyString_AS_STRING( + (PyStringObject *)t)); + P += 1 + strlen( + PyString_AS_STRING( + (PyStringObject *)t)); + Py_DECREF(obs[j]); + } + /* And doubly-terminate the list... */ + *P = '\0'; + free(obs); + break; + reg_multi_fail: + if (obs) { + for (j = 0; j < i; j++) + Py_XDECREF(obs[j]); + + free(obs); + } + return FALSE; + } + case REG_BINARY: + /* ALSO handle ALL unknown data types here. Even if we can't + support it natively, we should handle the bits. */ + default: + if (value == Py_None) { + *retDataSize = 0; + *retDataBuf = NULL; + } + else { + void *src_buf; + PyBufferProcs *pb = value->ob_type->tp_as_buffer; + if (pb == NULL || pb->bf_getreadbuffer == NULL) { + PyErr_Format(PyExc_TypeError, + "Objects of type '%s' can not " + "be used as binary registry values", + value->ob_type->tp_name); + return FALSE; + } + *retDataSize = (*pb->bf_getreadbuffer)(value, 0, &src_buf); + if (*retDataSize < 0) { + return FALSE; + } + *retDataBuf = (BYTE *)PyMem_NEW(char, *retDataSize); + if (*retDataBuf == NULL){ + PyErr_NoMemory(); + return FALSE; + } + memcpy(*retDataBuf, src_buf, *retDataSize); + } + break; + } + return TRUE; +} + +/* Convert Registry data into PyObject*/ +static PyObject * +Reg2Py(char *retDataBuf, DWORD retDataSize, DWORD typ) +{ + PyObject *obData; + + switch (typ) { + case REG_DWORD: + if (retDataSize == 0) + obData = Py_BuildValue("k", 0); + else + obData = Py_BuildValue("k", + *(int *)retDataBuf); + break; + case REG_SZ: + case REG_EXPAND_SZ: + /* retDataBuf may or may not have a trailing NULL in + the buffer. */ + if (retDataSize && retDataBuf[retDataSize-1] == '\0') + --retDataSize; + if (retDataSize ==0) + retDataBuf = ""; + obData = PyUnicode_DecodeMBCS(retDataBuf, + retDataSize, + NULL); + break; + case REG_MULTI_SZ: + if (retDataSize == 0) + obData = PyList_New(0); + else + { + int index = 0; + int s = countStrings(retDataBuf, retDataSize); + char **str = (char **)malloc(sizeof(char *)*s); + if (str == NULL) + return PyErr_NoMemory(); + + fixupMultiSZ(str, retDataBuf, retDataSize); + obData = PyList_New(s); + if (obData == NULL) { + free(str); + return NULL; + } + for (index = 0; index < s; index++) + { + size_t len = _mbstrlen(str[index]); + if (len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "registry string is too long for a Python string"); + Py_DECREF(obData); + free(str); + return NULL; + } + PyList_SetItem(obData, + index, + PyUnicode_DecodeMBCS( + (const char *)str[index], + (int)len, + NULL) + ); + } + free(str); + + break; + } + case REG_BINARY: + /* ALSO handle ALL unknown data types here. Even if we can't + support it natively, we should handle the bits. */ + default: + if (retDataSize == 0) { + Py_INCREF(Py_None); + obData = Py_None; + } + else + obData = Py_BuildValue("s#", + (char *)retDataBuf, + retDataSize); + break; + } + if (obData == NULL) + return NULL; + else + return obData; +} + +/* The Python methods */ + +static PyObject * +PyCloseKey(PyObject *self, PyObject *args) +{ + PyObject *obKey; + if (!PyArg_ParseTuple(args, "O:CloseKey", &obKey)) + return NULL; + if (!PyHKEY_Close(obKey)) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyConnectRegistry(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *szCompName = NULL; + HKEY retKey; + long rc; + if (!PyArg_ParseTuple(args, "zO:ConnectRegistry", &szCompName, &obKey)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + Py_BEGIN_ALLOW_THREADS + rc = RegConnectRegistry(szCompName, hKey, &retKey); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, + "ConnectRegistry"); + return PyHKEY_FromHKEY(retKey); +} + +static PyObject * +PyCreateKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *subKey; + HKEY retKey; + long rc; + if (!PyArg_ParseTuple(args, "Oz:CreateKey", &obKey, &subKey)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + rc = RegCreateKey(hKey, subKey, &retKey); + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "CreateKey"); + return PyHKEY_FromHKEY(retKey); +} + +static PyObject * +PyCreateKeyEx(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *subKey; + HKEY retKey; + int res = 0; + REGSAM sam = KEY_WRITE; + long rc; + if (!PyArg_ParseTuple(args, "Oz|ii:CreateKeyEx", &obKey, &subKey, + &res, &sam)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + + rc = RegCreateKeyEx(hKey, subKey, res, NULL, (DWORD)NULL, + sam, NULL, &retKey, NULL); + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "CreateKeyEx"); + return PyHKEY_FromHKEY(retKey); +} + +static PyObject * +PyDeleteKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *subKey; + long rc; + if (!PyArg_ParseTuple(args, "Os:DeleteKey", &obKey, &subKey)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + rc = RegDeleteKey(hKey, subKey ); + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "RegDeleteKey"); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyDeleteKeyEx(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + HMODULE hMod; + typedef LONG (WINAPI *RDKEFunc)(HKEY, const char*, REGSAM, int); + RDKEFunc pfn = NULL; + char *subKey; + long rc; + int res = 0; + REGSAM sam = KEY_WOW64_64KEY; + + if (!PyArg_ParseTuple(args, "Os|ii:DeleteKeyEx", + &obKey, &subKey, &sam, &res)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + + /* Only available on 64bit platforms, so we must load it + dynamically. */ + hMod = GetModuleHandle("advapi32.dll"); + if (hMod) + pfn = (RDKEFunc)GetProcAddress(hMod, + "RegDeleteKeyExA"); + if (!pfn) { + PyErr_SetString(PyExc_NotImplementedError, + "not implemented on this platform"); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + rc = (*pfn)(hKey, subKey, sam, res); + Py_END_ALLOW_THREADS + + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "RegDeleteKeyEx"); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyDeleteValue(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *subKey; + long rc; + if (!PyArg_ParseTuple(args, "Oz:DeleteValue", &obKey, &subKey)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + Py_BEGIN_ALLOW_THREADS + rc = RegDeleteValue(hKey, subKey); + Py_END_ALLOW_THREADS + if (rc !=ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, + "RegDeleteValue"); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyEnumKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + int index; + long rc; + PyObject *retStr; + + /* The Windows docs claim that the max key name length is 255 + * characters, plus a terminating nul character. However, + * empirical testing demonstrates that it is possible to + * create a 256 character key that is missing the terminating + * nul. RegEnumKeyEx requires a 257 character buffer to + * retrieve such a key name. */ + char tmpbuf[257]; + DWORD len = sizeof(tmpbuf); /* includes NULL terminator */ + + if (!PyArg_ParseTuple(args, "Oi:EnumKey", &obKey, &index)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + rc = RegEnumKeyEx(hKey, index, tmpbuf, &len, NULL, NULL, NULL, NULL); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "RegEnumKeyEx"); + + retStr = PyString_FromStringAndSize(tmpbuf, len); + return retStr; /* can be NULL */ +} + +static PyObject * +PyEnumValue(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + int index; + long rc; + char *retValueBuf; + char *retDataBuf; + char *tmpBuf; + DWORD retValueSize, bufValueSize; + DWORD retDataSize, bufDataSize; + DWORD typ; + PyObject *obData; + PyObject *retVal; + + if (!PyArg_ParseTuple(args, "Oi:EnumValue", &obKey, &index)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + + if ((rc = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, + &retValueSize, &retDataSize, NULL, NULL)) + != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, + "RegQueryInfoKey"); + ++retValueSize; /* include null terminators */ + ++retDataSize; + bufDataSize = retDataSize; + bufValueSize = retValueSize; + retValueBuf = (char *)PyMem_Malloc(retValueSize); + if (retValueBuf == NULL) + return PyErr_NoMemory(); + retDataBuf = (char *)PyMem_Malloc(retDataSize); + if (retDataBuf == NULL) { + PyMem_Free(retValueBuf); + return PyErr_NoMemory(); + } + + while (1) { + Py_BEGIN_ALLOW_THREADS + rc = RegEnumValue(hKey, + index, + retValueBuf, + &retValueSize, + NULL, + &typ, + (BYTE *)retDataBuf, + &retDataSize); + Py_END_ALLOW_THREADS + + if (rc != ERROR_MORE_DATA) + break; + + bufDataSize *= 2; + tmpBuf = (char *)PyMem_Realloc(retDataBuf, bufDataSize); + if (tmpBuf == NULL) { + PyErr_NoMemory(); + retVal = NULL; + goto fail; + } + retDataBuf = tmpBuf; + retDataSize = bufDataSize; + retValueSize = bufValueSize; + } + + if (rc != ERROR_SUCCESS) { + retVal = PyErr_SetFromWindowsErrWithFunction(rc, + "PyRegEnumValue"); + goto fail; + } + obData = Reg2Py(retDataBuf, retDataSize, typ); + if (obData == NULL) { + retVal = NULL; + goto fail; + } + retVal = Py_BuildValue("sOi", retValueBuf, obData, typ); + Py_DECREF(obData); + fail: + PyMem_Free(retValueBuf); + PyMem_Free(retDataBuf); + return retVal; +} + +static PyObject * +PyExpandEnvironmentStrings(PyObject *self, PyObject *args) +{ + Py_UNICODE *retValue = NULL; + Py_UNICODE *src; + DWORD retValueSize; + DWORD rc; + PyObject *o; + + if (!PyArg_ParseTuple(args, "u:ExpandEnvironmentStrings", &src)) + return NULL; + + retValueSize = ExpandEnvironmentStringsW(src, retValue, 0); + if (retValueSize == 0) { + return PyErr_SetFromWindowsErrWithFunction(retValueSize, + "ExpandEnvironmentStrings"); + } + retValue = (Py_UNICODE *)PyMem_Malloc(retValueSize * sizeof(Py_UNICODE)); + if (retValue == NULL) { + return PyErr_NoMemory(); + } + + rc = ExpandEnvironmentStringsW(src, retValue, retValueSize); + if (rc == 0) { + PyMem_Free(retValue); + return PyErr_SetFromWindowsErrWithFunction(retValueSize, + "ExpandEnvironmentStrings"); + } + o = PyUnicode_FromUnicode(retValue, wcslen(retValue)); + PyMem_Free(retValue); + return o; +} + +static PyObject * +PyFlushKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + long rc; + if (!PyArg_ParseTuple(args, "O:FlushKey", &obKey)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + Py_BEGIN_ALLOW_THREADS + rc = RegFlushKey(hKey); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "RegFlushKey"); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject * +PyLoadKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *subKey; + char *fileName; + + long rc; + if (!PyArg_ParseTuple(args, "Oss:LoadKey", &obKey, &subKey, &fileName)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + Py_BEGIN_ALLOW_THREADS + rc = RegLoadKey(hKey, subKey, fileName ); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "RegLoadKey"); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyOpenKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + + char *subKey; + int res = 0; + HKEY retKey; + long rc; + REGSAM sam = KEY_READ; + if (!PyArg_ParseTuple(args, "Oz|ii:OpenKey", &obKey, &subKey, + &res, &sam)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + rc = RegOpenKeyEx(hKey, subKey, res, sam, &retKey); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "RegOpenKeyEx"); + return PyHKEY_FromHKEY(retKey); +} + + +static PyObject * +PyQueryInfoKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + long rc; + DWORD nSubKeys, nValues; + FILETIME ft; + LARGE_INTEGER li; + PyObject *l; + PyObject *ret; + if (!PyArg_ParseTuple(args, "O:QueryInfoKey", &obKey)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + if ((rc = RegQueryInfoKey(hKey, NULL, NULL, 0, &nSubKeys, NULL, NULL, + &nValues, NULL, NULL, NULL, &ft)) + != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "RegQueryInfoKey"); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + l = PyLong_FromLongLong(li.QuadPart); + if (l == NULL) + return NULL; + ret = Py_BuildValue("iiO", nSubKeys, nValues, l); + Py_DECREF(l); + return ret; +} + +static PyObject * +PyQueryValue(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *subKey; + long rc; + PyObject *retStr; + char *retBuf; + DWORD bufSize = 0; + LONG retSize = 0; + char *tmp; + + if (!PyArg_ParseTuple(args, "Oz:QueryValue", &obKey, &subKey)) + return NULL; + + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + + rc = RegQueryValue(hKey, subKey, NULL, &retSize); + if (rc == ERROR_MORE_DATA) + retSize = 256; + else if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, + "RegQueryValue"); + + bufSize = retSize; + retBuf = (char *) PyMem_Malloc(bufSize); + if (retBuf == NULL) + return PyErr_NoMemory(); + + while (1) { + retSize = bufSize; + rc = RegQueryValue(hKey, subKey, retBuf, &retSize); + if (rc != ERROR_MORE_DATA) + break; + + bufSize *= 2; + tmp = (char *) PyMem_Realloc(retBuf, bufSize); + if (tmp == NULL) { + PyMem_Free(retBuf); + return PyErr_NoMemory(); + } + retBuf = tmp; + } + + if (rc != ERROR_SUCCESS) { + PyMem_Free(retBuf); + return PyErr_SetFromWindowsErrWithFunction(rc, + "RegQueryValue"); + } + + if (retBuf[retSize-1] == '\x00') + retSize--; + retStr = PyString_FromStringAndSize(retBuf, retSize); + if (retStr == NULL) { + PyMem_Free(retBuf); + return NULL; + } + return retStr; +} + +static PyObject * +PyQueryValueEx(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *valueName; + + long rc; + char *retBuf, *tmp; + DWORD bufSize = 0, retSize; + DWORD typ; + PyObject *obData; + PyObject *result; + + if (!PyArg_ParseTuple(args, "Oz:QueryValueEx", &obKey, &valueName)) + return NULL; + + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + + rc = RegQueryValueEx(hKey, valueName, NULL, NULL, NULL, &bufSize); + if (rc == ERROR_MORE_DATA) + bufSize = 256; + else if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, + "RegQueryValueEx"); + retBuf = (char *)PyMem_Malloc(bufSize); + if (retBuf == NULL) + return PyErr_NoMemory(); + + while (1) { + retSize = bufSize; + rc = RegQueryValueEx(hKey, valueName, NULL, &typ, + (BYTE *)retBuf, &retSize); + if (rc != ERROR_MORE_DATA) + break; + + bufSize *= 2; + tmp = (char *) PyMem_Realloc(retBuf, bufSize); + if (tmp == NULL) { + PyMem_Free(retBuf); + return PyErr_NoMemory(); + } + retBuf = tmp; + } + + if (rc != ERROR_SUCCESS) { + PyMem_Free(retBuf); + return PyErr_SetFromWindowsErrWithFunction(rc, + "RegQueryValueEx"); + } + obData = Reg2Py(retBuf, bufSize, typ); + PyMem_Free((void *)retBuf); + if (obData == NULL) + return NULL; + result = Py_BuildValue("Oi", obData, typ); + Py_DECREF(obData); + return result; +} + + +static PyObject * +PySaveKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *fileName; + LPSECURITY_ATTRIBUTES pSA = NULL; + + long rc; + if (!PyArg_ParseTuple(args, "Os:SaveKey", &obKey, &fileName)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; +/* One day we may get security into the core? + if (!PyWinObject_AsSECURITY_ATTRIBUTES(obSA, &pSA, TRUE)) + return NULL; +*/ + Py_BEGIN_ALLOW_THREADS + rc = RegSaveKey(hKey, fileName, pSA ); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "RegSaveKey"); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PySetValue(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *subKey; + char *str; + DWORD typ; + DWORD len; + long rc; + PyObject *obStrVal; + PyObject *obSubKey; + if (!PyArg_ParseTuple(args, "OOiO:SetValue", + &obKey, + &obSubKey, + &typ, + &obStrVal)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + if (typ != REG_SZ) { + PyErr_SetString(PyExc_TypeError, + "Type must be _winreg.REG_SZ"); + return NULL; + } + /* XXX - need Unicode support */ + str = PyString_AsString(obStrVal); + if (str == NULL) + return NULL; + len = PyString_Size(obStrVal); + if (obSubKey == Py_None) + subKey = NULL; + else { + subKey = PyString_AsString(obSubKey); + if (subKey == NULL) + return NULL; + } + Py_BEGIN_ALLOW_THREADS + rc = RegSetValue(hKey, subKey, REG_SZ, str, len+1); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, "RegSetValue"); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PySetValueEx(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + char *valueName; + PyObject *obRes; + PyObject *value; + BYTE *data; + DWORD len; + DWORD typ; + + LONG rc; + + if (!PyArg_ParseTuple(args, "OzOiO:SetValueEx", + &obKey, + &valueName, + &obRes, + &typ, + &value)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + if (!Py2Reg(value, typ, &data, &len)) + { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_ValueError, + "Could not convert the data to the specified type."); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + rc = RegSetValueEx(hKey, valueName, 0, typ, data, len); + Py_END_ALLOW_THREADS + PyMem_DEL(data); + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, + "RegSetValueEx"); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyDisableReflectionKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + HMODULE hMod; + typedef LONG (WINAPI *RDRKFunc)(HKEY); + RDRKFunc pfn = NULL; + LONG rc; + + if (!PyArg_ParseTuple(args, "O:DisableReflectionKey", &obKey)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + + /* Only available on 64bit platforms, so we must load it + dynamically. */ + hMod = GetModuleHandle("advapi32.dll"); + if (hMod) + pfn = (RDRKFunc)GetProcAddress(hMod, + "RegDisableReflectionKey"); + if (!pfn) { + PyErr_SetString(PyExc_NotImplementedError, + "not implemented on this platform"); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + rc = (*pfn)(hKey); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, + "RegDisableReflectionKey"); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyEnableReflectionKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + HMODULE hMod; + typedef LONG (WINAPI *RERKFunc)(HKEY); + RERKFunc pfn = NULL; + LONG rc; + + if (!PyArg_ParseTuple(args, "O:EnableReflectionKey", &obKey)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + + /* Only available on 64bit platforms, so we must load it + dynamically. */ + hMod = GetModuleHandle("advapi32.dll"); + if (hMod) + pfn = (RERKFunc)GetProcAddress(hMod, + "RegEnableReflectionKey"); + if (!pfn) { + PyErr_SetString(PyExc_NotImplementedError, + "not implemented on this platform"); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + rc = (*pfn)(hKey); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, + "RegEnableReflectionKey"); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyQueryReflectionKey(PyObject *self, PyObject *args) +{ + HKEY hKey; + PyObject *obKey; + HMODULE hMod; + typedef LONG (WINAPI *RQRKFunc)(HKEY, BOOL *); + RQRKFunc pfn = NULL; + BOOL result; + LONG rc; + + if (!PyArg_ParseTuple(args, "O:QueryReflectionKey", &obKey)) + return NULL; + if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE)) + return NULL; + + /* Only available on 64bit platforms, so we must load it + dynamically. */ + hMod = GetModuleHandle("advapi32.dll"); + if (hMod) + pfn = (RQRKFunc)GetProcAddress(hMod, + "RegQueryReflectionKey"); + if (!pfn) { + PyErr_SetString(PyExc_NotImplementedError, + "not implemented on this platform"); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + rc = (*pfn)(hKey, &result); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) + return PyErr_SetFromWindowsErrWithFunction(rc, + "RegQueryReflectionKey"); + return PyBool_FromLong(result); +} + +static struct PyMethodDef winreg_methods[] = { + {"CloseKey", PyCloseKey, METH_VARARGS, CloseKey_doc}, + {"ConnectRegistry", PyConnectRegistry, METH_VARARGS, ConnectRegistry_doc}, + {"CreateKey", PyCreateKey, METH_VARARGS, CreateKey_doc}, + {"CreateKeyEx", PyCreateKeyEx, METH_VARARGS, CreateKeyEx_doc}, + {"DeleteKey", PyDeleteKey, METH_VARARGS, DeleteKey_doc}, + {"DeleteKeyEx", PyDeleteKeyEx, METH_VARARGS, DeleteKeyEx_doc}, + {"DeleteValue", PyDeleteValue, METH_VARARGS, DeleteValue_doc}, + {"DisableReflectionKey", PyDisableReflectionKey, METH_VARARGS, DisableReflectionKey_doc}, + {"EnableReflectionKey", PyEnableReflectionKey, METH_VARARGS, EnableReflectionKey_doc}, + {"EnumKey", PyEnumKey, METH_VARARGS, EnumKey_doc}, + {"EnumValue", PyEnumValue, METH_VARARGS, EnumValue_doc}, + {"ExpandEnvironmentStrings", PyExpandEnvironmentStrings, METH_VARARGS, + ExpandEnvironmentStrings_doc }, + {"FlushKey", PyFlushKey, METH_VARARGS, FlushKey_doc}, + {"LoadKey", PyLoadKey, METH_VARARGS, LoadKey_doc}, + {"OpenKey", PyOpenKey, METH_VARARGS, OpenKey_doc}, + {"OpenKeyEx", PyOpenKey, METH_VARARGS, OpenKeyEx_doc}, + {"QueryValue", PyQueryValue, METH_VARARGS, QueryValue_doc}, + {"QueryValueEx", PyQueryValueEx, METH_VARARGS, QueryValueEx_doc}, + {"QueryInfoKey", PyQueryInfoKey, METH_VARARGS, QueryInfoKey_doc}, + {"QueryReflectionKey",PyQueryReflectionKey,METH_VARARGS, QueryReflectionKey_doc}, + {"SaveKey", PySaveKey, METH_VARARGS, SaveKey_doc}, + {"SetValue", PySetValue, METH_VARARGS, SetValue_doc}, + {"SetValueEx", PySetValueEx, METH_VARARGS, SetValueEx_doc}, + NULL, +}; + +static void +insint(PyObject * d, char * name, long value) +{ + PyObject *v = PyInt_FromLong(value); + if (!v || PyDict_SetItemString(d, name, v)) + PyErr_Clear(); + Py_XDECREF(v); +} + +#define ADD_INT(val) insint(d, #val, val) + +static void +inskey(PyObject * d, char * name, HKEY key) +{ + PyObject *v = PyLong_FromVoidPtr(key); + if (!v || PyDict_SetItemString(d, name, v)) + PyErr_Clear(); + Py_XDECREF(v); +} + +#define ADD_KEY(val) inskey(d, #val, val) + +PyMODINIT_FUNC init_winreg(void) +{ + PyObject *m, *d; + m = Py_InitModule3("_winreg", winreg_methods, module_doc); + if (m == NULL) + return; + d = PyModule_GetDict(m); + if (PyType_Ready(&PyHKEY_Type) < 0) + return; + PyHKEY_Type.tp_doc = PyHKEY_doc; + Py_INCREF(&PyHKEY_Type); + if (PyDict_SetItemString(d, "HKEYType", + (PyObject *)&PyHKEY_Type) != 0) + return; + Py_INCREF(PyExc_WindowsError); + if (PyDict_SetItemString(d, "error", + PyExc_WindowsError) != 0) + return; + + /* Add the relevant constants */ + ADD_KEY(HKEY_CLASSES_ROOT); + ADD_KEY(HKEY_CURRENT_USER); + ADD_KEY(HKEY_LOCAL_MACHINE); + ADD_KEY(HKEY_USERS); + ADD_KEY(HKEY_PERFORMANCE_DATA); +#ifdef HKEY_CURRENT_CONFIG + ADD_KEY(HKEY_CURRENT_CONFIG); +#endif +#ifdef HKEY_DYN_DATA + ADD_KEY(HKEY_DYN_DATA); +#endif + ADD_INT(KEY_QUERY_VALUE); + ADD_INT(KEY_SET_VALUE); + ADD_INT(KEY_CREATE_SUB_KEY); + ADD_INT(KEY_ENUMERATE_SUB_KEYS); + ADD_INT(KEY_NOTIFY); + ADD_INT(KEY_CREATE_LINK); + ADD_INT(KEY_READ); + ADD_INT(KEY_WRITE); + ADD_INT(KEY_EXECUTE); + ADD_INT(KEY_ALL_ACCESS); +#ifdef KEY_WOW64_64KEY + ADD_INT(KEY_WOW64_64KEY); +#endif +#ifdef KEY_WOW64_32KEY + ADD_INT(KEY_WOW64_32KEY); +#endif + ADD_INT(REG_OPTION_RESERVED); + ADD_INT(REG_OPTION_NON_VOLATILE); + ADD_INT(REG_OPTION_VOLATILE); + ADD_INT(REG_OPTION_CREATE_LINK); + ADD_INT(REG_OPTION_BACKUP_RESTORE); + ADD_INT(REG_OPTION_OPEN_LINK); + ADD_INT(REG_LEGAL_OPTION); + ADD_INT(REG_CREATED_NEW_KEY); + ADD_INT(REG_OPENED_EXISTING_KEY); + ADD_INT(REG_WHOLE_HIVE_VOLATILE); + ADD_INT(REG_REFRESH_HIVE); + ADD_INT(REG_NO_LAZY_FLUSH); + ADD_INT(REG_NOTIFY_CHANGE_NAME); + ADD_INT(REG_NOTIFY_CHANGE_ATTRIBUTES); + ADD_INT(REG_NOTIFY_CHANGE_LAST_SET); + ADD_INT(REG_NOTIFY_CHANGE_SECURITY); + ADD_INT(REG_LEGAL_CHANGE_FILTER); + ADD_INT(REG_NONE); + ADD_INT(REG_SZ); + ADD_INT(REG_EXPAND_SZ); + ADD_INT(REG_BINARY); + ADD_INT(REG_DWORD); + ADD_INT(REG_DWORD_LITTLE_ENDIAN); + ADD_INT(REG_DWORD_BIG_ENDIAN); + ADD_INT(REG_LINK); + ADD_INT(REG_MULTI_SZ); + ADD_INT(REG_RESOURCE_LIST); + ADD_INT(REG_FULL_RESOURCE_DESCRIPTOR); + ADD_INT(REG_RESOURCE_REQUIREMENTS_LIST); +} + diff --git a/contrib/tools/python/src/PC/dl_nt.c b/contrib/tools/python/src/PC/dl_nt.c new file mode 100644 index 00000000000..ef1ce0934c1 --- /dev/null +++ b/contrib/tools/python/src/PC/dl_nt.c @@ -0,0 +1,106 @@ +/* + +Entry point for the Windows NT DLL. + +About the only reason for having this, is so initall() can automatically +be called, removing that burden (and possible source of frustration if +forgotten) from the programmer. + +*/ + +#include "Python.h" +#include "windows.h" + +#ifdef Py_ENABLE_SHARED +char dllVersionBuffer[16] = ""; // a private buffer + +// Python Globals +HMODULE PyWin_DLLhModule = NULL; +const char *PyWin_DLLVersionString = dllVersionBuffer; + +// Windows "Activation Context" work: +// Our .pyd extension modules are generally built without a manifest (ie, +// those included with Python and those built with a default distutils. +// This requires we perform some "activation context" magic when loading our +// extensions. In summary: +// * As our DLL loads we save the context being used. +// * Before loading our extensions we re-activate our saved context. +// * After extension load is complete we restore the old context. +// As an added complication, this magic only works on XP or later - we simply +// use the existence (or not) of the relevant function pointers from kernel32. +// See bug 4566 (http://python.org/sf/4566) for more details. + +typedef BOOL (WINAPI * PFN_GETCURRENTACTCTX)(HANDLE *); +typedef BOOL (WINAPI * PFN_ACTIVATEACTCTX)(HANDLE, ULONG_PTR *); +typedef BOOL (WINAPI * PFN_DEACTIVATEACTCTX)(DWORD, ULONG_PTR); +typedef BOOL (WINAPI * PFN_ADDREFACTCTX)(HANDLE); +typedef BOOL (WINAPI * PFN_RELEASEACTCTX)(HANDLE); + +// locals and function pointers for this activation context magic. +static HANDLE PyWin_DLLhActivationContext = NULL; // one day it might be public +static PFN_GETCURRENTACTCTX pfnGetCurrentActCtx = NULL; +static PFN_ACTIVATEACTCTX pfnActivateActCtx = NULL; +static PFN_DEACTIVATEACTCTX pfnDeactivateActCtx = NULL; +static PFN_ADDREFACTCTX pfnAddRefActCtx = NULL; +static PFN_RELEASEACTCTX pfnReleaseActCtx = NULL; + +void _LoadActCtxPointers() +{ + HINSTANCE hKernel32 = GetModuleHandleW(L"kernel32.dll"); + if (hKernel32) + pfnGetCurrentActCtx = (PFN_GETCURRENTACTCTX) GetProcAddress(hKernel32, "GetCurrentActCtx"); + // If we can't load GetCurrentActCtx (ie, pre XP) , don't bother with the rest. + if (pfnGetCurrentActCtx) { + pfnActivateActCtx = (PFN_ACTIVATEACTCTX) GetProcAddress(hKernel32, "ActivateActCtx"); + pfnDeactivateActCtx = (PFN_DEACTIVATEACTCTX) GetProcAddress(hKernel32, "DeactivateActCtx"); + pfnAddRefActCtx = (PFN_ADDREFACTCTX) GetProcAddress(hKernel32, "AddRefActCtx"); + pfnReleaseActCtx = (PFN_RELEASEACTCTX) GetProcAddress(hKernel32, "ReleaseActCtx"); + } +} + +ULONG_PTR _Py_ActivateActCtx() +{ + ULONG_PTR ret = 0; + if (PyWin_DLLhActivationContext && pfnActivateActCtx) + if (!(*pfnActivateActCtx)(PyWin_DLLhActivationContext, &ret)) { + OutputDebugString("Python failed to activate the activation context before loading a DLL\n"); + ret = 0; // no promise the failing function didn't change it! + } + return ret; +} + +void _Py_DeactivateActCtx(ULONG_PTR cookie) +{ + if (cookie && pfnDeactivateActCtx) + if (!(*pfnDeactivateActCtx)(0, cookie)) + OutputDebugString("Python failed to de-activate the activation context\n"); +} + +BOOL WINAPI DllMain (HANDLE hInst, + ULONG ul_reason_for_call, + LPVOID lpReserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + PyWin_DLLhModule = hInst; + // 1000 is a magic number I picked out of the air. Could do with a #define, I spose... + LoadString(hInst, 1000, dllVersionBuffer, sizeof(dllVersionBuffer)); + + // and capture our activation context for use when loading extensions. + _LoadActCtxPointers(); + if (pfnGetCurrentActCtx && pfnAddRefActCtx) + if ((*pfnGetCurrentActCtx)(&PyWin_DLLhActivationContext)) + if (!(*pfnAddRefActCtx)(PyWin_DLLhActivationContext)) + OutputDebugString("Python failed to load the default activation context\n"); + break; + + case DLL_PROCESS_DETACH: + if (pfnReleaseActCtx) + (*pfnReleaseActCtx)(PyWin_DLLhActivationContext); + break; + } + return TRUE; +} + +#endif /* Py_ENABLE_SHARED */ diff --git a/contrib/tools/python/src/PC/errmap.h b/contrib/tools/python/src/PC/errmap.h new file mode 100644 index 00000000000..d225aa4311f --- /dev/null +++ b/contrib/tools/python/src/PC/errmap.h @@ -0,0 +1,78 @@ +/* Generated file. Do not edit. */ +int winerror_to_errno(int winerror) +{ + switch(winerror) { + case 2: return 2; + case 3: return 2; + case 4: return 24; + case 5: return 13; + case 6: return 9; + case 7: return 12; + case 8: return 12; + case 9: return 12; + case 10: return 7; + case 11: return 8; + case 15: return 2; + case 16: return 13; + case 17: return 18; + case 18: return 2; + case 19: return 13; + case 20: return 13; + case 21: return 13; + case 22: return 13; + case 23: return 13; + case 24: return 13; + case 25: return 13; + case 26: return 13; + case 27: return 13; + case 28: return 13; + case 29: return 13; + case 30: return 13; + case 31: return 13; + case 32: return 13; + case 33: return 13; + case 34: return 13; + case 35: return 13; + case 36: return 13; + case 53: return 2; + case 65: return 13; + case 67: return 2; + case 80: return 17; + case 82: return 13; + case 83: return 13; + case 89: return 11; + case 108: return 13; + case 109: return 32; + case 112: return 28; + case 114: return 9; + case 128: return 10; + case 129: return 10; + case 130: return 9; + case 132: return 13; + case 145: return 41; + case 158: return 13; + case 161: return 2; + case 164: return 11; + case 167: return 13; + case 183: return 17; + case 188: return 8; + case 189: return 8; + case 190: return 8; + case 191: return 8; + case 192: return 8; + case 193: return 8; + case 194: return 8; + case 195: return 8; + case 196: return 8; + case 197: return 8; + case 198: return 8; + case 199: return 8; + case 200: return 8; + case 201: return 8; + case 202: return 8; + case 206: return 2; + case 215: return 11; + case 1816: return 12; + default: return EINVAL; + } +} diff --git a/contrib/tools/python/src/PC/getpathp.c b/contrib/tools/python/src/PC/getpathp.c new file mode 100644 index 00000000000..a159ecff295 --- /dev/null +++ b/contrib/tools/python/src/PC/getpathp.c @@ -0,0 +1,715 @@ + +/* Return the initial module search path. */ +/* Used by DOS, OS/2, Windows 3.1, Windows 95/98, Windows NT. */ + +/* ---------------------------------------------------------------- + PATH RULES FOR WINDOWS: + This describes how sys.path is formed on Windows. It describes the + functionality, not the implementation (ie, the order in which these + are actually fetched is different) + + * Python always adds an empty entry at the start, which corresponds + to the current directory. + + * If the PYTHONPATH env. var. exists, its entries are added next. + + * We look in the registry for "application paths" - that is, sub-keys + under the main PythonPath registry key. These are added next (the + order of sub-key processing is undefined). + HKEY_CURRENT_USER is searched and added first. + HKEY_LOCAL_MACHINE is searched and added next. + (Note that all known installers only use HKLM, so HKCU is typically + empty) + + * We attempt to locate the "Python Home" - if the PYTHONHOME env var + is set, we believe it. Otherwise, we use the path of our host .EXE's + to try and locate our "landmark" (lib\\os.py) and deduce our home. + - If we DO have a Python Home: The relevant sub-directories (Lib, + plat-win, lib-tk, etc) are based on the Python Home + - If we DO NOT have a Python Home, the core Python Path is + loaded from the registry. This is the main PythonPath key, + and both HKLM and HKCU are combined to form the path) + + * Iff - we can not locate the Python Home, have not had a PYTHONPATH + specified, and can't locate any Registry entries (ie, we have _nothing_ + we can assume is a good path), a default path with relative entries is + used (eg. .\Lib;.\plat-win, etc) + + + The end result of all this is: + * When running python.exe, or any other .exe in the main Python directory + (either an installed version, or directly from the PCbuild directory), + the core path is deduced, and the core paths in the registry are + ignored. Other "application paths" in the registry are always read. + + * When Python is hosted in another exe (different directory, embedded via + COM, etc), the Python Home will not be deduced, so the core path from + the registry is used. Other "application paths" in the registry are + always read. + + * If Python can't find its home and there is no registry (eg, frozen + exe, some very strange installation setup) you get a path with + some default, but relative, paths. + + ---------------------------------------------------------------- */ + + +#include "Python.h" +#include "osdefs.h" + +#ifdef MS_WINDOWS +#include <windows.h> +#include <tchar.h> +#include <minmax.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif /* HAVE_SYS_TYPES_H */ + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif /* HAVE_SYS_STAT_H */ + +#include <string.h> + +/* Search in some common locations for the associated Python libraries. + * + * Py_GetPath() tries to return a sensible Python module search path. + * + * The approach is an adaptation for Windows of the strategy used in + * ../Modules/getpath.c; it uses the Windows Registry as one of its + * information sources. + */ + +#ifndef LANDMARK +#define LANDMARK "lib\\os.py" +#endif + +static char prefix[MAXPATHLEN+1]; +static char progpath[MAXPATHLEN+1]; +static char dllpath[MAXPATHLEN+1]; +static char *module_search_path = NULL; + + +static int +is_sep(char ch) /* determine if "ch" is a separator character */ +{ +#ifdef ALTSEP + return ch == SEP || ch == ALTSEP; +#else + return ch == SEP; +#endif +} + +/* assumes 'dir' null terminated in bounds. Never writes + beyond existing terminator. +*/ +static void +reduce(char *dir) +{ + size_t i = strlen(dir); + while (i > 0 && !is_sep(dir[i])) + --i; + dir[i] = '\0'; +} + + +static int +exists(char *filename) +{ + struct stat buf; + return stat(filename, &buf) == 0; +} + +/* Assumes 'filename' MAXPATHLEN+1 bytes long - + may extend 'filename' by one character. +*/ +static int +ismodule(char *filename) /* Is module -- check for .pyc/.pyo too */ +{ + if (exists(filename)) + return 1; + + /* Check for the compiled version of prefix. */ + if (strlen(filename) < MAXPATHLEN) { + strcat(filename, Py_OptimizeFlag ? "o" : "c"); + if (exists(filename)) + return 1; + } + return 0; +} + +/* Add a path component, by appending stuff to buffer. + buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a + NUL-terminated string with no more than MAXPATHLEN characters (not counting + the trailing NUL). It's a fatal error if it contains a string longer than + that (callers must be careful!). If these requirements are met, it's + guaranteed that buffer will still be a NUL-terminated string with no more + than MAXPATHLEN characters at exit. If stuff is too long, only as much of + stuff as fits will be appended. +*/ +static void +join(char *buffer, char *stuff) +{ + size_t n, k; + if (is_sep(stuff[0])) + n = 0; + else { + n = strlen(buffer); + if (n > 0 && !is_sep(buffer[n-1]) && n < MAXPATHLEN) + buffer[n++] = SEP; + } + if (n > MAXPATHLEN) + Py_FatalError("buffer overflow in getpathp.c's joinpath()"); + k = strlen(stuff); + if (n + k > MAXPATHLEN) + k = MAXPATHLEN - n; + strncpy(buffer+n, stuff, k); + buffer[n+k] = '\0'; +} + +/* gotlandmark only called by search_for_prefix, which ensures + 'prefix' is null terminated in bounds. join() ensures + 'landmark' can not overflow prefix if too long. +*/ +static int +gotlandmark(char *landmark) +{ + int ok; + Py_ssize_t n; + + n = strlen(prefix); + join(prefix, landmark); + ok = ismodule(prefix); + prefix[n] = '\0'; + return ok; +} + +/* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd. + assumption provided by only caller, calculate_path() */ +static int +search_for_prefix(char *argv0_path, char *landmark) +{ + /* Search from argv0_path, until landmark is found */ + strcpy(prefix, argv0_path); + do { + if (gotlandmark(landmark)) + return 1; + reduce(prefix); + } while (prefix[0]); + return 0; +} + +#ifdef MS_WINDOWS +#ifdef Py_ENABLE_SHARED + +/* a string loaded from the DLL at startup.*/ +extern const char *PyWin_DLLVersionString; + + +/* Load a PYTHONPATH value from the registry. + Load from either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER. + + Works in both Unicode and 8bit environments. Only uses the + Ex family of functions so it also works with Windows CE. + + Returns NULL, or a pointer that should be freed. + + XXX - this code is pretty strange, as it used to also + work on Win16, where the buffer sizes werent available + in advance. It could be simplied now Win16/Win32s is dead! +*/ + +static char * +getpythonregpath(HKEY keyBase, int skipcore) +{ + HKEY newKey = 0; + DWORD dataSize = 0; + DWORD numKeys = 0; + LONG rc; + char *retval = NULL; + TCHAR *dataBuf = NULL; + static const TCHAR keyPrefix[] = _T("Software\\Python\\PythonCore\\"); + static const TCHAR keySuffix[] = _T("\\PythonPath"); + size_t versionLen; + DWORD index; + TCHAR *keyBuf = NULL; + TCHAR *keyBufPtr; + TCHAR **ppPaths = NULL; + + /* Tried to use sysget("winver") but here is too early :-( */ + versionLen = _tcslen(PyWin_DLLVersionString); + /* Space for all the chars, plus one \0 */ + keyBuf = keyBufPtr = malloc(sizeof(keyPrefix) + + sizeof(TCHAR)*(versionLen-1) + + sizeof(keySuffix)); + if (keyBuf==NULL) goto done; + + memcpy(keyBufPtr, keyPrefix, sizeof(keyPrefix)-sizeof(TCHAR)); + keyBufPtr += sizeof(keyPrefix)/sizeof(TCHAR) - 1; + memcpy(keyBufPtr, PyWin_DLLVersionString, versionLen * sizeof(TCHAR)); + keyBufPtr += versionLen; + /* NULL comes with this one! */ + memcpy(keyBufPtr, keySuffix, sizeof(keySuffix)); + /* Open the root Python key */ + rc=RegOpenKeyEx(keyBase, + keyBuf, /* subkey */ + 0, /* reserved */ + KEY_READ, + &newKey); + if (rc!=ERROR_SUCCESS) goto done; + /* Find out how big our core buffer is, and how many subkeys we have */ + rc = RegQueryInfoKey(newKey, NULL, NULL, NULL, &numKeys, NULL, NULL, + NULL, NULL, &dataSize, NULL, NULL); + if (rc!=ERROR_SUCCESS) goto done; + if (skipcore) dataSize = 0; /* Only count core ones if we want them! */ + /* Allocate a temp array of char buffers, so we only need to loop + reading the registry once + */ + ppPaths = malloc( sizeof(TCHAR *) * numKeys ); + if (ppPaths==NULL) goto done; + memset(ppPaths, 0, sizeof(TCHAR *) * numKeys); + /* Loop over all subkeys, allocating a temp sub-buffer. */ + for(index=0;index<numKeys;index++) { + TCHAR keyBuf[MAX_PATH+1]; + HKEY subKey = 0; + DWORD reqdSize = MAX_PATH+1; + /* Get the sub-key name */ + DWORD rc = RegEnumKeyEx(newKey, index, keyBuf, &reqdSize, + NULL, NULL, NULL, NULL ); + if (rc!=ERROR_SUCCESS) goto done; + /* Open the sub-key */ + rc=RegOpenKeyEx(newKey, + keyBuf, /* subkey */ + 0, /* reserved */ + KEY_READ, + &subKey); + if (rc!=ERROR_SUCCESS) goto done; + /* Find the value of the buffer size, malloc, then read it */ + RegQueryValueEx(subKey, NULL, 0, NULL, NULL, &reqdSize); + if (reqdSize) { + ppPaths[index] = malloc(reqdSize); + if (ppPaths[index]) { + RegQueryValueEx(subKey, NULL, 0, NULL, + (LPBYTE)ppPaths[index], + &reqdSize); + dataSize += reqdSize + 1; /* 1 for the ";" */ + } + } + RegCloseKey(subKey); + } + + /* return null if no path to return */ + if (dataSize == 0) goto done; + + /* original datasize from RegQueryInfo doesn't include the \0 */ + dataBuf = malloc((dataSize+1) * sizeof(TCHAR)); + if (dataBuf) { + TCHAR *szCur = dataBuf; + DWORD reqdSize = dataSize; + /* Copy our collected strings */ + for (index=0;index<numKeys;index++) { + if (index > 0) { + *(szCur++) = _T(';'); + dataSize--; + } + if (ppPaths[index]) { + Py_ssize_t len = _tcslen(ppPaths[index]); + _tcsncpy(szCur, ppPaths[index], len); + szCur += len; + assert(dataSize > (DWORD)len); + dataSize -= (DWORD)len; + } + } + if (skipcore) + *szCur = '\0'; + else { + /* If we have no values, we dont need a ';' */ + if (numKeys) { + *(szCur++) = _T(';'); + dataSize--; + } + /* Now append the core path entries - + this will include the NULL + */ + rc = RegQueryValueEx(newKey, NULL, 0, NULL, + (LPBYTE)szCur, &dataSize); + } + /* And set the result - caller must free + If MBCS, it is fine as is. If Unicode, allocate new + buffer and convert. + */ +#ifdef UNICODE + retval = (char *)malloc(reqdSize+1); + if (retval) + WideCharToMultiByte(CP_ACP, 0, + dataBuf, -1, /* source */ + retval, reqdSize+1, /* dest */ + NULL, NULL); + free(dataBuf); +#else + retval = dataBuf; +#endif + } +done: + /* Loop freeing my temp buffers */ + if (ppPaths) { + for(index=0;index<numKeys;index++) + if (ppPaths[index]) free(ppPaths[index]); + free(ppPaths); + } + if (newKey) + RegCloseKey(newKey); + if (keyBuf) + free(keyBuf); + return retval; +} +#endif /* Py_ENABLE_SHARED */ +#endif /* MS_WINDOWS */ + +static void +get_progpath(void) +{ + extern char *Py_GetProgramName(void); + char *path = getenv("PATH"); + char *prog = Py_GetProgramName(); + +#ifdef MS_WINDOWS + extern HANDLE PyWin_DLLhModule; +#ifdef UNICODE + WCHAR wprogpath[MAXPATHLEN+1]; + /* Windows documents that GetModuleFileName() will "truncate", + but makes no mention of the null terminator. Play it safe. + PLUS Windows itself defines MAX_PATH as the same, but anyway... + */ +#ifdef Py_ENABLE_SHARED + wprogpath[MAXPATHLEN]=_T('\0'); + if (PyWin_DLLhModule && + GetModuleFileName(PyWin_DLLhModule, wprogpath, MAXPATHLEN)) { + WideCharToMultiByte(CP_ACP, 0, + wprogpath, -1, + dllpath, MAXPATHLEN+1, + NULL, NULL); + } +#else + dllpath[0] = 0; +#endif + wprogpath[MAXPATHLEN]=_T('\0'); + if (GetModuleFileName(NULL, wprogpath, MAXPATHLEN)) { + WideCharToMultiByte(CP_ACP, 0, + wprogpath, -1, + progpath, MAXPATHLEN+1, + NULL, NULL); + return; + } +#else + /* static init of progpath ensures final char remains \0 */ +#ifdef Py_ENABLE_SHARED + if (PyWin_DLLhModule) + if (!GetModuleFileName(PyWin_DLLhModule, dllpath, MAXPATHLEN)) + dllpath[0] = 0; +#else + dllpath[0] = 0; +#endif + if (GetModuleFileName(NULL, progpath, MAXPATHLEN)) + return; +#endif +#endif + if (prog == NULL || *prog == '\0') + prog = "python"; + + /* If there is no slash in the argv0 path, then we have to + * assume python is on the user's $PATH, since there's no + * other way to find a directory to start the search from. If + * $PATH isn't exported, you lose. + */ +#ifdef ALTSEP + if (strchr(prog, SEP) || strchr(prog, ALTSEP)) +#else + if (strchr(prog, SEP)) +#endif + strncpy(progpath, prog, MAXPATHLEN); + else if (path) { + while (1) { + char *delim = strchr(path, DELIM); + + if (delim) { + size_t len = delim - path; + /* ensure we can't overwrite buffer */ + len = min(MAXPATHLEN,len); + strncpy(progpath, path, len); + *(progpath + len) = '\0'; + } + else + strncpy(progpath, path, MAXPATHLEN); + + /* join() is safe for MAXPATHLEN+1 size buffer */ + join(progpath, prog); + if (exists(progpath)) + break; + + if (!delim) { + progpath[0] = '\0'; + break; + } + path = delim + 1; + } + } + else + progpath[0] = '\0'; +} + +static void +calculate_path(void) +{ + char argv0_path[MAXPATHLEN+1]; + char *buf; + size_t bufsz; + char *pythonhome = Py_GetPythonHome(); + char *envpath = Py_GETENV("PYTHONPATH"); + +#ifdef MS_WINDOWS + int skiphome, skipdefault; + char *machinepath = NULL; + char *userpath = NULL; + char zip_path[MAXPATHLEN+1]; + size_t len; +#endif + + get_progpath(); + /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */ + strcpy(argv0_path, progpath); + reduce(argv0_path); + if (pythonhome == NULL || *pythonhome == '\0') { + if (search_for_prefix(argv0_path, LANDMARK)) + pythonhome = prefix; + else + pythonhome = NULL; + } + else + strncpy(prefix, pythonhome, MAXPATHLEN); + + if (envpath && *envpath == '\0') + envpath = NULL; + + +#ifdef MS_WINDOWS + /* Calculate zip archive path */ + if (dllpath[0]) /* use name of python DLL */ + strncpy(zip_path, dllpath, MAXPATHLEN); + else /* use name of executable program */ + strncpy(zip_path, progpath, MAXPATHLEN); + zip_path[MAXPATHLEN] = '\0'; + len = strlen(zip_path); + if (len > 4) { + zip_path[len-3] = 'z'; /* change ending to "zip" */ + zip_path[len-2] = 'i'; + zip_path[len-1] = 'p'; + } + else { + zip_path[0] = 0; + } + + skiphome = pythonhome==NULL ? 0 : 1; +#ifdef Py_ENABLE_SHARED + machinepath = getpythonregpath(HKEY_LOCAL_MACHINE, skiphome); + userpath = getpythonregpath(HKEY_CURRENT_USER, skiphome); +#endif + /* We only use the default relative PYTHONPATH if we havent + anything better to use! */ + skipdefault = envpath!=NULL || pythonhome!=NULL || \ + machinepath!=NULL || userpath!=NULL; +#endif + + /* We need to construct a path from the following parts. + (1) the PYTHONPATH environment variable, if set; + (2) for Win32, the zip archive file path; + (3) for Win32, the machinepath and userpath, if set; + (4) the PYTHONPATH config macro, with the leading "." + of each component replaced with pythonhome, if set; + (5) the directory containing the executable (argv0_path). + The length calculation calculates #4 first. + Extra rules: + - If PYTHONHOME is set (in any way) item (3) is ignored. + - If registry values are used, (4) and (5) are ignored. + */ + + /* Calculate size of return buffer */ + if (pythonhome != NULL) { + char *p; + bufsz = 1; + for (p = PYTHONPATH; *p; p++) { + if (*p == DELIM) + bufsz++; /* number of DELIM plus one */ + } + bufsz *= strlen(pythonhome); + } + else + bufsz = 0; + bufsz += strlen(PYTHONPATH) + 1; + bufsz += strlen(argv0_path) + 1; +#ifdef MS_WINDOWS + if (userpath) + bufsz += strlen(userpath) + 1; + if (machinepath) + bufsz += strlen(machinepath) + 1; + bufsz += strlen(zip_path) + 1; +#endif + if (envpath != NULL) + bufsz += strlen(envpath) + 1; + + module_search_path = buf = (char*)malloc(bufsz); + if (buf == NULL) { + /* We can't exit, so print a warning and limp along */ + fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n"); + if (envpath) { + fprintf(stderr, "Using environment $PYTHONPATH.\n"); + module_search_path = envpath; + } + else { + fprintf(stderr, "Using default static path.\n"); + module_search_path = PYTHONPATH; + } +#ifdef MS_WINDOWS + if (machinepath) + free(machinepath); + if (userpath) + free(userpath); +#endif /* MS_WINDOWS */ + return; + } + + if (envpath) { + strcpy(buf, envpath); + buf = strchr(buf, '\0'); + *buf++ = DELIM; + } +#ifdef MS_WINDOWS + if (zip_path[0]) { + strcpy(buf, zip_path); + buf = strchr(buf, '\0'); + *buf++ = DELIM; + } + if (userpath) { + strcpy(buf, userpath); + buf = strchr(buf, '\0'); + *buf++ = DELIM; + free(userpath); + } + if (machinepath) { + strcpy(buf, machinepath); + buf = strchr(buf, '\0'); + *buf++ = DELIM; + free(machinepath); + } + if (pythonhome == NULL) { + if (!skipdefault) { + strcpy(buf, PYTHONPATH); + buf = strchr(buf, '\0'); + } + } +#else + if (pythonhome == NULL) { + strcpy(buf, PYTHONPATH); + buf = strchr(buf, '\0'); + } +#endif /* MS_WINDOWS */ + else { + char *p = PYTHONPATH; + char *q; + size_t n; + for (;;) { + q = strchr(p, DELIM); + if (q == NULL) + n = strlen(p); + else + n = q-p; + if (p[0] == '.' && is_sep(p[1])) { + strcpy(buf, pythonhome); + buf = strchr(buf, '\0'); + p++; + n--; + } + strncpy(buf, p, n); + buf += n; + if (q == NULL) + break; + *buf++ = DELIM; + p = q+1; + } + } + if (argv0_path) { + *buf++ = DELIM; + strcpy(buf, argv0_path); + buf = strchr(buf, '\0'); + } + *buf = '\0'; + /* Now to pull one last hack/trick. If sys.prefix is + empty, then try and find it somewhere on the paths + we calculated. We scan backwards, as our general policy + is that Python core directories are at the *end* of + sys.path. We assume that our "lib" directory is + on the path, and that our 'prefix' directory is + the parent of that. + */ + if (*prefix=='\0') { + char lookBuf[MAXPATHLEN+1]; + char *look = buf - 1; /* 'buf' is at the end of the buffer */ + while (1) { + Py_ssize_t nchars; + char *lookEnd = look; + /* 'look' will end up one character before the + start of the path in question - even if this + is one character before the start of the buffer + */ + while (look >= module_search_path && *look != DELIM) + look--; + nchars = lookEnd-look; + strncpy(lookBuf, look+1, nchars); + lookBuf[nchars] = '\0'; + /* Up one level to the parent */ + reduce(lookBuf); + if (search_for_prefix(lookBuf, LANDMARK)) { + break; + } + /* If we are out of paths to search - give up */ + if (look < module_search_path) + break; + look--; + } + } +} + + +/* External interface */ + +char * +Py_GetPath(void) +{ + if (!module_search_path) + calculate_path(); + return module_search_path; +} + +char * +Py_GetPrefix(void) +{ + if (!module_search_path) + calculate_path(); + return prefix; +} + +char * +Py_GetExecPrefix(void) +{ + return Py_GetPrefix(); +} + +char * +Py_GetProgramFullPath(void) +{ + if (!module_search_path) + calculate_path(); + return progpath; +} diff --git a/contrib/tools/python/src/PC/import_nt.c b/contrib/tools/python/src/PC/import_nt.c new file mode 100644 index 00000000000..9b0d8e8c1df --- /dev/null +++ b/contrib/tools/python/src/PC/import_nt.c @@ -0,0 +1,86 @@ +/******************************************************************** + + import_nt.c + + Win32 specific import code. + +*/ + +#include "Python.h" +#include "osdefs.h" +#include <windows.h> +#include <Python/importdl.h> +#include "malloc.h" /* for alloca */ + +/* a string loaded from the DLL at startup */ +extern const char *PyWin_DLLVersionString; + +FILE *PyWin_FindRegisteredModule(const char *moduleName, + struct filedescr **ppFileDesc, + char *pathBuf, + Py_ssize_t pathLen) +{ + char *moduleKey; + const char keyPrefix[] = "Software\\Python\\PythonCore\\"; + const char keySuffix[] = "\\Modules\\"; +#ifdef _DEBUG + /* In debugging builds, we _must_ have the debug version + * registered. + */ + const char debugString[] = "\\Debug"; +#else + const char debugString[] = ""; +#endif + struct filedescr *fdp = NULL; + FILE *fp; + HKEY keyBase = HKEY_CURRENT_USER; + LONG modNameSize; + long regStat; + + /* Calculate the size for the sprintf buffer. + * Get the size of the chars only, plus 1 NULL. + */ + size_t bufSize = sizeof(keyPrefix)-1 + + strlen(PyWin_DLLVersionString) + + sizeof(keySuffix) + + strlen(moduleName) + + sizeof(debugString) - 1; + /* alloca == no free required, but memory only local to fn, + * also no heap fragmentation! + */ + moduleKey = (char*)alloca(bufSize); + PyOS_snprintf(moduleKey, bufSize, + "Software\\Python\\PythonCore\\%s\\Modules\\%s%s", + PyWin_DLLVersionString, moduleName, debugString); + + assert(pathLen < INT_MAX); + modNameSize = (int)pathLen; + regStat = RegQueryValue(keyBase, moduleKey, pathBuf, &modNameSize); + if (regStat != ERROR_SUCCESS) { + /* No user setting - lookup in machine settings */ + keyBase = HKEY_LOCAL_MACHINE; + /* be anal - failure may have reset size param */ + modNameSize = (int)pathLen; + regStat = RegQueryValue(keyBase, moduleKey, + pathBuf, &modNameSize); + + if (regStat != ERROR_SUCCESS) + return NULL; + } + /* use the file extension to locate the type entry. */ + for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) { + size_t extLen = strlen(fdp->suffix); + assert(modNameSize >= 0); /* else cast to size_t is wrong */ + if ((size_t)modNameSize > extLen && + strnicmp(pathBuf + ((size_t)modNameSize-extLen-1), + fdp->suffix, + extLen) == 0) + break; + } + if (fdp->suffix == NULL) + return NULL; + fp = fopen(pathBuf, fdp->mode); + if (fp != NULL) + *ppFileDesc = fdp; + return fp; +} diff --git a/contrib/tools/python/src/PC/msvcrtmodule.c b/contrib/tools/python/src/PC/msvcrtmodule.c new file mode 100644 index 00000000000..44c82e4594f --- /dev/null +++ b/contrib/tools/python/src/PC/msvcrtmodule.c @@ -0,0 +1,430 @@ +/********************************************************* + + msvcrtmodule.c + + A Python interface to the Microsoft Visual C Runtime + Library, providing access to those non-portable, but + still useful routines. + + Only ever compiled with an MS compiler, so no attempt + has been made to avoid MS language extensions, etc... + + This may only work on NT or 95... + + Author: Mark Hammond and Guido van Rossum. + Maintenance: Guido van Rossum. + +***********************************************************/ + +#include "Python.h" +#include "malloc.h" +#include <io.h> +#include <conio.h> +#include <sys/locking.h> + +#ifdef _MSC_VER +#if _MSC_VER >= 1500 && _MSC_VER < 1600 +#include <crtassem.h> +#endif +#endif + +// Force the malloc heap to clean itself up, and free unused blocks +// back to the OS. (According to the docs, only works on NT.) +static PyObject * +msvcrt_heapmin(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":heapmin")) + return NULL; + + if (_heapmin() != 0) + return PyErr_SetFromErrno(PyExc_IOError); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(heapmin_doc, +"heapmin() -> None\n\ +\n\ +Force the malloc() heap to clean itself up and return unused blocks\n\ +to the operating system. On failure, this raises IOError."); + +// Perform locking operations on a C runtime file descriptor. +static PyObject * +msvcrt_locking(PyObject *self, PyObject *args) +{ + int fd; + int mode; + long nbytes; + int err; + + if (!PyArg_ParseTuple(args, "iil:locking", &fd, &mode, &nbytes)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + err = _locking(fd, mode, nbytes); + Py_END_ALLOW_THREADS + if (err != 0) + return PyErr_SetFromErrno(PyExc_IOError); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(locking_doc, +"locking(fd, mode, nbytes) -> None\n\ +\n\ +Lock part of a file based on file descriptor fd from the C runtime.\n\ +Raises IOError on failure. The locked region of the file extends from\n\ +the current file position for nbytes bytes, and may continue beyond\n\ +the end of the file. mode must be one of the LK_* constants listed\n\ +below. Multiple regions in a file may be locked at the same time, but\n\ +may not overlap. Adjacent regions are not merged; they must be unlocked\n\ +individually."); + +// Set the file translation mode for a C runtime file descriptor. +static PyObject * +msvcrt_setmode(PyObject *self, PyObject *args) +{ + int fd; + int flags; + if (!PyArg_ParseTuple(args,"ii:setmode", &fd, &flags)) + return NULL; + + flags = _setmode(fd, flags); + if (flags == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + return PyInt_FromLong(flags); +} + +PyDoc_STRVAR(setmode_doc, +"setmode(fd, mode) -> Previous mode\n\ +\n\ +Set the line-end translation mode for the file descriptor fd. To set\n\ +it to text mode, flags should be os.O_TEXT; for binary, it should be\n\ +os.O_BINARY."); + +// Convert an OS file handle to a C runtime file descriptor. +static PyObject * +msvcrt_open_osfhandle(PyObject *self, PyObject *args) +{ + long handle; + int flags; + int fd; + + if (!PyArg_ParseTuple(args, "li:open_osfhandle", &handle, &flags)) + return NULL; + + fd = _open_osfhandle(handle, flags); + if (fd == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + return PyInt_FromLong(fd); +} + +PyDoc_STRVAR(open_osfhandle_doc, +"open_osfhandle(handle, flags) -> file descriptor\n\ +\n\ +Create a C runtime file descriptor from the file handle handle. The\n\ +flags parameter should be a bitwise OR of os.O_APPEND, os.O_RDONLY,\n\ +and os.O_TEXT. The returned file descriptor may be used as a parameter\n\ +to os.fdopen() to create a file object."); + +// Convert a C runtime file descriptor to an OS file handle. +static PyObject * +msvcrt_get_osfhandle(PyObject *self, PyObject *args) +{ + int fd; + Py_intptr_t handle; + + if (!PyArg_ParseTuple(args,"i:get_osfhandle", &fd)) + return NULL; + + if (!_PyVerify_fd(fd)) + return PyErr_SetFromErrno(PyExc_IOError); + + handle = _get_osfhandle(fd); + if (handle == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + /* technically 'handle' is not a pointer, but an integer as + large as a pointer, Python's *VoidPtr interface is the + most appropriate here */ + return PyLong_FromVoidPtr((void*)handle); +} + +PyDoc_STRVAR(get_osfhandle_doc, +"get_osfhandle(fd) -> file handle\n\ +\n\ +Return the file handle for the file descriptor fd. Raises IOError\n\ +if fd is not recognized."); + +/* Console I/O */ + +static PyObject * +msvcrt_kbhit(PyObject *self, PyObject *args) +{ + int ok; + + if (!PyArg_ParseTuple(args, ":kbhit")) + return NULL; + + ok = _kbhit(); + return PyInt_FromLong(ok); +} + +PyDoc_STRVAR(kbhit_doc, +"kbhit() -> bool\n\ +\n\ +Return true if a keypress is waiting to be read."); + +static PyObject * +msvcrt_getch(PyObject *self, PyObject *args) +{ + int ch; + char s[1]; + + if (!PyArg_ParseTuple(args, ":getch")) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ch = _getch(); + Py_END_ALLOW_THREADS + s[0] = ch; + return PyString_FromStringAndSize(s, 1); +} + +PyDoc_STRVAR(getch_doc, +"getch() -> key character\n\ +\n\ +Read a keypress and return the resulting character. Nothing is echoed to\n\ +the console. This call will block if a keypress is not already\n\ +available, but will not wait for Enter to be pressed. If the pressed key\n\ +was a special function key, this will return '\\000' or '\\xe0'; the next\n\ +call will return the keycode. The Control-C keypress cannot be read with\n\ +this function."); + +#ifdef _WCONIO_DEFINED +static PyObject * +msvcrt_getwch(PyObject *self, PyObject *args) +{ + Py_UNICODE ch; + Py_UNICODE u[1]; + + if (!PyArg_ParseTuple(args, ":getwch")) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ch = _getwch(); + Py_END_ALLOW_THREADS + u[0] = ch; + return PyUnicode_FromUnicode(u, 1); +} + +PyDoc_STRVAR(getwch_doc, +"getwch() -> Unicode key character\n\ +\n\ +Wide char variant of getch(), returning a Unicode value."); +#endif + +static PyObject * +msvcrt_getche(PyObject *self, PyObject *args) +{ + int ch; + char s[1]; + + if (!PyArg_ParseTuple(args, ":getche")) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ch = _getche(); + Py_END_ALLOW_THREADS + s[0] = ch; + return PyString_FromStringAndSize(s, 1); +} + +PyDoc_STRVAR(getche_doc, +"getche() -> key character\n\ +\n\ +Similar to getch(), but the keypress will be echoed if it represents\n\ +a printable character."); + +#ifdef _WCONIO_DEFINED +static PyObject * +msvcrt_getwche(PyObject *self, PyObject *args) +{ + Py_UNICODE ch; + Py_UNICODE s[1]; + + if (!PyArg_ParseTuple(args, ":getwche")) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ch = _getwche(); + Py_END_ALLOW_THREADS + s[0] = ch; + return PyUnicode_FromUnicode(s, 1); +} + +PyDoc_STRVAR(getwche_doc, +"getwche() -> Unicode key character\n\ +\n\ +Wide char variant of getche(), returning a Unicode value."); +#endif + +static PyObject * +msvcrt_putch(PyObject *self, PyObject *args) +{ + char ch; + + if (!PyArg_ParseTuple(args, "c:putch", &ch)) + return NULL; + + _putch(ch); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(putch_doc, +"putch(char) -> None\n\ +\n\ +Print the character char to the console without buffering."); + +#ifdef _WCONIO_DEFINED +static PyObject * +msvcrt_putwch(PyObject *self, PyObject *args) +{ + Py_UNICODE *ch; + int size; + + if (!PyArg_ParseTuple(args, "u#:putwch", &ch, &size)) + return NULL; + + if (size == 0) { + PyErr_SetString(PyExc_ValueError, + "Expected unicode string of length 1"); + return NULL; + } + _putwch(*ch); + Py_RETURN_NONE; + +} + +PyDoc_STRVAR(putwch_doc, +"putwch(unicode_char) -> None\n\ +\n\ +Wide char variant of putch(), accepting a Unicode value."); +#endif + +static PyObject * +msvcrt_ungetch(PyObject *self, PyObject *args) +{ + char ch; + + if (!PyArg_ParseTuple(args, "c:ungetch", &ch)) + return NULL; + + if (_ungetch(ch) == EOF) + return PyErr_SetFromErrno(PyExc_IOError); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(ungetch_doc, +"ungetch(char) -> None\n\ +\n\ +Cause the character char to be \"pushed back\" into the console buffer;\n\ +it will be the next character read by getch() or getche()."); + +#ifdef _WCONIO_DEFINED +static PyObject * +msvcrt_ungetwch(PyObject *self, PyObject *args) +{ + Py_UNICODE ch; + + if (!PyArg_ParseTuple(args, "u:ungetwch", &ch)) + return NULL; + + if (_ungetch(ch) == EOF) + return PyErr_SetFromErrno(PyExc_IOError); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(ungetwch_doc, +"ungetwch(unicode_char) -> None\n\ +\n\ +Wide char variant of ungetch(), accepting a Unicode value."); +#endif + +static void +insertint(PyObject *d, char *name, int value) +{ + PyObject *v = PyInt_FromLong((long) value); + if (v == NULL) { + /* Don't bother reporting this error */ + PyErr_Clear(); + } + else { + PyDict_SetItemString(d, name, v); + Py_DECREF(v); + } +} + + +/* List of functions exported by this module */ +static struct PyMethodDef msvcrt_functions[] = { + {"heapmin", msvcrt_heapmin, METH_VARARGS, heapmin_doc}, + {"locking", msvcrt_locking, METH_VARARGS, locking_doc}, + {"setmode", msvcrt_setmode, METH_VARARGS, setmode_doc}, + {"open_osfhandle", msvcrt_open_osfhandle, METH_VARARGS, open_osfhandle_doc}, + {"get_osfhandle", msvcrt_get_osfhandle, METH_VARARGS, get_osfhandle_doc}, + {"kbhit", msvcrt_kbhit, METH_VARARGS, kbhit_doc}, + {"getch", msvcrt_getch, METH_VARARGS, getch_doc}, + {"getche", msvcrt_getche, METH_VARARGS, getche_doc}, + {"putch", msvcrt_putch, METH_VARARGS, putch_doc}, + {"ungetch", msvcrt_ungetch, METH_VARARGS, ungetch_doc}, +#ifdef _WCONIO_DEFINED + {"getwch", msvcrt_getwch, METH_VARARGS, getwch_doc}, + {"getwche", msvcrt_getwche, METH_VARARGS, getwche_doc}, + {"putwch", msvcrt_putwch, METH_VARARGS, putwch_doc}, + {"ungetwch", msvcrt_ungetwch, METH_VARARGS, ungetwch_doc}, +#endif + {NULL, NULL} +}; + +PyMODINIT_FUNC +initmsvcrt(void) +{ + int st; + PyObject *d; + PyObject *m = Py_InitModule("msvcrt", msvcrt_functions); + if (m == NULL) + return; + d = PyModule_GetDict(m); + + /* constants for the locking() function's mode argument */ + insertint(d, "LK_LOCK", _LK_LOCK); + insertint(d, "LK_NBLCK", _LK_NBLCK); + insertint(d, "LK_NBRLCK", _LK_NBRLCK); + insertint(d, "LK_RLCK", _LK_RLCK); + insertint(d, "LK_UNLCK", _LK_UNLCK); + + /* constants for the crt versions */ +#ifdef _VC_ASSEMBLY_PUBLICKEYTOKEN + st = PyModule_AddStringConstant(m, "VC_ASSEMBLY_PUBLICKEYTOKEN", + _VC_ASSEMBLY_PUBLICKEYTOKEN); + if (st < 0)return; +#endif +#ifdef _CRT_ASSEMBLY_VERSION + st = PyModule_AddStringConstant(m, "CRT_ASSEMBLY_VERSION", + _CRT_ASSEMBLY_VERSION); + if (st < 0)return; +#endif +#ifdef __LIBRARIES_ASSEMBLY_NAME_PREFIX + st = PyModule_AddStringConstant(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX", + __LIBRARIES_ASSEMBLY_NAME_PREFIX); + if (st < 0)return; +#endif +} |
