diff options
Diffstat (limited to 'pcilib/py.c')
-rw-r--r-- | pcilib/py.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/pcilib/py.c b/pcilib/py.c new file mode 100644 index 0000000..2248892 --- /dev/null +++ b/pcilib/py.c @@ -0,0 +1,171 @@ +#include <Python.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + + +#include "pci.h" +#include "pcilib.h" +#include "py.h" +#include "error.h" + +struct pcilib_py_s { + PyObject *main_module; + PyObject *global_dict; +}; + +int pcilib_init_py(pcilib_t *ctx) { + ctx->py = (pcilib_py_t*)malloc(sizeof(pcilib_py_t)); + if (!ctx->py) return PCILIB_ERROR_MEMORY; + + Py_Initialize(); + + ctx->py->main_module = PyImport_AddModule("__parser__"); + if (!ctx->py->main_module) + return PCILIB_ERROR_FAILED; + + ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module); + if (!ctx->py->global_dict) + return PCILIB_ERROR_FAILED; + + return 0; +} + +void pcilib_free_py(pcilib_t *ctx) { + if (ctx->py) { + // Dict and module references are borrowed + free(ctx->py); + ctx->py = NULL; + } + + Py_Finalize(); +} + +/* +static int pcilib_py_realloc_string(pcilib_t *ctx, size_t required, size_t *size, char **str) { + char *ptr; + size_t cur = *size; + + if ((required + 1) > cur) { + while (cur < required) cur *= 2; + ptr = (char*)realloc(*str, cur); + if (!ptr) return PCILIB_ERROR_MEMORY; + *size = cur; + *str = ptr; + } + ] + return 0; +} +*/ + +static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) { + int i; + int err = 0; + pcilib_value_t val; + pcilib_register_value_t regval; + + char save; + char *reg, *cur; + size_t offset = 0; + + size_t size; + char *src; + char *dst; + + size_t max_repl = 2 + 2 * sizeof(pcilib_value_t); // the text representation of largest integer + + if (value) { + err = pcilib_copy_value(ctx, &val, value); + if (err) return NULL; + + err = pcilib_convert_value_type(ctx, &val, PCILIB_TYPE_STRING); + if (err) return NULL; + + if (strlen(val.sval) > max_repl) + max_repl = strlen(val.sval); + } + + size = ((max_repl + 1) / 3 + 1) * strlen(codestr); // minimum register length is 3 symbols ($a + delimiter space), it is replaces with (max_repl+1) symbols + + src = strdup(codestr); + dst = (char*)malloc(size); // allocating maximum required space + + if ((!src)||(!dst)) { + if (src) free(src); + if (dst) free(dst); + pcilib_error("Failed to allocate memory for string formulas"); + return NULL; + } + + cur = src; + reg = strchr(src, '$'); + while (reg) { + strcpy(dst + offset, cur); + offset += reg - cur; + + // find the end of the register name + reg++; + for (i = 0; isalnum(reg[i]); i++); + save = reg[i]; + reg[i] = 0; + + // determine replacement value + if (!strcasecmp(reg, "value")) { + if (!value) { + pcilib_error("Python formula (%s) relies on the value of register, but it is not provided", codestr); + err = PCILIB_ERROR_INVALID_REQUEST; + break; + } + + strcpy(dst + offset, val.sval); + } else { + err = pcilib_read_register(ctx, NULL, reg, ®val); + if (err) break; + + sprintf(dst + offset, "0x%x", regval); + } + + offset += strlen(dst + offset); + reg[i] = save; + + // Advance to the next register if any + cur = reg + i; + reg = strchr(cur, '$'); + } + + strcpy(dst + offset, cur); + + free(src); + + if (err) { + free(dst); + return NULL; + } + + return dst; +} + +int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) { + PyGILState_STATE gstate; + char *code; + PyObject* obj; + + code = pcilib_py_parse_string(ctx, codestr, value); + if (!code) { + pcilib_error("Failed to parse registers in the code: %s", codestr); + return PCILIB_ERROR_FAILED; + } + + gstate = PyGILState_Ensure(); + obj = PyRun_String(code, Py_eval_input, ctx->py->global_dict, ctx->py->global_dict); + PyGILState_Release(gstate); + + if (!obj) { + pcilib_error("Failed to run the Python code: %s", code); + return PCILIB_ERROR_FAILED; + } + + return pcilib_set_value_from_float(ctx, value, PyFloat_AsDouble(obj)); +} |