lut.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2001 by Sun Microsystems, Inc.
* All rights reserved.
*
* logadm/lut.c -- simple lookup table module
*
* this file contains a very simple lookup table (lut) implementation.
* the tables only support insert & lookup, no delete, and can
* only be walked in lexical order. if the key already exists
* for something being inserted, the previous entry is simply
* replaced. the left-hand-side (lhs), which is the key, is
* copied into malloc'd memory. the right-hand-side (rhs), which
* is the datum, is not copied (in fact, the lut routines don't
* know the size or type of the datum, just the void * pointer to it).
*
* yea, this module could be much fancier and do much more, but
* the idea was to keep it really simple and just provide what
* was needed by logadm for options processing.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <strings.h>
#include "err.h"
#include "lut.h"
/* forward declarations of functions private to this module */
static void dooper(const char *lhs, void *rhs, void *arg);
/* info created by lut_add() and lut_dup(), private to this module */
struct lut {
struct lut *lut_left;
struct lut *lut_right;
char *lut_lhs; /* search key */
void *lut_rhs; /* the datum */
};
/*
* lut_add -- add an entry to the table
*
* use it like this:
* struct lut *root = NULL;
* root = lut_add(root, "key", value);
*
* the key string gets strdup'd by lut_add(), but the memory holding
* the *value should not be freed until the lut is freed by lut_free().
*/
struct lut *
lut_add(struct lut *root, const char *lhs, void *rhs)
{
int diff;
if (root == NULL) {
/* not in tree, create new node */
root = MALLOC(sizeof (*root));
root->lut_lhs = STRDUP(lhs);
root->lut_rhs = rhs;
root->lut_left = root->lut_right = NULL;
} else if ((diff = strcmp(root->lut_lhs, lhs)) == 0) {
/* already in tree, replace node */
root->lut_rhs = rhs;
} else if (diff > 0)
root->lut_left = lut_add(root->lut_left, lhs, rhs);
else
root->lut_right = lut_add(root->lut_right, lhs, rhs);
return (root);
}
/* helper function for lut_dup() */
static void
dooper(const char *lhs, void *rhs, void *arg)
{
struct lut **rootp = (struct lut **)arg;
*rootp = lut_add(*rootp, lhs, rhs);
}
/*
* lut_dup -- duplicate a lookup table
*
* caller is responsible for keeping track of how many tables are keeping
* pointers to the void * datum values.
*/
struct lut *
lut_dup(struct lut *root)
{
struct lut *ret = NULL;
lut_walk(root, dooper, &ret);
return (ret);
}
/*
* lut_lookup -- find an entry
*/
void *
lut_lookup(struct lut *root, const char *lhs)
{
int diff;
if (root == NULL)
return (NULL);
else if ((diff = strcmp(root->lut_lhs, lhs)) == 0)
return (root->lut_rhs);
else if (diff > 0)
return (lut_lookup(root->lut_left, lhs));
else
return (lut_lookup(root->lut_right, lhs));
}
/*
* lut_walk -- walk the table in lexical order
*/
void
lut_walk(struct lut *root,
void (*callback)(const char *lhs, void *rhs, void *arg), void *arg)
{
if (root) {
lut_walk(root->lut_left, callback, arg);
(*callback)(root->lut_lhs, root->lut_rhs, arg);
lut_walk(root->lut_right, callback, arg);
}
}
/*
* lut_free -- free a lut
*
* if callback is provided, it is called for each value in the table.
* it the values are things that the caller malloc'd, then you can do:
* lut_free(root, free);
*/
void
lut_free(struct lut *root, void (*callback)(void *rhs))
{
if (root) {
lut_free(root->lut_left, callback);
lut_free(root->lut_right, callback);
FREE(root->lut_lhs);
if (callback)
(*callback)(root->lut_rhs);
FREE(root);
}
}
#ifdef TESTMODULE
void
printer(const char *lhs, void *rhs, void *arg)
{
struct lut *root = (struct lut *)arg;
printf("<%s> <%s> (<%s>)\n", lhs, (char *)rhs,
(char *)lut_lookup(arg, lhs));
}
/*
* test main for lut module, usage: a.out [lhs[=rhs]...]
*/
main(int argc, char *argv[])
{
struct lut *r = NULL;
struct lut *dupr = NULL;
char *equals;
err_init(argv[0]);
setbuf(stdout, NULL);
for (argv++; *argv; argv++)
if ((equals = strchr(*argv, '=')) != NULL) {
*equals++ = '\0';
r = lut_add(r, *argv, equals);
} else
r = lut_add(r, *argv, "NULL");
printf("lut contains:\n");
lut_walk(r, printer, r);
dupr = lut_dup(r);
lut_free(r, NULL);
printf("dup lut contains:\n");
lut_walk(dupr, printer, dupr);
lut_free(dupr, NULL);
err_done(0);
}
#endif /* TESTMODULE */