aboutsummaryrefslogtreecommitdiffstats
path: root/utils/plist.c
blob: daca93c92f3505b4bde156dfb9b5fc908da80452 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include "../stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "plist.h"

/*
 * A plist is a double-linked list of key-value pairs
 * It can be circular or not.
 */

/*
 * This is a node in a plist
 */
struct plist_node {
	void *pn_key;
	void *pn_value;
	struct plist_node *pn_next;
	struct plist_node *pn_prev;
};

/*
 * Adds a new entry into a plist.
 * if !*root it creates a node where prev and next point to itself
 * else, inserts itself in the list before *root
 * returns 1 on success, 0 on NOMEM failure.
 */
int
plist_add(void *k, void *v, plist_node_t **root)
{
	plist_node_t *n;

	if (!(n = malloc(sizeof (*n))))
		return 0;
	n->pn_key = k;
	n->pn_value = v;
	if (!*root) {
		n->pn_next = n;
		n->pn_prev = n;
		*root = n;
	} else {
		n->pn_prev = (*root)->pn_prev;
		n->pn_next = (*root);
		(*root)->pn_prev->pn_next = n;
		(*root)->pn_prev = n;
	}
	return 1;
}

/*
 * traverse list until cur == *root or cur == 0, freeing each node
 * (list could be either circular or not)
 * note that the key and value pointers are still valid.
 */
void
plist_clear(plist_node_t **root)
{
	plist_node_t *cur;
	plist_node_t *fr;

	cur = *root;
	while (cur) {
		fr = cur;
		cur = cur->pn_next;
		free(fr); fr = NULL;
		if (cur == *root) {
			*root = NULL;
			return;
		}
	}
}

/*
 * removes a node from a plist where the key pointer == k
 * if ov is not null, it will point to the old value from the removed node
 * This only removes the 1st occurance of k.
 * returns 1 on success, 0 if k was not in the list
 */
int
plist_remove(void *k, plist_node_t **rootp, void **ov)
{
	plist_node_t *cur;

	cur = *rootp;
	while (cur) {
		if (cur->pn_key == k) {
			if (ov)
				*ov = cur->pn_value;
			cur->pn_prev->pn_next = cur->pn_next;
			cur->pn_next->pn_prev = cur->pn_prev;
			if (cur->pn_next == cur)
				*rootp = NULL;
			else if (*rootp == cur)
				*rootp = cur->pn_next;
			free(cur); cur = NULL;
			return 1;
		}
		cur = cur->pn_next;
		if (cur == *rootp)
			return 0;
	}
	return 0;
}

/*
 * finds k in plist.
 * if ov != 0, it will be set to the value pointer
 * returns 1 when the key is found, 0 if not found.
 */
int
plist_contains(void *k, plist_node_t *root, void **ov)
{
	plist_node_t *cur;

	cur = root;
	while (cur) {
		if (cur->pn_key == k) {
			if (ov)
				*ov = cur->pn_value;
			return 1;
		}
		cur = cur->pn_next;
		if (cur == root)
			return 0;
	}
	return 0;
}

/*
 * traverses the plist from start, until we get back to start or next==0
 * runs func with key, val, arg.
 * if func returns 0, stops traversing and returns 0
 * else returns 1 for success
 */
int
plist_walk(plist_node_t *start, int (*func)(const void *k, const void *v,
    void *arg), void *arg)
{
	plist_node_t *cur;
	int res;

	cur = start;
	while (cur) {
		if (!(res = func(cur->pn_key, cur->pn_value, arg)))
			return res;
		cur = cur->pn_next;
		if (cur == start)
			return 1;
	}
	return 1;
}