/** * Get the value of a Python dictionary item, returned as a newly * allocated char *. * * @param py_obj The dictionary to probe. * @param key Key of the item to retrieve. * @param outstr Pointer to char * storage to be filled in. * * @return SRD_OK upon success, a (negative) error code otherwise. * The 'outstr' argument points to a malloc()ed string upon success. * * @private */ SRD_PRIV int py_dictitem_as_str(const PyObject *py_obj, const char *key, char **outstr) { PyObject *py_value; int ret; if (!PyDict_Check((PyObject *)py_obj)) { srd_dbg("Object is a %s, not a dictionary.", Py_TYPE((PyObject *)py_obj)->tp_name); return SRD_ERR_PYTHON; } if (!(py_value = PyDict_GetItemString((PyObject *)py_obj, key))) { srd_dbg("Dictionary has no attribute '%s'.", key); return SRD_ERR_PYTHON; } if (!PyUnicode_Check(py_value)) { srd_dbg("Dictionary value for %s should be a string, but is " "a %s.", key, Py_TYPE(py_value)->tp_name); return SRD_ERR_PYTHON; } ret = py_str_as_str(py_value, outstr); return ret; }
/** * Get the value of a Python object's attribute, returned as a newly * allocated char *. * * @param py_obj The object to probe. * @param attr Name of the attribute to retrieve. * @param outstr ptr to char * storage to be filled in. * * @return SRD_OK upon success, a (negative) error code otherwise. * The 'outstr' argument points to a malloc()ed string upon success. * * @private */ SRD_PRIV int py_attr_as_str(const PyObject *py_obj, const char *attr, char **outstr) { PyObject *py_str; int ret; if (!PyObject_HasAttrString((PyObject *)py_obj, attr)) { srd_dbg("%s object has no attribute '%s'.", Py_TYPE(py_obj)->tp_name, attr); return SRD_ERR_PYTHON; } if (!(py_str = PyObject_GetAttrString((PyObject *)py_obj, attr))) { srd_exception_catch(""); return SRD_ERR_PYTHON; } if (!PyUnicode_Check(py_str)) { srd_dbg("%s attribute should be a string, but is a %s.", attr, Py_TYPE(py_str)->tp_name); Py_DecRef(py_str); return SRD_ERR_PYTHON; } ret = py_str_as_str(py_str, outstr); Py_DecRef(py_str); return ret; }
/** * Add an additional search directory for the protocol decoders. * * The specified directory is prepended (not appended!) to Python's sys.path, * in order to search for sigrok protocol decoders in the specified * directories first, and in the generic Python module directories (and in * the current working directory) last. This avoids conflicts if there are * Python modules which have the same name as a sigrok protocol decoder in * sys.path or in the current working directory. * * @param path Path to the directory containing protocol decoders which shall * be added to the Python sys.path, or NULL. * * @return SRD_OK upon success, a (negative) error code otherwise. */ SRD_PRIV int srd_decoder_searchpath_add(const char *path) { PyObject *py_cur_path, *py_item; GString *new_path; int wc_len, i; wchar_t *wc_new_path; char *item; srd_dbg("Adding '%s' to module path.", path); new_path = g_string_sized_new(256); g_string_assign(new_path, g_strdup(path)); py_cur_path = PySys_GetObject("path"); for (i = 0; i < PyList_Size(py_cur_path); i++) { g_string_append(new_path, g_strdup(G_SEARCHPATH_SEPARATOR_S)); py_item = PyList_GetItem(py_cur_path, i); if (!PyUnicode_Check(py_item)) /* Shouldn't happen. */ continue; if (py_str_as_str(py_item, &item) != SRD_OK) continue; g_string_append(new_path, item); } /* Convert to wide chars. */ wc_len = sizeof(wchar_t) * (new_path->len + 1); if (!(wc_new_path = g_try_malloc(wc_len))) { srd_dbg("malloc failed"); return SRD_ERR_MALLOC; } mbstowcs(wc_new_path, new_path->str, wc_len); PySys_SetPath(wc_new_path); g_string_free(new_path, TRUE); g_free(wc_new_path); //#ifdef _WIN32 // gchar **splitted; // // /* // * On Windows/MinGW, Python's sys.path needs entries of the form // * 'C:\\foo\\bar' instead of '/foo/bar'. // */ // // splitted = g_strsplit(DECODERS_DIR, "/", 0); // path = g_build_pathv("\\\\", splitted); // g_strfreev(splitted); //#else // path = g_strdup(DECODERS_DIR); //#endif return SRD_OK; }
/** * Return a protocol decoder's docstring. * * @param dec The loaded protocol decoder. * * @return A newly allocated buffer containing the protocol decoder's * documentation. The caller is responsible for free'ing the buffer. */ SRD_API char *srd_decoder_doc_get(const struct srd_decoder *dec) { PyObject *py_str; char *doc; if (!PyObject_HasAttrString(dec->py_mod, "__doc__")) return NULL; if (!(py_str = PyObject_GetAttrString(dec->py_mod, "__doc__"))) { srd_exception_catch(""); return NULL; } doc = NULL; if (py_str != Py_None) py_str_as_str(py_str, &doc); Py_DecRef(py_str); return doc; }
/** * Add an additional search directory for the protocol decoders. * * The specified directory is prepended (not appended!) to Python's sys.path, * in order to search for sigrok protocol decoders in the specified * directories first, and in the generic Python module directories (and in * the current working directory) last. This avoids conflicts if there are * Python modules which have the same name as a sigrok protocol decoder in * sys.path or in the current working directory. * * @param path Path to the directory containing protocol decoders which shall * be added to the Python sys.path, or NULL. * * @return SRD_OK upon success, a (negative) error code otherwise. * * @private * * @since 0.1.0 */ SRD_PRIV int srd_decoder_searchpath_add(const char *path) { PyObject *py_cur_path, *py_item; GString *new_path; int wc_len, i; wchar_t *wc_new_path; char *item; srd_dbg("Adding '%s' to module path.", path); new_path = g_string_sized_new(256); g_string_assign(new_path, path); py_cur_path = PySys_GetObject("path"); for (i = 0; i < PyList_Size(py_cur_path); i++) { g_string_append(new_path, G_SEARCHPATH_SEPARATOR_S); py_item = PyList_GetItem(py_cur_path, i); if (!PyUnicode_Check(py_item)) /* Shouldn't happen. */ continue; if (py_str_as_str(py_item, &item) != SRD_OK) continue; g_string_append(new_path, item); g_free(item); } /* Convert to wide chars. */ wc_len = sizeof(wchar_t) * (new_path->len + 1); if (!(wc_new_path = g_try_malloc(wc_len))) { srd_dbg("malloc failed"); return SRD_ERR_MALLOC; } mbstowcs(wc_new_path, new_path->str, wc_len); PySys_SetPath(wc_new_path); g_string_free(new_path, TRUE); g_free(wc_new_path); return SRD_OK; }
/** @private */ SRD_PRIV void srd_exception_catch(const char *format, ...) { PyObject *etype, *evalue, *etb, *py_str; PyTracebackObject *py_tb; GString *msg; va_list args; char *ename, *str, *tracestr; if (!PyErr_Occurred()) /* Nothing is wrong. */ return; PyErr_Fetch(&etype, &evalue, &etb); PyErr_NormalizeException(&etype, &evalue, &etb); if (!(py_str = PyObject_Str(evalue))) { /* Shouldn't happen. */ srd_dbg("Failed to convert exception value to string."); return; } /* Send the exception error message(s) to srd_err(). */ if (evalue) ename = (char *)Py_TYPE(evalue)->tp_name; else /* Can be NULL. */ ename = "(unknown exception)"; msg = g_string_sized_new(128); g_string_append(msg, ename); g_string_append(msg, ": "); va_start(args, format); g_string_append_vprintf(msg, format, args); va_end(args); py_str_as_str(py_str, &str); g_string_append(msg, str); Py_DecRef(py_str); srd_err(msg->str); /* Send a more precise error location to srd_dbg(), if we have it. */ if (etb && etb != Py_None) { tracestr = NULL; py_tb = (PyTracebackObject *)etb; py_str = PyUnicode_FromFormat("%U:%d in %U", py_tb->tb_frame->f_code->co_filename, py_tb->tb_frame->f_lineno, py_tb->tb_frame->f_code->co_name); py_str_as_str(py_str, &tracestr); Py_DecRef(py_str); g_string_printf(msg, "%s in %s: %s", ename, tracestr, str); srd_dbg(msg->str); g_free(tracestr); } g_free(str); g_string_free(msg, TRUE); Py_XDECREF(etype); Py_XDECREF(evalue); Py_XDECREF(etb); /* Just in case. */ PyErr_Clear(); }
/** * Set one or more options in a decoder instance. * * Handled options are removed from the hash. * * @param di Decoder instance. * @param options A GHashTable of options to set. * * @return SRD_OK upon success, a (negative) error code otherwise. * * @since 0.1.0 */ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, GHashTable *options) { PyObject *py_dec_options, *py_dec_optkeys, *py_di_options, *py_optval; PyObject *py_optlist, *py_classval; Py_UNICODE *py_ustr; GVariant *value; unsigned long long int val_ull; gint64 val_int; int num_optkeys, ret, size, i; const char *val_str; char *dbg, *key; if (!di) { srd_err("Invalid decoder instance."); return SRD_ERR_ARG; } if (!options) { srd_err("Invalid options GHashTable."); return SRD_ERR_ARG; } if (!PyObject_HasAttrString(di->decoder->py_dec, "options")) { /* Decoder has no options. */ if (g_hash_table_size(options) == 0) { /* No options provided. */ return SRD_OK; } else { srd_err("Protocol decoder has no options."); return SRD_ERR_ARG; } return SRD_OK; } ret = SRD_ERR_PYTHON; key = NULL; py_dec_options = py_dec_optkeys = py_di_options = py_optval = NULL; py_optlist = py_classval = NULL; py_dec_options = PyObject_GetAttrString(di->decoder->py_dec, "options"); /* All of these are synthesized objects, so they're good. */ py_dec_optkeys = PyDict_Keys(py_dec_options); num_optkeys = PyList_Size(py_dec_optkeys); /* * The 'options' dictionary is a class variable, but we need to * change it. Changing it directly will affect the entire class, * so we need to create a new object for it, and populate that * instead. */ if (!(py_di_options = PyObject_GetAttrString(di->py_inst, "options"))) goto err_out; Py_DECREF(py_di_options); py_di_options = PyDict_New(); PyObject_SetAttrString(di->py_inst, "options", py_di_options); for (i = 0; i < num_optkeys; i++) { /* Get the default class value for this option. */ py_str_as_str(PyList_GetItem(py_dec_optkeys, i), &key); if (!(py_optlist = PyDict_GetItemString(py_dec_options, key))) goto err_out; if (!(py_classval = PyList_GetItem(py_optlist, 1))) goto err_out; if (!PyUnicode_Check(py_classval) && !PyLong_Check(py_classval)) { srd_err("Options of type %s are not yet supported.", Py_TYPE(py_classval)->tp_name); goto err_out; } if ((value = g_hash_table_lookup(options, key))) { dbg = g_variant_print(value, TRUE); srd_dbg("got option '%s' = %s", key, dbg); g_free(dbg); /* An override for this option was provided. */ if (PyUnicode_Check(py_classval)) { if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { srd_err("Option '%s' requires a string value.", key); goto err_out; } val_str = g_variant_get_string(value, NULL); if (!(py_optval = PyUnicode_FromString(val_str))) { /* Some UTF-8 encoding error. */ PyErr_Clear(); srd_err("Option '%s' requires a UTF-8 string value.", key); goto err_out; } } else if (PyLong_Check(py_classval)) { if (!g_variant_is_of_type(value, G_VARIANT_TYPE_INT64)) { srd_err("Option '%s' requires an integer value.", key); goto err_out; } val_int = g_variant_get_int64(value); if (!(py_optval = PyLong_FromLong(val_int))) { /* ValueError Exception */ PyErr_Clear(); srd_err("Option '%s' has invalid integer value.", key); goto err_out; } } g_hash_table_remove(options, key); } else { /* Use the class default for this option. */ if (PyUnicode_Check(py_classval)) { /* Make a brand new copy of the string. */ py_ustr = PyUnicode_AS_UNICODE(py_classval); size = PyUnicode_GET_SIZE(py_classval); py_optval = PyUnicode_FromUnicode(py_ustr, size); } else if (PyLong_Check(py_classval)) { /* Make a brand new copy of the integer. */ val_ull = PyLong_AsUnsignedLongLong(py_classval); if (val_ull == (unsigned long long)-1) { /* OverFlowError exception */ PyErr_Clear(); srd_err("Invalid integer value for %s: " "expected integer.", key); goto err_out; } if (!(py_optval = PyLong_FromUnsignedLongLong(val_ull))) goto err_out; } } /* * If we got here, py_optval holds a known good new reference * to the instance option to set. */ if (PyDict_SetItemString(py_di_options, key, py_optval) == -1) goto err_out; g_free(key); key = NULL; } ret = SRD_OK; err_out: Py_XDECREF(py_di_options); Py_XDECREF(py_dec_optkeys); Py_XDECREF(py_dec_options); g_free(key); if (PyErr_Occurred()) { srd_exception_catch("Stray exception in srd_inst_option_set()."); ret = SRD_ERR_PYTHON; } return ret; }
/** * Set one or more options in a decoder instance. * * Handled options are removed from the hash. * * @param di Decoder instance. * @param options A GHashTable of options to set. * * @return SRD_OK upon success, a (negative) error code otherwise. */ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, GHashTable *options) { PyObject *py_dec_options, *py_dec_optkeys, *py_di_options, *py_optval; PyObject *py_optlist, *py_classval; Py_UNICODE *py_ustr; unsigned long long int val_ull; int num_optkeys, ret, size, i; char *key, *value; if (!PyObject_HasAttrString(di->decoder->py_dec, "options")) { /* Decoder has no options. */ if (g_hash_table_size(options) == 0) { /* No options provided. */ return SRD_OK; } else { srd_err("Protocol decoder has no options."); return SRD_ERR_ARG; } return SRD_OK; } ret = SRD_ERR_PYTHON; key = NULL; py_dec_options = py_dec_optkeys = py_di_options = py_optval = NULL; py_optlist = py_classval = NULL; py_dec_options = PyObject_GetAttrString(di->decoder->py_dec, "options"); /* All of these are synthesized objects, so they're good. */ py_dec_optkeys = PyDict_Keys(py_dec_options); num_optkeys = PyList_Size(py_dec_optkeys); if (!(py_di_options = PyObject_GetAttrString(di->py_inst, "options"))) goto err_out; for (i = 0; i < num_optkeys; i++) { /* Get the default class value for this option. */ py_str_as_str(PyList_GetItem(py_dec_optkeys, i), &key); if (!(py_optlist = PyDict_GetItemString(py_dec_options, key))) goto err_out; if (!(py_classval = PyList_GetItem(py_optlist, 1))) goto err_out; if (!PyUnicode_Check(py_classval) && !PyLong_Check(py_classval)) { srd_err("Options of type %s are not yet supported.", Py_TYPE(py_classval)->tp_name); goto err_out; } if ((value = g_hash_table_lookup(options, key))) { /* An override for this option was provided. */ if (PyUnicode_Check(py_classval)) { if (!(py_optval = PyUnicode_FromString(value))) { /* Some UTF-8 encoding error. */ PyErr_Clear(); goto err_out; } } else if (PyLong_Check(py_classval)) { if (!(py_optval = PyLong_FromString(value, NULL, 0))) { /* ValueError Exception */ PyErr_Clear(); srd_err("Option %s has invalid value " "%s: expected integer.", key, value); goto err_out; } } g_hash_table_remove(options, key); } else { /* Use the class default for this option. */ if (PyUnicode_Check(py_classval)) { /* Make a brand new copy of the string. */ py_ustr = PyUnicode_AS_UNICODE(py_classval); size = PyUnicode_GET_SIZE(py_classval); py_optval = PyUnicode_FromUnicode(py_ustr, size); } else if (PyLong_Check(py_classval)) { /* Make a brand new copy of the integer. */ val_ull = PyLong_AsUnsignedLongLong(py_classval); if (val_ull == (unsigned long long)-1) { /* OverFlowError exception */ PyErr_Clear(); srd_err("Invalid integer value for %s: " "expected integer.", key); goto err_out; } if (!(py_optval = PyLong_FromUnsignedLongLong(val_ull))) goto err_out; } } /* * If we got here, py_optval holds a known good new reference * to the instance option to set. */ if (PyDict_SetItemString(py_di_options, key, py_optval) == -1) goto err_out; } ret = SRD_OK; err_out: Py_XDECREF(py_optlist); Py_XDECREF(py_di_options); Py_XDECREF(py_dec_optkeys); Py_XDECREF(py_dec_options); g_free(key); if (PyErr_Occurred()) srd_exception_catch("Stray exception in srd_inst_option_set()."); return ret; }