| 272 | } |
| 273 | |
| 274 | static int get_options(struct srd_decoder *d) |
| 275 | { |
| 276 | PyObject *py_opts, *py_opt, *py_str, *py_values, *py_default, *py_item; |
| 277 | GSList *options; |
| 278 | struct srd_decoder_option *o; |
| 279 | GVariant *gvar; |
| 280 | ssize_t opt, i; |
| 281 | PyGILState_STATE gstate; |
| 282 | |
| 283 | gstate = PyGILState_Ensure(); |
| 284 | |
| 285 | if (!PyObject_HasAttrString(d->py_dec, "options")) { |
| 286 | /* No options, that's fine. */ |
| 287 | PyGILState_Release(gstate); |
| 288 | return SRD_OK; |
| 289 | } |
| 290 | |
| 291 | options = NULL; |
| 292 | |
| 293 | /* If present, options must be a tuple. */ |
| 294 | py_opts = PyObject_GetAttrString(d->py_dec, "options"); |
| 295 | if (!py_opts) |
| 296 | goto except_out; |
| 297 | |
| 298 | if (!PyTuple_Check(py_opts)) { |
| 299 | srd_err("Protocol decoder %s: options attribute is not " |
| 300 | "a tuple.", d->id); |
| 301 | goto err_out; |
| 302 | } |
| 303 | |
| 304 | for (opt = PyTuple_Size(py_opts) - 1; opt >= 0; opt--) { |
| 305 | py_opt = PyTuple_GetItem(py_opts, opt); |
| 306 | if (!py_opt) |
| 307 | goto except_out; |
| 308 | |
| 309 | if (!PyDict_Check(py_opt)) { |
| 310 | srd_err("Protocol decoder %s options: each option " |
| 311 | "must consist of a dictionary.", d->name); |
| 312 | goto err_out; |
| 313 | } |
| 314 | |
| 315 | o = malloc(sizeof(struct srd_decoder_option)); |
| 316 | if (o == NULL){ |
| 317 | srd_err("%s,ERROR:failed to alloc memory.", __func__); |
| 318 | goto err_out; |
| 319 | } |
| 320 | memset(o, 0, sizeof(struct srd_decoder_option)); |
| 321 | |
| 322 | /* Add to list right away so it doesn't get lost. */ |
| 323 | options = g_slist_prepend(options, o); |
| 324 | |
| 325 | py_str = PyDict_GetItemString(py_opt, "id"); |
| 326 | if (!py_str) { |
| 327 | srd_err("Protocol decoder %s option %zd has no ID.", |
| 328 | d->name, opt); |
| 329 | goto err_out; |
| 330 | } |
| 331 | if (py_str_as_str(py_str, &o->id) != SRD_OK) |
no test coverage detected