]>
Commit | Line | Data |
---|---|---|
9e246ac3 | 1 | /* |
492b1d2e CD |
2 | * This file is part of the ZFS Event Daemon (ZED) |
3 | * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>. | |
9e246ac3 CD |
4 | * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). |
5 | * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. | |
492b1d2e CD |
6 | * Refer to the ZoL git commit log for authoritative copyright attribution. |
7 | * | |
8 | * The contents of this file are subject to the terms of the | |
9 | * Common Development and Distribution License Version 1.0 (CDDL-1.0). | |
10 | * You can obtain a copy of the license from the top-level file | |
11 | * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>. | |
12 | * You may not use this file except in compliance with the license. | |
9e246ac3 CD |
13 | */ |
14 | ||
15 | #include <assert.h> | |
16 | #include <errno.h> | |
17 | #include <stddef.h> | |
18 | #include <stdlib.h> | |
19 | #include <string.h> | |
20 | #include <sys/avl.h> | |
21 | #include <sys/sysmacros.h> | |
22 | #include "zed_strings.h" | |
23 | ||
24 | struct zed_strings { | |
25 | avl_tree_t tree; | |
26 | avl_node_t *iteratorp; | |
27 | }; | |
28 | ||
29 | struct zed_strings_node { | |
30 | avl_node_t node; | |
854f30a9 CD |
31 | char *key; |
32 | char *val; | |
9e246ac3 CD |
33 | }; |
34 | ||
35 | typedef struct zed_strings_node zed_strings_node_t; | |
36 | ||
37 | /* | |
38 | * Compare zed_strings_node_t nodes [x1] and [x2]. | |
5043deaa | 39 | * As required for the AVL tree, return -1 for <, 0 for ==, and +1 for >. |
9e246ac3 CD |
40 | */ |
41 | static int | |
42 | _zed_strings_node_compare(const void *x1, const void *x2) | |
43 | { | |
44 | const char *s1; | |
45 | const char *s2; | |
46 | int rv; | |
47 | ||
48 | assert(x1 != NULL); | |
49 | assert(x2 != NULL); | |
50 | ||
854f30a9 | 51 | s1 = ((const zed_strings_node_t *) x1)->key; |
9e246ac3 | 52 | assert(s1 != NULL); |
854f30a9 | 53 | s2 = ((const zed_strings_node_t *) x2)->key; |
9e246ac3 CD |
54 | assert(s2 != NULL); |
55 | rv = strcmp(s1, s2); | |
56 | ||
57 | if (rv < 0) | |
58 | return (-1); | |
59 | ||
60 | if (rv > 0) | |
61 | return (1); | |
62 | ||
63 | return (0); | |
64 | } | |
65 | ||
66 | /* | |
67 | * Return a new string container, or NULL on error. | |
68 | */ | |
69 | zed_strings_t * | |
70 | zed_strings_create(void) | |
71 | { | |
72 | zed_strings_t *zsp; | |
73 | ||
8cb8cf91 | 74 | zsp = calloc(1, sizeof (*zsp)); |
9e246ac3 CD |
75 | if (!zsp) |
76 | return (NULL); | |
77 | ||
9e246ac3 CD |
78 | avl_create(&zsp->tree, _zed_strings_node_compare, |
79 | sizeof (zed_strings_node_t), offsetof(zed_strings_node_t, node)); | |
80 | ||
81 | zsp->iteratorp = NULL; | |
82 | return (zsp); | |
83 | } | |
84 | ||
85 | /* | |
854f30a9 CD |
86 | * Destroy the string node [np]. |
87 | */ | |
88 | static void | |
89 | _zed_strings_node_destroy(zed_strings_node_t *np) | |
90 | { | |
91 | if (!np) | |
92 | return; | |
93 | ||
94 | if (np->key) { | |
95 | if (np->key != np->val) | |
96 | free(np->key); | |
97 | np->key = NULL; | |
98 | } | |
99 | if (np->val) { | |
100 | free(np->val); | |
101 | np->val = NULL; | |
102 | } | |
103 | free(np); | |
104 | } | |
105 | ||
106 | /* | |
107 | * Return a new string node for storing the string [val], or NULL on error. | |
108 | * If [key] is specified, it will be used to index the node; otherwise, | |
109 | * the string [val] will be used. | |
110 | */ | |
111 | zed_strings_node_t * | |
112 | _zed_strings_node_create(const char *key, const char *val) | |
113 | { | |
114 | zed_strings_node_t *np; | |
115 | ||
116 | assert(val != NULL); | |
117 | ||
118 | np = calloc(1, sizeof (*np)); | |
119 | if (!np) | |
120 | return (NULL); | |
121 | ||
122 | np->val = strdup(val); | |
123 | if (!np->val) | |
124 | goto nomem; | |
125 | ||
126 | if (key) { | |
127 | np->key = strdup(key); | |
128 | if (!np->key) | |
129 | goto nomem; | |
130 | } else { | |
131 | np->key = np->val; | |
132 | } | |
133 | return (np); | |
134 | ||
135 | nomem: | |
136 | _zed_strings_node_destroy(np); | |
137 | return (NULL); | |
138 | } | |
139 | ||
140 | /* | |
141 | * Destroy the string container [zsp] and all nodes within. | |
9e246ac3 CD |
142 | */ |
143 | void | |
144 | zed_strings_destroy(zed_strings_t *zsp) | |
145 | { | |
146 | void *cookie; | |
147 | zed_strings_node_t *np; | |
148 | ||
149 | if (!zsp) | |
150 | return; | |
151 | ||
152 | cookie = NULL; | |
153 | while ((np = avl_destroy_nodes(&zsp->tree, &cookie))) | |
854f30a9 | 154 | _zed_strings_node_destroy(np); |
9e246ac3 CD |
155 | |
156 | avl_destroy(&zsp->tree); | |
157 | free(zsp); | |
158 | } | |
159 | ||
160 | /* | |
854f30a9 CD |
161 | * Add a copy of the string [s] indexed by [key] to the container [zsp]. |
162 | * If [key] already exists within the container [zsp], it will be replaced | |
163 | * with the new string [s]. | |
164 | * If [key] is NULL, the string [s] will be used as the key. | |
9e246ac3 | 165 | * Return 0 on success, or -1 on error. |
9e246ac3 CD |
166 | */ |
167 | int | |
854f30a9 | 168 | zed_strings_add(zed_strings_t *zsp, const char *key, const char *s) |
9e246ac3 | 169 | { |
854f30a9 | 170 | zed_strings_node_t *newp, *oldp; |
9e246ac3 CD |
171 | |
172 | if (!zsp || !s) { | |
173 | errno = EINVAL; | |
174 | return (-1); | |
175 | } | |
854f30a9 CD |
176 | if (key == s) |
177 | key = NULL; | |
178 | ||
179 | newp = _zed_strings_node_create(key, s); | |
180 | if (!newp) | |
9e246ac3 CD |
181 | return (-1); |
182 | ||
854f30a9 CD |
183 | oldp = avl_find(&zsp->tree, newp, NULL); |
184 | if (oldp) { | |
185 | avl_remove(&zsp->tree, oldp); | |
186 | _zed_strings_node_destroy(oldp); | |
187 | } | |
188 | avl_add(&zsp->tree, newp); | |
9e246ac3 CD |
189 | return (0); |
190 | } | |
191 | ||
192 | /* | |
193 | * Return the first string in container [zsp]. | |
194 | * Return NULL if there are no strings, or on error. | |
195 | * This can be called multiple times to re-traverse [zsp]. | |
196 | * XXX: Not thread-safe. | |
197 | */ | |
198 | const char * | |
199 | zed_strings_first(zed_strings_t *zsp) | |
200 | { | |
201 | if (!zsp) { | |
202 | errno = EINVAL; | |
203 | return (NULL); | |
204 | } | |
205 | zsp->iteratorp = avl_first(&zsp->tree); | |
206 | if (!zsp->iteratorp) | |
207 | return (NULL); | |
208 | ||
02730c33 | 209 | return (((zed_strings_node_t *)zsp->iteratorp)->val); |
9e246ac3 CD |
210 | |
211 | } | |
212 | ||
213 | /* | |
214 | * Return the next string in container [zsp]. | |
215 | * Return NULL after the last string, or on error. | |
216 | * This must be called after zed_strings_first(). | |
217 | * XXX: Not thread-safe. | |
218 | */ | |
219 | const char * | |
220 | zed_strings_next(zed_strings_t *zsp) | |
221 | { | |
222 | if (!zsp) { | |
223 | errno = EINVAL; | |
224 | return (NULL); | |
225 | } | |
226 | if (!zsp->iteratorp) | |
227 | return (NULL); | |
228 | ||
229 | zsp->iteratorp = AVL_NEXT(&zsp->tree, zsp->iteratorp); | |
230 | if (!zsp->iteratorp) | |
231 | return (NULL); | |
232 | ||
854f30a9 | 233 | return (((zed_strings_node_t *)zsp->iteratorp)->val); |
9e246ac3 CD |
234 | } |
235 | ||
236 | /* | |
237 | * Return the number of strings in container [zsp], or -1 on error. | |
238 | */ | |
239 | int | |
240 | zed_strings_count(zed_strings_t *zsp) | |
241 | { | |
242 | if (!zsp) { | |
243 | errno = EINVAL; | |
244 | return (-1); | |
245 | } | |
246 | return (avl_numnodes(&zsp->tree)); | |
247 | } |