+
+unsigned avahi_string_list_length(const AvahiStringList *l) {
+ unsigned n = 0;
+
+ for (; l; l = l->next)
+ n++;
+
+ return n;
+}
+
+AvahiStringList *avahi_string_list_add_vprintf(AvahiStringList *l, const char *format, va_list va) {
+ size_t len = 80;
+ AvahiStringList *r;
+
+ assert(format);
+
+ if (!(r = avahi_malloc(sizeof(AvahiStringList) + len)))
+ return NULL;
+
+ for (;;) {
+ int n;
+ AvahiStringList *nr;
+ va_list va2;
+
+ va_copy(va2, va);
+ n = vsnprintf((char*) r->text, len, format, va2);
+ va_end(va2);
+
+ if (n >= 0 && n < (int) len)
+ break;
+
+ if (n >= 0)
+ len = n+1;
+ else
+ len *= 2;
+
+ if (!(nr = avahi_realloc(r, sizeof(AvahiStringList) + len))) {
+ avahi_free(r);
+ return NULL;
+ }
+
+ r = nr;
+ }
+
+ r->next = l;
+ r->size = strlen((char*) r->text);
+
+ return r;
+}
+
+AvahiStringList *avahi_string_list_add_printf(AvahiStringList *l, const char *format, ...) {
+ va_list va;
+
+ assert(format);
+
+ va_start(va, format);
+ l = avahi_string_list_add_vprintf(l, format, va);
+ va_end(va);
+
+ return l;
+}
+
+AvahiStringList *avahi_string_list_find(AvahiStringList *l, const char *key) {
+ size_t n;
+
+ assert(key);
+ n = strlen(key);
+
+ for (; l; l = l->next) {
+ if (strcasecmp((char*) l->text, key) == 0)
+ return l;
+
+ if (strncasecmp((char*) l->text, key, n) == 0 && l->text[n] == '=')
+ return l;
+ }
+
+ return NULL;
+}
+
+AvahiStringList *avahi_string_list_add_pair(AvahiStringList *l, const char *key, const char *value) {
+ assert(key);
+
+ if (value)
+ return avahi_string_list_add_printf(l, "%s=%s", key, value);
+ else
+ return avahi_string_list_add(l, key);
+}
+
+AvahiStringList *avahi_string_list_add_pair_arbitrary(AvahiStringList *l, const char *key, const uint8_t *value, size_t size) {
+ size_t n;
+ assert(key);
+
+ if (!value)
+ return avahi_string_list_add(l, key);
+
+ n = strlen(key);
+
+ if (!(l = avahi_string_list_add_anonymous(l, n + 1 + size)))
+ return NULL;
+
+ memcpy(l->text, key, n);
+ l->text[n] = '=';
+ memcpy(l->text + n + 1, value, size);
+
+ return l;
+}
+
+int avahi_string_list_get_pair(AvahiStringList *l, char **key, char **value, size_t *size) {
+ char *e;
+
+ assert(l);
+
+ if (!(e = memchr(l->text, '=', l->size))) {
+
+ if (key)
+ if (!(*key = avahi_strdup((char*) l->text)))
+ return -1;
+
+ if (value)
+ *value = NULL;
+
+ if (size)
+ *size = 0;
+
+ } else {
+ size_t n;
+
+ if (key)
+ if (!(*key = avahi_strndup((char*) l->text, e - (char *) l->text)))
+ return -1;
+
+ e++; /* Advance after '=' */
+
+ n = l->size - (e - (char*) l->text);
+
+ if (value) {
+
+ if (!(*value = avahi_memdup(e, n+1))) {
+ if (key)
+ avahi_free(*key);
+ return -1;
+ }
+
+ (*value)[n] = 0;
+ }
+
+ if (size)
+ *size = n;
+ }
+
+ return 0;
+}
+
+AvahiStringList *avahi_string_list_get_next(AvahiStringList *l) {
+ assert(l);
+ return l->next;
+}
+
+uint8_t *avahi_string_list_get_text(AvahiStringList *l) {
+ assert(l);
+ return l->text;
+}
+
+size_t avahi_string_list_get_size(AvahiStringList *l) {
+ assert(l);
+ return l->size;
+}
+
+uint32_t avahi_string_list_get_service_cookie(AvahiStringList *l) {
+ AvahiStringList *f;
+ char *value = NULL, *end = NULL;
+ uint32_t ret;
+
+ if (!(f = avahi_string_list_find(l, AVAHI_SERVICE_COOKIE)))
+ return AVAHI_SERVICE_COOKIE_INVALID;
+
+ if (avahi_string_list_get_pair(f, NULL, &value, NULL) < 0 || !value)
+ return AVAHI_SERVICE_COOKIE_INVALID;
+
+ ret = (uint32_t) strtoll(value, &end, 0);
+
+ if (*value && end && *end != 0) {
+ avahi_free(value);
+ return AVAHI_SERVICE_COOKIE_INVALID;
+ }
+
+ avahi_free(value);
+
+ return ret;
+}