| // SPDX-License-Identifier: GPL-2.0-only | 
 | /* | 
 |  * Based on intlist.c by: | 
 |  * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com> | 
 |  */ | 
 |  | 
 | #include <errno.h> | 
 | #include <stdlib.h> | 
 | #include <linux/compiler.h> | 
 |  | 
 | #include "intlist.h" | 
 |  | 
 | static struct rb_node *intlist__node_new(struct rblist *rblist __maybe_unused, | 
 | 					 const void *entry) | 
 | { | 
 | 	unsigned long i = (unsigned long)entry; | 
 | 	struct rb_node *rc = NULL; | 
 | 	struct int_node *node = malloc(sizeof(*node)); | 
 |  | 
 | 	if (node != NULL) { | 
 | 		node->i = i; | 
 | 		node->priv = NULL; | 
 | 		rc = &node->rb_node; | 
 | 	} | 
 |  | 
 | 	return rc; | 
 | } | 
 |  | 
 | static void int_node__delete(struct int_node *ilist) | 
 | { | 
 | 	free(ilist); | 
 | } | 
 |  | 
 | static void intlist__node_delete(struct rblist *rblist __maybe_unused, | 
 | 				 struct rb_node *rb_node) | 
 | { | 
 | 	struct int_node *node = container_of(rb_node, struct int_node, rb_node); | 
 |  | 
 | 	int_node__delete(node); | 
 | } | 
 |  | 
 | static int intlist__node_cmp(struct rb_node *rb_node, const void *entry) | 
 | { | 
 | 	unsigned long i = (unsigned long)entry; | 
 | 	struct int_node *node = container_of(rb_node, struct int_node, rb_node); | 
 |  | 
 | 	if (node->i > i) | 
 | 		return 1; | 
 | 	else if (node->i < i) | 
 | 		return -1; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int intlist__add(struct intlist *ilist, unsigned long i) | 
 | { | 
 | 	return rblist__add_node(&ilist->rblist, (void *)i); | 
 | } | 
 |  | 
 | void intlist__remove(struct intlist *ilist, struct int_node *node) | 
 | { | 
 | 	rblist__remove_node(&ilist->rblist, &node->rb_node); | 
 | } | 
 |  | 
 | static struct int_node *__intlist__findnew(struct intlist *ilist, | 
 | 					   unsigned long i, bool create) | 
 | { | 
 | 	struct int_node *node = NULL; | 
 | 	struct rb_node *rb_node; | 
 |  | 
 | 	if (ilist == NULL) | 
 | 		return NULL; | 
 |  | 
 | 	if (create) | 
 | 		rb_node = rblist__findnew(&ilist->rblist, (void *)i); | 
 | 	else | 
 | 		rb_node = rblist__find(&ilist->rblist, (void *)i); | 
 |  | 
 | 	if (rb_node) | 
 | 		node = container_of(rb_node, struct int_node, rb_node); | 
 |  | 
 | 	return node; | 
 | } | 
 |  | 
 | struct int_node *intlist__find(struct intlist *ilist, unsigned long i) | 
 | { | 
 | 	return __intlist__findnew(ilist, i, false); | 
 | } | 
 |  | 
 | struct int_node *intlist__findnew(struct intlist *ilist, unsigned long i) | 
 | { | 
 | 	return __intlist__findnew(ilist, i, true); | 
 | } | 
 |  | 
 | static int intlist__parse_list(struct intlist *ilist, const char *s) | 
 | { | 
 | 	char *sep; | 
 | 	int err; | 
 |  | 
 | 	do { | 
 | 		unsigned long value = strtol(s, &sep, 10); | 
 | 		err = -EINVAL; | 
 | 		if (*sep != ',' && *sep != '\0') | 
 | 			break; | 
 | 		err = intlist__add(ilist, value); | 
 | 		if (err) | 
 | 			break; | 
 | 		s = sep + 1; | 
 | 	} while (*sep != '\0'); | 
 |  | 
 | 	return err; | 
 | } | 
 |  | 
 | struct intlist *intlist__new(const char *slist) | 
 | { | 
 | 	struct intlist *ilist = malloc(sizeof(*ilist)); | 
 |  | 
 | 	if (ilist != NULL) { | 
 | 		rblist__init(&ilist->rblist); | 
 | 		ilist->rblist.node_cmp    = intlist__node_cmp; | 
 | 		ilist->rblist.node_new    = intlist__node_new; | 
 | 		ilist->rblist.node_delete = intlist__node_delete; | 
 |  | 
 | 		if (slist && intlist__parse_list(ilist, slist)) | 
 | 			goto out_delete; | 
 | 	} | 
 |  | 
 | 	return ilist; | 
 | out_delete: | 
 | 	intlist__delete(ilist); | 
 | 	return NULL; | 
 | } | 
 |  | 
 | void intlist__delete(struct intlist *ilist) | 
 | { | 
 | 	if (ilist != NULL) | 
 | 		rblist__delete(&ilist->rblist); | 
 | } | 
 |  | 
 | struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx) | 
 | { | 
 | 	struct int_node *node = NULL; | 
 | 	struct rb_node *rb_node; | 
 |  | 
 | 	rb_node = rblist__entry(&ilist->rblist, idx); | 
 | 	if (rb_node) | 
 | 		node = container_of(rb_node, struct int_node, rb_node); | 
 |  | 
 | 	return node; | 
 | } |