/* * The contents of this file are subject to the AOLserver Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://aolserver.com/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is AOLserver Code and related documentation * distributed by AOL. * * The Initial Developer of the Original Code is America Online, * Inc. Portions created by AOL are Copyright (C) 1999 America Online, * Inc. All Rights Reserved. * * Alternatively, the contents of this file may be used under the terms * of the GNU General Public License (the "GPL"), in which case the * provisions of GPL are applicable instead of those above. If you wish * to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the * License, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the GPL. * If you do not delete the provisions above, a recipient may use your * version of this file under either the License or the GPL. */ /* * set.c -- * * Implements the Ns_Set data type. */ static const char *RCSID = "@(#) $Header: /cvsroot/aolserver/aolserver/nsd/set.c,v 1.4 2000/08/25 13:49:57 jgdavidson Exp $, compiled: " __DATE__ " " __TIME__; #include "nsd.h" /* *---------------------------------------------------------------------- * * Ns_SetUpdate -- * * Remove a tuple and re-add it. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Ns_SetUpdate(Ns_Set *set, char *key, char *value) { Ns_SetDeleteKey(set, key); Ns_SetPut(set, key, value); } /* *---------------------------------------------------------------------- * * Ns_SetCreate -- * * Initialize a new set. * * Results: * A pointer to a new set. * * Side effects: * Memory is allocated; free with Ns_SetFree. * *---------------------------------------------------------------------- */ Ns_Set * Ns_SetCreate(char *name) { Ns_Set *setPtr; setPtr = ns_malloc(sizeof(Ns_Set)); setPtr->size = 0; setPtr->maxSize = 10; setPtr->name = ns_strcopy(name); setPtr->fields = ns_malloc(sizeof(Ns_SetField) * setPtr->maxSize); return setPtr; } /* *---------------------------------------------------------------------- * * Ns_SetFree -- * * Free a set and its associated data with ns_free. * * Results: * None. * * Side effects: * Will free both the Ns_Set structure AND its tuples. * *---------------------------------------------------------------------- */ void Ns_SetFree(Ns_Set *set) { int i; if (set != NULL) { for (i = 0; i < set->size; ++i) { ns_free(set->fields[i].name); ns_free(set->fields[i].value); } ns_free(set->fields); ns_free(set->name); ns_free(set); } } /* *---------------------------------------------------------------------- * * Ns_SetPut -- * * Insert a tuple into an existing set. * * Results: * The index number of the new tuple. * * Side effects: * The key/value will be strdup'ed. * *---------------------------------------------------------------------- */ int Ns_SetPut(Ns_Set *set, char *key, char *value) { int index; index = set->size; set->size++; if (set->size > set->maxSize) { set->maxSize = set->size * 2; set->fields = ns_realloc(set->fields, sizeof(Ns_SetField) * set->maxSize); } set->fields[index].name = ns_strcopy(key); set->fields[index].value = ns_strcopy(value); return index; } /* *---------------------------------------------------------------------- * * Ns_SetUniqueCmp -- * * Using the comparison function, see if multiple keys match * key. * * Results: * NS_FALSE: multiple keys match key * NS_TRUE: 0 or 1 keys match key. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Ns_SetUniqueCmp(Ns_Set *set, char *key, int (*cmp) (char *s1, char *s2)) { int i; char *name; int found; found = 0; for (i = 0; i < set->size; ++i) { name = set->fields[i].name; if ((key == NULL && name == NULL) || (key != NULL && name != NULL && ((*cmp) (key, name)) == 0)) { if (found) { return NS_FALSE; } found = 1; } } return NS_TRUE; } /* *---------------------------------------------------------------------- * * Ns_SetFindCmp -- * * Returns the index of a tuple matching key, using a comparison * function callback. * * Results: * A tuple index or -1 if no matches. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Ns_SetFindCmp(Ns_Set *set, char *key, int (*cmp) (char *s1, char *s2)) { int i; char *name; for (i = 0; i < set->size; ++i) { name = set->fields[i].name; if ((key == NULL && name == NULL) || (key != NULL && name != NULL && ((*cmp) (key, name)) == 0)) { return i; } } return -1; } /* *---------------------------------------------------------------------- * * Ns_SetGetCmp -- * * Returns the value of a tuple matching key, using a comparison * function callback. * * Results: * A value or NULL if no matches. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * Ns_SetGetCmp(Ns_Set *set, char *key, int (*cmp) (char *s1, char *s2)) { int i; i = Ns_SetFindCmp(set, key, cmp); if (i == -1) { return NULL; } return set->fields[i].value; } /* *---------------------------------------------------------------------- * * Ns_SetUnique -- * * Check if a key in a set is unique (case sensitive). * * Results: * NS_TRUE if unique, NS_FALSE if not. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Ns_SetUnique(Ns_Set *set, char *key) { return Ns_SetUniqueCmp(set, key, (int (*) (char *, char *)) strcmp); } /* *---------------------------------------------------------------------- * * Ns_SetIUnique -- * * Check if a key in a set is unique (case insensitive). * * Results: * NS_TRUE if unique, NS_FALSE if not. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Ns_SetIUnique(Ns_Set *set, char *key) { return Ns_SetUniqueCmp(set, key, (int (*) (char *, char *)) strcasecmp); } /* *---------------------------------------------------------------------- * * Ns_SetFind -- * * Locate the index of a field in a set (case sensitive) * * Results: * A field index or -1 if not found. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Ns_SetFind(Ns_Set *set, char *key) { return Ns_SetFindCmp(set, key, (int (*) (char *, char *)) strcmp); } /* *---------------------------------------------------------------------- * * Ns_SetIFind -- * * Locate the index of a field in a set (case insensitive) * * Results: * A field index or -1 if not found. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Ns_SetIFind(Ns_Set *set, char *key) { return Ns_SetFindCmp(set, key, (int (*) (char *, char *)) strcasecmp); } /* *---------------------------------------------------------------------- * * Ns_SetGet -- * * Return the value associated with a key, case sensitive. * * Results: * A value or NULL if key not found. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * Ns_SetGet(Ns_Set *set, char *key) { return Ns_SetGetCmp(set, key, (int (*) (char *, char *)) strcmp); } /* *---------------------------------------------------------------------- * * Ns_SetIGet -- * * Return the value associated with a key, case insensitive. * * Results: * A value or NULL if key not found. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * Ns_SetIGet(Ns_Set *set, char *key) { return Ns_SetGetCmp(set, key, (int (*) (char *, char *)) strcasecmp); } /* *---------------------------------------------------------------------- * * Ns_SetTrunc -- * * Remove all tuples after 'size' * * Results: * None. * * Side effects: * Will free tuple memory. * *---------------------------------------------------------------------- */ void Ns_SetTrunc(Ns_Set *set, int size) { if (size < set->size) { int index; for (index = size; index < set->size; index++) { ns_free(set->fields[index].name); ns_free(set->fields[index].value); } set->size = size; } } /* *---------------------------------------------------------------------- * * Ns_SetDelete -- * * Delete a tuple from a set. * * Results: * None. * * Side effects: * Will free tuple memory. * *---------------------------------------------------------------------- */ void Ns_SetDelete(Ns_Set *set, int index) { if ((index != -1) && (index < set->size)) { int i; ns_free(set->fields[index].name); ns_free(set->fields[index].value); for (i = index; i < set->size; ++i) { set->fields[i].name = set->fields[i + 1].name; set->fields[i].value = set->fields[i + 1].value; } --set->size; } } /* *---------------------------------------------------------------------- * * Ns_SetPutValue -- * * Set the value for a given tuple. * * Results: * None. * * Side effects: * Will free the old value dup the new value. * *---------------------------------------------------------------------- */ void Ns_SetPutValue(Ns_Set *set, int index, char *value) { if ((index != -1) && (index < set->size)) { ns_free(set->fields[index].value); set->fields[index].value = ns_strcopy(value); } } /* *---------------------------------------------------------------------- * * Ns_SetDeleteKey -- * * Delete a tuple from the set (case sensitive). * * Results: * None. * * Side effects: * Will free tuple memory. * *---------------------------------------------------------------------- */ void Ns_SetDeleteKey(Ns_Set *set, char *key) { Ns_SetDelete(set, Ns_SetFind(set, key)); } /* *---------------------------------------------------------------------- * * Ns_SetIDeleteKey -- * * Delete a tuple from the set (case insensitive). * * Results: * None. * * Side effects: * Will free tuple memory. * *---------------------------------------------------------------------- */ void Ns_SetIDeleteKey(Ns_Set *set, char *key) { Ns_SetDelete(set, Ns_SetIFind(set, key)); } /* *---------------------------------------------------------------------- * * Ns_SetListFind -- * * In a null-terminated array of sets, find the set with the * given name. * * Results: * A set, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ Ns_Set * Ns_SetListFind(Ns_Set **sets, char *name) { while (*sets != NULL) { if (name == NULL) { if ((*sets)->name == NULL) { return (*sets); } } else { if ((*sets)->name != NULL && STREQ((*sets)->name, name)) { return (*sets); } } ++sets; } return NULL; } /* *---------------------------------------------------------------------- * * Ns_SetSplit -- * * Split a set into an array of new sets. This assumes that each * key name in the fields of a set contains a separating * character. The fields of the set are partitioned into new * sets whose set names are the characters before the separator * and whose field key names are the characters after the * separator. * * Results: * A new set. * * Side effects: * Will allocate a new set and tuples. * *---------------------------------------------------------------------- */ Ns_Set ** Ns_SetSplit(Ns_Set *set, char sep) { int i; Ns_DString ds; Ns_Set *end = NULL; Ns_DStringInit(&ds); Ns_DStringNAppend(&ds, (char *) &end, sizeof(Ns_Set *)); for (i = 0; i < set->size; ++i) { Ns_Set *next; char *name; char *key; key = strchr(set->fields[i].name, sep); if (key != NULL) { *key++ = '\0'; name = set->fields[i].name; } else { key = set->fields[i].name; name = NULL; } next = Ns_SetListFind((Ns_Set **) ds.string, name); if (next == NULL) { Ns_Set **sp; next = Ns_SetCreate(name); sp = (Ns_Set **) (ds.string + ds.length - sizeof(Ns_Set *)); *sp = next; Ns_DStringNAppend(&ds, (char *) &end, sizeof(Ns_Set *)); } Ns_SetPut(next, key, set->fields[i].value); if (name != NULL) { *--key = sep; } } return (Ns_Set **) Ns_DStringExport(&ds); } /* *---------------------------------------------------------------------- * * Ns_SetListFree -- * * Free a null-terminated array of sets. * * Results: * None. * * Side effects: * Will free all sets in the array and their tuples. * *---------------------------------------------------------------------- */ void Ns_SetListFree(Ns_Set **sets) { Ns_Set **s; s = sets; while (*s != NULL) { Ns_SetFree(*s); ++s; } ns_free(sets); } /* *---------------------------------------------------------------------- * * Ns_SetMerge -- * * Combine the 'low' set into the 'high' set. * * Results: * None. * * Side effects: * Will add tuples to 'high'. * *---------------------------------------------------------------------- */ void Ns_SetMerge(Ns_Set *high, Ns_Set *low) { int i,j; for (i = 0; i < low->size; ++i) { j = Ns_SetFind(high, low->fields[i].name); if (j == -1) { Ns_SetPut(high, low->fields[i].name, low->fields[i].value); } } } /* *---------------------------------------------------------------------- * * Ns_SetCopy -- * * Make a duplicate of a set. * * Results: * A new set. * * Side effects: * Will copy tuples and alloc new memory for them, too. * *---------------------------------------------------------------------- */ Ns_Set * Ns_SetCopy(Ns_Set *old) { int i; Ns_Set *new; if (old == NULL) { return NULL; } new = Ns_SetCreate(old->name); for (i = 0; i < old->size; ++i) { Ns_SetPut(new, old->fields[i].name, old->fields[i].value); } return new; } /* *---------------------------------------------------------------------- * * Ns_SetMove -- * * Moves the data from one set to another, truncating the "from" * set. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Ns_SetMove(Ns_Set *to, Ns_Set *from) { int i; for (i = 0; i < from->size; i++) { Ns_SetPut(to, from->fields[i].name, from->fields[i].value); } Ns_SetTrunc(from, 0); } /* *---------------------------------------------------------------------- * * Ns_SetPrint -- * * Dump the contents of a set to stderr. * * Results: * None. * * Side effects: * Will write to stderr. * *---------------------------------------------------------------------- */ void Ns_SetPrint(Ns_Set *set) { int i; fprintf(stderr, "%s:\n", set->name ? set->name : ""); for (i = 0; i < set->size; ++i) { if (set->fields[i].name == NULL) { fprintf(stderr, "\t(null) = "); } else { fprintf(stderr, "\t%s = ", set->fields[i].name); } if (set->fields[i].value == NULL) { fprintf(stderr, "(null)\n"); } else { fprintf(stderr, "%s\n", set->fields[i].value); } } }