/* * libbrlapi - A library providing access to braille terminals for applications. * * Copyright (C) 2005-2021 by * Alexis Robert * Samuel Thibault * * libbrlapi comes with ABSOLUTELY NO WARRANTY. * * This is free software, placed under the terms of the * GNU Lesser General Public License, as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any * later version. Please see the file LICENSE-LGPL for details. * * Web Page: http://brltty.app/ * * This software is maintained by Dave Mielke . */ /* bindings.c provides initialized variables and brlapi exception handler to * the Python bindings */ /* include Python.h first in order to prevent a redefine of _POSIX_C_SOURCE */ #include #include "brlapi.h" /* a kludge to get around a broken MinGW header */ #ifdef __MINGW32__ #ifdef __struct_timespec_defined #ifndef _TIMESPEC_DEFINED #define _TIMESPEC_DEFINED #endif /* _TIMESPEC_DEFINED */ #endif /* __struct_timespec_defined */ #endif /* __MINGW32__ */ #include #include #include #include "bindings.h" const brlapi_writeArguments_t brlapi_writeArguments_initialized = BRLAPI_WRITEARGUMENTS_INITIALIZER; static pthread_once_t brlapi_protocolExceptionOnce = PTHREAD_ONCE_INIT; static pthread_key_t brlapi_protocolExceptionKey; static char *brlapi_protocolExceptionSingleThread; #if defined(WINDOWS) #elif defined(__GNUC__) || defined(__sun__) #pragma weak pthread_once #pragma weak pthread_key_create #pragma weak pthread_getspecific #pragma weak pthread_setspecific #endif /* weak external references */ static void BRLAPI_STDCALL brlapi_pythonExceptionHandler(brlapi_handle_t *handle, int error, brlapi_packetType_t type, const void *packet, size_t size) { char str[128]; brlapi__strexception(handle, str, sizeof(str), error, type, packet, size); #ifndef WINDOWS if (!(pthread_once && pthread_key_create)) brlapi_protocolExceptionSingleThread = strdup(str); else #endif pthread_setspecific(brlapi_protocolExceptionKey, strdup(str)); } char *brlapi_protocolException(void) { char *exception; #ifndef WINDOWS if (!(pthread_once && pthread_key_create)) { exception = brlapi_protocolExceptionSingleThread; brlapi_protocolExceptionSingleThread = NULL; return exception; } else #endif { exception = pthread_getspecific(brlapi_protocolExceptionKey); pthread_setspecific(brlapi_protocolExceptionKey, NULL); return exception; } } static void do_brlapi_protocolExceptionInit(void) { pthread_key_create(&brlapi_protocolExceptionKey, free); } void brlapi_protocolExceptionInit(brlapi_handle_t *handle) { #ifndef WINDOWS if (pthread_once && pthread_key_create) #endif /* WINDOWS */ pthread_once(&brlapi_protocolExceptionOnce, do_brlapi_protocolExceptionInit); brlapi__setExceptionHandler(handle, &brlapi_pythonExceptionHandler); } /* brlapi_python_parameter_callback */ /* This is called from brlapi functions called by Python. We pass the callback * data as such for brlapi.pyx' callback to translate them into python objects */ static void brlapi_python_parameter_callback(brlapi_param_t parameter, brlapi_param_subparam_t subparam, brlapi_param_flags_t flags, void *priv, const void *data, size_t len) { brlapi_python_paramCallbackDescriptor_t *descr = priv; PyObject *arglist, *result; PyGILState_STATE gstate; brlapi_python_callbackData_t callbackData = { .parameter = parameter, .subparam = subparam, .flags = flags, .data = data, .len = len, }; gstate = PyGILState_Ensure(); arglist = Py_BuildValue("(L)", (long long) (uintptr_t) &callbackData); result = PyObject_CallObject(descr->callback, arglist); if (result != NULL) Py_DECREF(result); PyGILState_Release(gstate); } brlapi_python_paramCallbackDescriptor_t *brlapi_python_watchParameter(brlapi_handle_t *handle, brlapi_param_t param, brlapi_param_subparam_t subparam, brlapi_param_flags_t flags, PyObject *func) { brlapi_python_paramCallbackDescriptor_t *descr; brlapi_paramCallbackDescriptor_t *brlapi_descr; PyObject *result; if (!PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "parameter must be callable"); return NULL; } Py_INCREF(func); descr = malloc(sizeof(*descr)); descr->callback = func; brlapi_descr = brlapi__watchParameter(handle, param, subparam, flags, brlapi_python_parameter_callback, descr, NULL, 0); if (!brlapi_descr) { free(descr); PyErr_SetString(PyExc_ValueError, "watching parameter failed"); return NULL; } descr->brlapi_descr = brlapi_descr; return descr; } int brlapi_python_unwatchParameter(brlapi_handle_t *handle, brlapi_python_paramCallbackDescriptor_t *descr) { int ret; ret = brlapi__unwatchParameter(handle, descr->brlapi_descr); Py_DECREF(descr->callback); free(descr); return ret; }