X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=decoder.c;h=fc6ae07317c86929a8db634c9b9d2e4391dba081;hb=a83e259abd32c2c8a340af47d5e0d3633331a6cd;hp=7374b779453e015025b59ae6dc4b5f16e5416e09;hpb=2842721f189c5338d268a6e70002936289ae6069;p=libsigrokdecode.git diff --git a/decoder.c b/decoder.c index 7374b77..fc6ae07 100644 --- a/decoder.c +++ b/decoder.c @@ -171,6 +171,7 @@ static void decoder_free(struct srd_decoder *dec) g_slist_free_full(dec->outputs, g_free); g_slist_free_full(dec->inputs, g_free); + g_slist_free_full(dec->tags, g_free); g_free(dec->license); g_free(dec->desc); g_free(dec->longname); @@ -667,6 +668,53 @@ SRD_PRIV long srd_decoder_apiver(const struct srd_decoder *d) return apiver; } +static gboolean contains_duplicates(GSList *list) +{ + for (GSList *l1 = list; l1; l1 = l1->next) { + for (GSList *l2 = l1->next; l2; l2 = l2->next) + if (!strcmp(l1->data, l2->data)) + return TRUE; + } + + return FALSE; +} + +static gboolean contains_duplicate_ids(GSList *list1, GSList *list2) +{ + for (GSList *l1 = list1; l1; l1 = l1->next) { + unsigned int cnt = 0; + const char **s1 = l1->data; + for (GSList *l2 = list2; l2; l2 = l2->next) { + const char **s2 = l2->data; + if (!strcmp(s1[0], s2[0])) + cnt++; + if ((list1 == list2) && cnt > 1) + return TRUE; + if ((list1 != list2) && cnt > 0) + return TRUE; + } + } + + return FALSE; +} + +static gboolean contains_duplicate_row_ids(GSList *list1, GSList *list2) +{ + for (GSList *l1 = list1; l1; l1 = l1->next) { + unsigned int cnt = 0; + const struct srd_decoder_annotation_row *r1 = l1->data; + for (GSList *l2 = list2; l2; l2 = l2->next) { + const struct srd_decoder_annotation_row *r2 = l2->data; + if (!strcmp(r1->id, r2->id)) + cnt++; + if (cnt > 1) + return TRUE; + } + } + + return FALSE; +} + /** * Load a protocol decoder module into the embedded Python interpreter. * @@ -751,6 +799,11 @@ SRD_API int srd_decoder_load(const char *module_name) /* Check Decoder class for required methods. */ + if (check_method(d->py_dec, module_name, "reset") != SRD_OK) { + fail_txt = "no 'reset()' method"; + goto err_out; + } + if (check_method(d->py_dec, module_name, "start") != SRD_OK) { fail_txt = "no 'start()' method"; goto err_out; @@ -797,6 +850,11 @@ SRD_API int srd_decoder_load(const char *module_name) goto err_out; } + if (py_attr_as_strlist(d->py_dec, "tags", &(d->tags)) != SRD_OK) { + fail_txt = "missing or malformed 'tags' attribute"; + goto err_out; + } + /* All options and their default values. */ if (get_options(d) != SRD_OK) { fail_txt = "cannot get options"; @@ -831,6 +889,61 @@ SRD_API int srd_decoder_load(const char *module_name) goto err_out; } + if (contains_duplicates(d->inputs)) { + fail_txt = "duplicate input IDs"; + goto err_out; + } + + if (contains_duplicates(d->outputs)) { + fail_txt = "duplicate output IDs"; + goto err_out; + } + + if (contains_duplicates(d->tags)) { + fail_txt = "duplicate tags"; + goto err_out; + } + + if (contains_duplicate_ids(d->channels, d->channels)) { + fail_txt = "duplicate channel IDs"; + goto err_out; + } + + if (contains_duplicate_ids(d->opt_channels, d->opt_channels)) { + fail_txt = "duplicate optional channel IDs"; + goto err_out; + } + + if (contains_duplicate_ids(d->channels, d->opt_channels)) { + fail_txt = "channel and optional channel IDs contain duplicates"; + goto err_out; + } + + if (contains_duplicate_ids(d->options, d->options)) { + fail_txt = "duplicate option IDs"; + goto err_out; + } + + if (contains_duplicate_ids(d->annotations, d->annotations)) { + fail_txt = "duplicate annotation class IDs"; + goto err_out; + } + + if (contains_duplicate_row_ids(d->annotation_rows, d->annotation_rows)) { + fail_txt = "duplicate annotation row IDs"; + goto err_out; + } + + if (contains_duplicate_ids(d->annotations, d->annotation_rows)) { + fail_txt = "annotation class/row IDs contain duplicates"; + goto err_out; + } + + if (contains_duplicate_ids(d->binary, d->binary)) { + fail_txt = "duplicate binary class IDs"; + goto err_out; + } + PyGILState_Release(gstate); /* Append it to the list of loaded decoders. */ @@ -858,7 +971,7 @@ err_out: /** * Return a protocol decoder's docstring. * - * @param dec The loaded protocol decoder. + * @param dec The loaded protocol decoder. Must not be NULL. * * @return A newly allocated buffer containing the protocol decoder's * documentation. The caller is responsible for free'ing the buffer. @@ -874,7 +987,7 @@ SRD_API char *srd_decoder_doc_get(const struct srd_decoder *dec) if (!srd_check_init()) return NULL; - if (!dec) + if (!dec || !dec->py_mod) return NULL; gstate = PyGILState_Ensure(); @@ -1068,6 +1181,13 @@ SRD_API int srd_decoder_load_all(void) return SRD_OK; } +static void srd_decoder_unload_cb(void *arg, void *ignored) +{ + (void)ignored; + + srd_decoder_unload((struct srd_decoder *)arg); +} + /** * Unload all loaded protocol decoders. * @@ -1077,8 +1197,7 @@ SRD_API int srd_decoder_load_all(void) */ SRD_API int srd_decoder_unload_all(void) { - for (GSList *l = pd_list; l; l = l->next) - srd_decoder_unload(l->data); + g_slist_foreach(pd_list, srd_decoder_unload_cb, NULL); g_slist_free(pd_list); pd_list = NULL;