162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Based on intlist.c by:
462306a36Sopenharmony_ci * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <errno.h>
862306a36Sopenharmony_ci#include <stdlib.h>
962306a36Sopenharmony_ci#include <linux/compiler.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "intlist.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic struct rb_node *intlist__node_new(struct rblist *rblist __maybe_unused,
1462306a36Sopenharmony_ci					 const void *entry)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	unsigned long i = (unsigned long)entry;
1762306a36Sopenharmony_ci	struct rb_node *rc = NULL;
1862306a36Sopenharmony_ci	struct int_node *node = malloc(sizeof(*node));
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	if (node != NULL) {
2162306a36Sopenharmony_ci		node->i = i;
2262306a36Sopenharmony_ci		node->priv = NULL;
2362306a36Sopenharmony_ci		rc = &node->rb_node;
2462306a36Sopenharmony_ci	}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	return rc;
2762306a36Sopenharmony_ci}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic void int_node__delete(struct int_node *ilist)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	free(ilist);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic void intlist__node_delete(struct rblist *rblist __maybe_unused,
3562306a36Sopenharmony_ci				 struct rb_node *rb_node)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	struct int_node *node = container_of(rb_node, struct int_node, rb_node);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	int_node__delete(node);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic int intlist__node_cmp(struct rb_node *rb_node, const void *entry)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	unsigned long i = (unsigned long)entry;
4562306a36Sopenharmony_ci	struct int_node *node = container_of(rb_node, struct int_node, rb_node);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (node->i > i)
4862306a36Sopenharmony_ci		return 1;
4962306a36Sopenharmony_ci	else if (node->i < i)
5062306a36Sopenharmony_ci		return -1;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	return 0;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ciint intlist__add(struct intlist *ilist, unsigned long i)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	return rblist__add_node(&ilist->rblist, (void *)i);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_civoid intlist__remove(struct intlist *ilist, struct int_node *node)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	rblist__remove_node(&ilist->rblist, &node->rb_node);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic struct int_node *__intlist__findnew(struct intlist *ilist,
6662306a36Sopenharmony_ci					   unsigned long i, bool create)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct int_node *node = NULL;
6962306a36Sopenharmony_ci	struct rb_node *rb_node;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (ilist == NULL)
7262306a36Sopenharmony_ci		return NULL;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (create)
7562306a36Sopenharmony_ci		rb_node = rblist__findnew(&ilist->rblist, (void *)i);
7662306a36Sopenharmony_ci	else
7762306a36Sopenharmony_ci		rb_node = rblist__find(&ilist->rblist, (void *)i);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (rb_node)
8062306a36Sopenharmony_ci		node = container_of(rb_node, struct int_node, rb_node);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return node;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistruct int_node *intlist__find(struct intlist *ilist, unsigned long i)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	return __intlist__findnew(ilist, i, false);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistruct int_node *intlist__findnew(struct intlist *ilist, unsigned long i)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	return __intlist__findnew(ilist, i, true);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int intlist__parse_list(struct intlist *ilist, const char *s)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	char *sep;
9862306a36Sopenharmony_ci	int err;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	do {
10162306a36Sopenharmony_ci		unsigned long value = strtol(s, &sep, 10);
10262306a36Sopenharmony_ci		err = -EINVAL;
10362306a36Sopenharmony_ci		if (*sep != ',' && *sep != '\0')
10462306a36Sopenharmony_ci			break;
10562306a36Sopenharmony_ci		err = intlist__add(ilist, value);
10662306a36Sopenharmony_ci		if (err)
10762306a36Sopenharmony_ci			break;
10862306a36Sopenharmony_ci		s = sep + 1;
10962306a36Sopenharmony_ci	} while (*sep != '\0');
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	return err;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistruct intlist *intlist__new(const char *slist)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct intlist *ilist = malloc(sizeof(*ilist));
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	if (ilist != NULL) {
11962306a36Sopenharmony_ci		rblist__init(&ilist->rblist);
12062306a36Sopenharmony_ci		ilist->rblist.node_cmp    = intlist__node_cmp;
12162306a36Sopenharmony_ci		ilist->rblist.node_new    = intlist__node_new;
12262306a36Sopenharmony_ci		ilist->rblist.node_delete = intlist__node_delete;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		if (slist && intlist__parse_list(ilist, slist))
12562306a36Sopenharmony_ci			goto out_delete;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return ilist;
12962306a36Sopenharmony_ciout_delete:
13062306a36Sopenharmony_ci	intlist__delete(ilist);
13162306a36Sopenharmony_ci	return NULL;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_civoid intlist__delete(struct intlist *ilist)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	if (ilist != NULL)
13762306a36Sopenharmony_ci		rblist__delete(&ilist->rblist);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistruct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct int_node *node = NULL;
14362306a36Sopenharmony_ci	struct rb_node *rb_node;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	rb_node = rblist__entry(&ilist->rblist, idx);
14662306a36Sopenharmony_ci	if (rb_node)
14762306a36Sopenharmony_ci		node = container_of(rb_node, struct int_node, rb_node);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return node;
15062306a36Sopenharmony_ci}
151