1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Based on intlist.c by:
4  * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
5  */
6 
7 #include <errno.h>
8 #include <stdlib.h>
9 #include <linux/compiler.h>
10 
11 #include "intlist.h"
12 
intlist__node_new(struct rblist * rblist __maybe_unused,const void * entry)13 static struct rb_node *intlist__node_new(struct rblist *rblist __maybe_unused,
14 					 const void *entry)
15 {
16 	unsigned long i = (unsigned long)entry;
17 	struct rb_node *rc = NULL;
18 	struct int_node *node = malloc(sizeof(*node));
19 
20 	if (node != NULL) {
21 		node->i = i;
22 		node->priv = NULL;
23 		rc = &node->rb_node;
24 	}
25 
26 	return rc;
27 }
28 
int_node__delete(struct int_node * ilist)29 static void int_node__delete(struct int_node *ilist)
30 {
31 	free(ilist);
32 }
33 
intlist__node_delete(struct rblist * rblist __maybe_unused,struct rb_node * rb_node)34 static void intlist__node_delete(struct rblist *rblist __maybe_unused,
35 				 struct rb_node *rb_node)
36 {
37 	struct int_node *node = container_of(rb_node, struct int_node, rb_node);
38 
39 	int_node__delete(node);
40 }
41 
intlist__node_cmp(struct rb_node * rb_node,const void * entry)42 static int intlist__node_cmp(struct rb_node *rb_node, const void *entry)
43 {
44 	unsigned long i = (unsigned long)entry;
45 	struct int_node *node = container_of(rb_node, struct int_node, rb_node);
46 
47 	if (node->i > i)
48 		return 1;
49 	else if (node->i < i)
50 		return -1;
51 
52 	return 0;
53 }
54 
intlist__add(struct intlist * ilist,unsigned long i)55 int intlist__add(struct intlist *ilist, unsigned long i)
56 {
57 	return rblist__add_node(&ilist->rblist, (void *)i);
58 }
59 
intlist__remove(struct intlist * ilist,struct int_node * node)60 void intlist__remove(struct intlist *ilist, struct int_node *node)
61 {
62 	rblist__remove_node(&ilist->rblist, &node->rb_node);
63 }
64 
__intlist__findnew(struct intlist * ilist,unsigned long i,bool create)65 static struct int_node *__intlist__findnew(struct intlist *ilist,
66 					   unsigned long i, bool create)
67 {
68 	struct int_node *node = NULL;
69 	struct rb_node *rb_node;
70 
71 	if (ilist == NULL)
72 		return NULL;
73 
74 	if (create)
75 		rb_node = rblist__findnew(&ilist->rblist, (void *)i);
76 	else
77 		rb_node = rblist__find(&ilist->rblist, (void *)i);
78 
79 	if (rb_node)
80 		node = container_of(rb_node, struct int_node, rb_node);
81 
82 	return node;
83 }
84 
intlist__find(struct intlist * ilist,unsigned long i)85 struct int_node *intlist__find(struct intlist *ilist, unsigned long i)
86 {
87 	return __intlist__findnew(ilist, i, false);
88 }
89 
intlist__findnew(struct intlist * ilist,unsigned long i)90 struct int_node *intlist__findnew(struct intlist *ilist, unsigned long i)
91 {
92 	return __intlist__findnew(ilist, i, true);
93 }
94 
intlist__parse_list(struct intlist * ilist,const char * s)95 static int intlist__parse_list(struct intlist *ilist, const char *s)
96 {
97 	char *sep;
98 	int err;
99 
100 	do {
101 		unsigned long value = strtol(s, &sep, 10);
102 		err = -EINVAL;
103 		if (*sep != ',' && *sep != '\0')
104 			break;
105 		err = intlist__add(ilist, value);
106 		if (err)
107 			break;
108 		s = sep + 1;
109 	} while (*sep != '\0');
110 
111 	return err;
112 }
113 
intlist__new(const char * slist)114 struct intlist *intlist__new(const char *slist)
115 {
116 	struct intlist *ilist = malloc(sizeof(*ilist));
117 
118 	if (ilist != NULL) {
119 		rblist__init(&ilist->rblist);
120 		ilist->rblist.node_cmp    = intlist__node_cmp;
121 		ilist->rblist.node_new    = intlist__node_new;
122 		ilist->rblist.node_delete = intlist__node_delete;
123 
124 		if (slist && intlist__parse_list(ilist, slist))
125 			goto out_delete;
126 	}
127 
128 	return ilist;
129 out_delete:
130 	intlist__delete(ilist);
131 	return NULL;
132 }
133 
intlist__delete(struct intlist * ilist)134 void intlist__delete(struct intlist *ilist)
135 {
136 	if (ilist != NULL)
137 		rblist__delete(&ilist->rblist);
138 }
139 
intlist__entry(const struct intlist * ilist,unsigned int idx)140 struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx)
141 {
142 	struct int_node *node = NULL;
143 	struct rb_node *rb_node;
144 
145 	rb_node = rblist__entry(&ilist->rblist, idx);
146 	if (rb_node)
147 		node = container_of(rb_node, struct int_node, rb_node);
148 
149 	return node;
150 }
151