From: Uwe Hermann Date: Mon, 30 Dec 2019 15:31:25 +0000 (+0100) Subject: srd_decoder_load(): Error out upon various duplicate IDs. X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=commitdiff_plain;h=1734f4c263201ae4b3aeab6b9ffc7f0eb23fdffd srd_decoder_load(): Error out upon various duplicate IDs. --- diff --git a/HACKING b/HACKING index c5f24f5..9f2f143 100644 --- a/HACKING +++ b/HACKING @@ -150,6 +150,19 @@ Protocol decoder guidelines protocol decoder, e.g., UART) via "sigrok-cli -P uart --show", or in various other places in GUIs. + - Input IDs, output IDs, tags, channel IDs, option IDs, annotation class IDs, + annotation row IDs, and binary class IDs each must be unique. + + - Annotation class IDs must not overlap with annotation row IDs. + For example, you cannot have an annotation row named "foo" if you already + have an annotation class named "foo". This avoids confusion for users + and simplifies e.g. command-line usage of decoders. + + - Annotation class IDs should generally be singular, annotation row IDs + should generally be plural. Example: UART annotation classes could be + named "stop-bit" or "parity-bit" (singular), the annotation row containing + these annotation classes could be named "bits" (plural). + - Generally use strings for states (of the PD state machine), not integers. This avoids having to keep a list of state definitions at the top of file. The performance overhead for this is negligible in practice. diff --git a/decoder.c b/decoder.c index cef4f29..fc6ae07 100644 --- a/decoder.c +++ b/decoder.c @@ -668,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. * @@ -842,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. */