]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
xmltv: Add sorted string_list type. (#4441).
authorE.Smith <31170571+azlm8t@users.noreply.github.com>
Wed, 20 Sep 2017 00:49:47 +0000 (01:49 +0100)
committerJaroslav Kysela <perex@perex.cz>
Mon, 9 Oct 2017 14:15:05 +0000 (16:15 +0200)
It's useful to be able to keep lists of sorted strings.
Although htsmsg allows us to keep lists, it is not
designed for easy sorted lists. So, build a simple
type on top of the existing RB trees.

Makefile
src/string_list.c [new file with mode: 0644]
src/string_list.h [new file with mode: 0644]

index a46a64d622c289fcfd39a30f1a8ba62caa6271b5..a7969c3e2bb57fbeaa569dd453969dd7bb62d951 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -254,6 +254,7 @@ SRCS-1 = \
        src/profile.c \
        src/bouquet.c \
        src/lock.c \
+       src/string_list.c \
        src/wizard.c \
        src/memoryinfo.c
 SRCS = $(SRCS-1)
diff --git a/src/string_list.c b/src/string_list.c
new file mode 100644 (file)
index 0000000..09d3ff4
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  Sorted String List Functions
+ *  Copyright (C) 2017 Tvheadend Foundation CIC
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "string_list.h"
+
+#include <string.h>
+#include "htsmsg.h"
+
+/// Sorted string list helper functions.
+void
+string_list_init(string_list_t *l)
+{
+  RB_INIT(l);
+}
+
+string_list_t *
+string_list_create(void)
+{
+  string_list_t *ret = calloc(1, sizeof(string_list_t));
+  string_list_init(ret);
+  return ret;
+}
+
+
+void
+string_list_destroy(string_list_t *l)
+{
+  if (!l) return;
+
+  string_list_item_t *item;
+  while ((item = RB_FIRST(l))) {
+    RB_REMOVE(l, item, h_link);
+    free(item->id);
+  }
+}
+
+static inline int
+string_list_item_cmp(const void *a, const void *b)
+{
+  return strcmp(((const string_list_item_t*)a)->id, ((const string_list_item_t*)b)->id);
+}
+
+void
+string_list_insert(string_list_t *l, const char *id)
+{
+  if (!id) return;
+
+  string_list_item_t *item = calloc(1, sizeof(string_list_item_t));
+  item->id = strdup(id);
+  if (RB_INSERT_SORTED(l, item, h_link, string_list_item_cmp)) {
+    /* Duplicate, so not inserted. */
+    free(item->id);
+    free(item);
+  }
+}
+
+htsmsg_t *
+string_list_to_htsmsg(const string_list_t *l)
+{
+  htsmsg_t *ret = NULL;
+  string_list_item_t *item;
+  RB_FOREACH(item, l, h_link) {
+    if (!ret) ret = htsmsg_create_list();
+    const char *id = item->id;
+    htsmsg_add_str(ret, NULL, id);
+  }
+  return ret;
+}
+
+string_list_t *
+htsmsg_to_string_list(const htsmsg_t *m)
+{
+  string_list_t *ret = NULL;
+  htsmsg_field_t *f;
+  HTSMSG_FOREACH(f, m) {
+    if (f->hmf_type == HMF_STR) {
+      const char *str = f->hmf_str;
+      if (str && *str) {
+        if (!ret) ret = string_list_create();
+
+        string_list_insert(ret, str);
+      }
+    }
+  }
+  return ret;
+}
+
+void
+string_list_serialize(const string_list_t *l, htsmsg_t *m, const char *f)
+{
+    if (!l) return;
+
+    htsmsg_t *msg = string_list_to_htsmsg(l);
+    if (msg)
+      htsmsg_add_msg(m, f, msg);
+}
+
+string_list_t *
+string_list_deserialize(const htsmsg_t *m, const char *n)
+{
+  htsmsg_t *sub = htsmsg_get_list(m, n);
+  if (!sub) return NULL;
+  return htsmsg_to_string_list(sub);
+}
+
+char *
+string_list_2_csv(const string_list_t *l, char delim, int human)
+{
+  if (!l) return NULL;
+
+  htsmsg_t *msg = string_list_to_htsmsg(l);
+  if (!msg) return NULL;
+
+  char *ret = htsmsg_list_2_csv(msg, delim, human);
+  htsmsg_destroy(msg);
+  return ret;
+}
+
+int
+string_list_cmp(const string_list_t *m1, const string_list_t *m2)
+{
+  /* Algorithm based on htsmsg_cmp */
+  if (m1 == NULL && m2 == NULL)
+    return 0;
+  if (m1 == NULL || m2 == NULL)
+    return 1;
+
+  string_list_item_t *i1;
+  string_list_item_t *i2 = RB_FIRST(m2);
+  RB_FOREACH(i1, m1, h_link) {
+    if (i2 == NULL)
+      return 1;
+    const int cmp = strcmp(i1->id, i2->id);
+    /* Not equal? */
+    if (cmp)
+      return cmp;
+
+    i2 = RB_NEXT(i2, h_link);
+  }
+
+  if (i2)
+    return 1;
+
+  return 0;
+}
+
+string_list_t *
+string_list_copy(const string_list_t *src)
+{
+  if (!src) return NULL;
+  string_list_t *ret = string_list_create();
+  string_list_item_t *item;
+  RB_FOREACH(item, src, h_link) {
+    const char *id = item->id;
+    string_list_insert(ret, id);
+  }
+
+  return ret;
+}
diff --git a/src/string_list.h b/src/string_list.h
new file mode 100644 (file)
index 0000000..8657133
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *  Sorted String List Functions
+ *  Copyright (C) 2017 Tvheadend Foundation CIC
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef STRING_LIST_H
+#define STRING_LIST_H
+
+#include "redblack.h"
+
+/*
+ * External forward decls
+ */
+struct htsmsg;
+
+/// Simple _sorted_ string list type and helper functions.
+/// The htsmsg implements lists and maps but they are unsorted.
+/// This implements a simple api for keeping track of sorted
+/// strings. Only one copy of the string is kept in the list
+/// (duplicates are not stored). The list owns the memory
+/// for the strings (takes a copy).
+///
+/// Example:
+/// string_list_create_t *l = string_list_create();
+/// string_list_insert(l, "str1");
+/// string_list_insert(l, "str2");
+/// string_list_destroy(l);
+
+typedef struct string_list_item
+{
+  char* id;
+  RB_ENTRY(string_list_item) h_link;
+} string_list_item_t;
+typedef RB_HEAD(string_list, string_list_item) string_list_t;
+
+/// Initialize the memory used by the list.
+void string_list_init(string_list_t *l);
+/// Dynamically allocate and initialize a list.
+string_list_t *string_list_create(void);
+
+/// Free up the memory used by the list.
+void string_list_destroy(string_list_t *l);
+
+/// Insert a copy of id in to the sorted string list.
+void string_list_insert(string_list_t *l, const char *id);
+
+/// Conversion function from sorted string list to an htsmsg.
+/// @return NULL if empty.
+struct htsmsg *string_list_to_htsmsg(const string_list_t *l)
+    __attribute__((warn_unused_result));
+string_list_t * htsmsg_to_string_list(const struct htsmsg *m)
+    __attribute__((warn_unused_result));
+void string_list_serialize(const string_list_t *l, struct htsmsg *m, const char *f);
+string_list_t *string_list_deserialize(const struct htsmsg *m, const char *f)
+    __attribute__((warn_unused_result));
+char *string_list_2_csv(const string_list_t *l, char delim, int human)
+    __attribute__((warn_unused_result));
+int string_list_cmp(const string_list_t *m1, const string_list_t *m2)
+    __attribute__((warn_unused_result));
+/// Deep clone (shares no pointers, so have to string_list_destroy both.
+string_list_t *string_list_copy(const string_list_t *src)
+    __attribute__((warn_unused_result));
+#endif