/*
* This file is part of the ZFS Event Daemon (ZED)
* for ZFS on Linux (ZoL) .
* Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
* Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
* Refer to the ZoL git commit log for authoritative copyright attribution.
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License Version 1.0 (CDDL-1.0).
* You can obtain a copy of the license from the top-level file
* "OPENSOLARIS.LICENSE" or at .
* You may not use this file except in compliance with the license.
*/
#include
#include
#include
#include
#include
#include
#include
#include "zed_strings.h"
struct zed_strings {
avl_tree_t tree;
avl_node_t *iteratorp;
};
struct zed_strings_node {
avl_node_t node;
char *key;
char *val;
};
typedef struct zed_strings_node zed_strings_node_t;
/*
* Compare zed_strings_node_t nodes [x1] and [x2].
* As required for the AVL tree, return -1 for <, 0 for ==, and +1 for >.
*/
static int
_zed_strings_node_compare(const void *x1, const void *x2)
{
const char *s1;
const char *s2;
int rv;
assert(x1 != NULL);
assert(x2 != NULL);
s1 = ((const zed_strings_node_t *) x1)->key;
assert(s1 != NULL);
s2 = ((const zed_strings_node_t *) x2)->key;
assert(s2 != NULL);
rv = strcmp(s1, s2);
if (rv < 0)
return (-1);
if (rv > 0)
return (1);
return (0);
}
/*
* Return a new string container, or NULL on error.
*/
zed_strings_t *
zed_strings_create(void)
{
zed_strings_t *zsp;
zsp = calloc(1, sizeof (*zsp));
if (!zsp)
return (NULL);
avl_create(&zsp->tree, _zed_strings_node_compare,
sizeof (zed_strings_node_t), offsetof(zed_strings_node_t, node));
zsp->iteratorp = NULL;
return (zsp);
}
/*
* Destroy the string node [np].
*/
static void
_zed_strings_node_destroy(zed_strings_node_t *np)
{
if (!np)
return;
if (np->key) {
if (np->key != np->val)
free(np->key);
np->key = NULL;
}
if (np->val) {
free(np->val);
np->val = NULL;
}
free(np);
}
/*
* Return a new string node for storing the string [val], or NULL on error.
* If [key] is specified, it will be used to index the node; otherwise,
* the string [val] will be used.
*/
static zed_strings_node_t *
_zed_strings_node_create(const char *key, const char *val)
{
zed_strings_node_t *np;
assert(val != NULL);
np = calloc(1, sizeof (*np));
if (!np)
return (NULL);
np->val = strdup(val);
if (!np->val)
goto nomem;
if (key) {
np->key = strdup(key);
if (!np->key)
goto nomem;
} else {
np->key = np->val;
}
return (np);
nomem:
_zed_strings_node_destroy(np);
return (NULL);
}
/*
* Destroy the string container [zsp] and all nodes within.
*/
void
zed_strings_destroy(zed_strings_t *zsp)
{
void *cookie;
zed_strings_node_t *np;
if (!zsp)
return;
cookie = NULL;
while ((np = avl_destroy_nodes(&zsp->tree, &cookie)))
_zed_strings_node_destroy(np);
avl_destroy(&zsp->tree);
free(zsp);
}
/*
* Add a copy of the string [s] indexed by [key] to the container [zsp].
* If [key] already exists within the container [zsp], it will be replaced
* with the new string [s].
* If [key] is NULL, the string [s] will be used as the key.
* Return 0 on success, or -1 on error.
*/
int
zed_strings_add(zed_strings_t *zsp, const char *key, const char *s)
{
zed_strings_node_t *newp, *oldp;
if (!zsp || !s) {
errno = EINVAL;
return (-1);
}
if (key == s)
key = NULL;
newp = _zed_strings_node_create(key, s);
if (!newp)
return (-1);
oldp = avl_find(&zsp->tree, newp, NULL);
if (oldp) {
avl_remove(&zsp->tree, oldp);
_zed_strings_node_destroy(oldp);
}
avl_add(&zsp->tree, newp);
return (0);
}
/*
* Return the first string in container [zsp].
* Return NULL if there are no strings, or on error.
* This can be called multiple times to re-traverse [zsp].
* XXX: Not thread-safe.
*/
const char *
zed_strings_first(zed_strings_t *zsp)
{
if (!zsp) {
errno = EINVAL;
return (NULL);
}
zsp->iteratorp = avl_first(&zsp->tree);
if (!zsp->iteratorp)
return (NULL);
return (((zed_strings_node_t *)zsp->iteratorp)->val);
}
/*
* Return the next string in container [zsp].
* Return NULL after the last string, or on error.
* This must be called after zed_strings_first().
* XXX: Not thread-safe.
*/
const char *
zed_strings_next(zed_strings_t *zsp)
{
if (!zsp) {
errno = EINVAL;
return (NULL);
}
if (!zsp->iteratorp)
return (NULL);
zsp->iteratorp = AVL_NEXT(&zsp->tree, zsp->iteratorp);
if (!zsp->iteratorp)
return (NULL);
return (((zed_strings_node_t *)zsp->iteratorp)->val);
}
/*
* Return the number of strings in container [zsp], or -1 on error.
*/
int
zed_strings_count(zed_strings_t *zsp)
{
if (!zsp) {
errno = EINVAL;
return (-1);
}
return (avl_numnodes(&zsp->tree));
}