/* $Id$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "fdm.h"
void *strb_address(struct strb *, const char *);
void
strb_create(struct strb **sbp)
{
*sbp = xcalloc(1, STRBOFFSET);
strb_clear(sbp);
}
void
strb_clear(struct strb **sbp)
{
struct strb *sb = *sbp;
sb->ent_used = 0;
sb->ent_max = STRBENTRIES;
sb->str_size = STRBBLOCK;
sb->str_used = 0;
sb = *sbp = xrealloc(sb, 1, STRB_SIZE(sb));
memset(STRB_BASE(sb), 0, sb->str_size + STRB_ENTSIZE(sb));
}
void
strb_destroy(struct strb **sbp)
{
xfree(*sbp);
*sbp = NULL;
}
void
strb_dump(struct strb *sb, const char *prefix, void (*p)(const char *, ...))
{
struct strbent *sbe;
u_int i;
for (i = 0; i < sb->ent_used; i++) {
sbe = STRB_ENTRY(sb, i);
p("%s: %s: %s", prefix, STRB_KEY(sb, sbe), STRB_VALUE(sb, sbe));
}
}
void printflike3
strb_add(struct strb **sbp, const char *key, const char *value, ...)
{
va_list ap;
va_start(ap, value);
strb_vadd(sbp, key, value, ap);
va_end(ap);
}
void
strb_vadd(struct strb **sbp, const char *key, const char *value, va_list ap)
{
struct strb *sb = *sbp;
size_t size, keylen, valuelen;
u_int n;
struct strbent sbe, *sbep;
va_list aq;
keylen = strlen(key) + 1;
va_copy(aq, ap);
valuelen = xvsnprintf(NULL, 0, value, aq) + 1;
va_end(aq);
size = sb->str_size;
while (sb->str_size - sb->str_used < keylen + valuelen) {
if (STRB_SIZE(sb) > SIZE_MAX / 2)
fatalx("size too large");
sb->str_size *= 2;
}
if (size != sb->str_size) {
sb = *sbp = xrealloc(sb, 1, STRB_SIZE(sb));
memmove(
STRB_ENTBASE(sb), STRB_BASE(sb) + size, STRB_ENTSIZE(sb));
memset(STRB_BASE(sb) + size, 0, sb->str_size - size);
}
sbep = strb_address(sb, key);
if (sbep == NULL) {
if (sb->ent_used > sb->ent_max) {
/* Allocate some more entries. */
n = sb->ent_max;
size = STRB_SIZE(sb);
if (sb->ent_max > UINT_MAX / 2)
fatalx("ent_max too large");
sb->ent_max *= 2;
if (STRB_SIZE(sb) < size)
fatalx("size too large");
sb = *sbp = xrealloc(sb, 1, STRB_SIZE(sb));
memset(STRB_ENTRY(sb, n), 0, STRB_ENTSIZE(sb) / 2);
}
sbep = STRB_ENTRY(sb, sb->ent_used);
sb->ent_used++;
sbe.key = sb->str_used;
memcpy(STRB_KEY(sb, &sbe), key, keylen);
sb->str_used += keylen;
} else
memcpy(&sbe, sbep, sizeof sbe);
sbe.value = sb->str_used;
xvsnprintf(STRB_VALUE(sb, &sbe), valuelen, value, ap);
sb->str_used += valuelen;
memcpy(sbep, &sbe, sizeof sbe);
}
void *
strb_address(struct strb *sb, const char *key)
{
struct strbent sbe;
u_int i;
for (i = 0; i < sb->ent_used; i++) {
memcpy(&sbe, STRB_ENTRY(sb, i), sizeof sbe);
if (strcmp(key, STRB_KEY(sb, &sbe)) == 0)
return (STRB_ENTRY(sb, i));
}
return (NULL);
}
struct strbent *
strb_find(struct strb *sb, const char *key)
{
static struct strbent sbe;
void *sbep;
sbep = strb_address(sb, key);
if (sbep == NULL)
return (NULL);
memcpy(&sbe, sbep, sizeof sbe);
return (&sbe);
}
struct strbent *
strb_match(struct strb *sb, const char *patt)
{
static struct strbent sbe;
u_int i;
for (i = 0; i < sb->ent_used; i++) {
memcpy(&sbe, STRB_ENTRY(sb, i), sizeof sbe);
if (fnmatch(patt, STRB_KEY(sb, &sbe), 0) == 0)
return (&sbe);
}
return (NULL);
}