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