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