#include <sys/types.h>
#if defined(_KERNEL)
#include <sys/kmem.h>
#include <sys/systm.h>
static void *
strlist_alloc(size_t const size)
{
return kmem_zalloc(size, KM_SLEEP);
}
static void
strlist_free(void * const v, size_t const size)
{
kmem_free(v, size);
}
#elif defined(_STANDALONE)
#include <lib/libkern/libkern.h>
#include <lib/libsa/stand.h>
static void *
strlist_alloc(size_t const size)
{
char *cp = alloc(size);
if (cp != NULL) {
memset(cp, 0, size);
}
return cp;
}
static void
strlist_free(void * const v, size_t const size)
{
dealloc(v, size);
}
#else
#include <stdlib.h>
#include <string.h>
extern int pmatch(const char *, const char *, const char **);
static void *
strlist_alloc(size_t const size)
{
return calloc(1, size);
}
static void
strlist_free(void * const v, size_t const size __unused)
{
free(v);
}
#endif
#include "strlist.h"
const char *
strlist_next(const char * const sl, size_t const slsize, size_t * const cursorp)
{
if (sl == NULL || slsize == 0 || cursorp == NULL) {
return NULL;
}
size_t cursor = *cursorp;
if (cursor >= slsize) {
return NULL;
}
const char *cp = sl + cursor;
*cursorp = cursor + strlen(cp) + 1;
return cp;
}
unsigned int
strlist_count(const char *sl, size_t slsize)
{
if (sl == NULL || slsize == 0) {
return 0;
}
size_t cursize;
unsigned int count;
for (count = 0; slsize != 0;
count++, sl += cursize, slsize -= cursize) {
cursize = strlen(sl) + 1;
}
return count;
}
const char *
strlist_string(const char * sl, size_t slsize, unsigned int const idx)
{
if (sl == NULL || slsize == 0) {
return NULL;
}
size_t cursize;
unsigned int i;
for (i = 0; slsize != 0; i++, slsize -= cursize, sl += cursize) {
cursize = strlen(sl) + 1;
if (i == idx) {
return sl;
}
}
return NULL;
}
static bool
match_strcmp(const char * const s1, const char * const s2)
{
return strcmp(s1, s2) == 0;
}
#if !defined(_STANDALONE)
static bool
match_pmatch(const char * const s1, const char * const s2)
{
return pmatch(s1, s2, NULL) == 2;
}
#endif
static bool
strlist_match_internal(const char * const sl, size_t slsize,
const char * const str, int * const indexp, unsigned int * const countp,
bool (*match_fn)(const char *, const char *))
{
const char *cp;
size_t l;
int i;
bool rv = false;
if (sl == NULL || slsize == 0) {
return false;
}
cp = sl;
for (i = 0; slsize != 0;
l = strlen(cp) + 1, slsize -= l, cp += l, i++) {
if (rv) {
continue;
}
if ((*match_fn)(cp, str)) {
*indexp = i;
rv = true;
if (countp == NULL) {
break;
}
}
}
if (countp != NULL) {
*countp = i;
}
return rv;
}
int
strlist_match(const char * const sl, size_t const slsize,
const char * const str)
{
unsigned int count;
int idx = 0 ;
if (strlist_match_internal(sl, slsize, str, &idx, &count,
match_strcmp)) {
return count - idx;
}
return 0;
}
#if !defined(_STANDALONE)
int
strlist_pmatch(const char * const sl, size_t const slsize,
const char * const pattern)
{
unsigned int count;
int idx = 0;
if (strlist_match_internal(sl, slsize, pattern, &idx, &count,
match_pmatch)) {
return count - idx;
}
return 0;
}
#endif
int
strlist_index(const char * const sl, size_t const slsize,
const char * const str)
{
int idx;
if (strlist_match_internal(sl, slsize, str, &idx, NULL,
match_strcmp)) {
return idx;
}
return -1;
}
bool
strlist_append(char ** const slp, size_t * const slsizep,
const char * const str)
{
size_t const slsize = *slsizep;
char * const sl = *slp;
size_t const addsize = strlen(str) + 1;
size_t const newsize = slsize + addsize;
char * const newbuf = strlist_alloc(newsize);
if (newbuf == NULL) {
return false;
}
if (sl != NULL) {
memcpy(newbuf, sl, slsize);
}
memcpy(newbuf + slsize, str, addsize);
if (sl != NULL) {
strlist_free(sl, slsize);
}
*slp = newbuf;
*slsizep = newsize;
return true;
}
#ifdef STRLIST_TEST
static char nice_blob[] = "zero\0one\0two\0three\0four\0five";
static char gross_blob[] = "zero\0\0two\0\0four\0\0";
#include <assert.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
const char *sl;
size_t slsize;
size_t cursor;
const char *cp;
size_t size;
sl = nice_blob;
slsize = sizeof(nice_blob);
printf("Testing basic properties.\n");
assert(strlist_count(sl, slsize) == 6);
printf("Testing enumeration.\n");
cursor = 0;
assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
assert(strcmp(cp, "zero") == 0);
assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
assert(strcmp(cp, "one") == 0);
assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
assert(strcmp(cp, "two") == 0);
assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
assert(strcmp(cp, "three") == 0);
assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
assert(strcmp(cp, "four") == 0);
assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
assert(strcmp(cp, "five") == 0);
assert((cp = strlist_next(sl, slsize, &cursor)) == NULL);
printf("Testing weighted matching.\n");
assert(strlist_match(sl, slsize, "non-existent") == 0);
assert(strlist_match(sl, slsize, "zero") == 6);
assert(strlist_match(sl, slsize, "one") == 5);
assert(strlist_match(sl, slsize, "two") == 4);
assert(strlist_match(sl, slsize, "three") == 3);
assert(strlist_match(sl, slsize, "four") == 2);
assert(strlist_match(sl, slsize, "five") == 1);
printf("Testing pattern matching.\n");
assert(strlist_pmatch(sl, slsize, "t?o") == 4);
assert(strlist_pmatch(sl, slsize, "f[a-o][o-u][a-z]") == 2);
printf("Testing index return.\n");
assert(strlist_index(sl, slsize, "non-existent") == -1);
assert(strlist_index(sl, slsize, "zero") == 0);
assert(strlist_index(sl, slsize, "one") == 1);
assert(strlist_index(sl, slsize, "two") == 2);
assert(strlist_index(sl, slsize, "three") == 3);
assert(strlist_index(sl, slsize, "four") == 4);
assert(strlist_index(sl, slsize, "five") == 5);
printf("Testing string-at-index.\n");
assert(strcmp(strlist_string(sl, slsize, 0), "zero") == 0);
assert(strcmp(strlist_string(sl, slsize, 1), "one") == 0);
assert(strcmp(strlist_string(sl, slsize, 2), "two") == 0);
assert(strcmp(strlist_string(sl, slsize, 3), "three") == 0);
assert(strcmp(strlist_string(sl, slsize, 4), "four") == 0);
assert(strcmp(strlist_string(sl, slsize, 5), "five") == 0);
assert(strlist_string(sl, slsize, 6) == NULL);
sl = gross_blob;
slsize = sizeof(gross_blob);
printf("Testing gross blob count.\n");
assert(strlist_count(sl, slsize) == 7);
printf("Testing gross blob indexing.\n");
assert(strcmp(strlist_string(sl, slsize, 0), "zero") == 0);
assert(strcmp(strlist_string(sl, slsize, 1), "") == 0);
assert(strcmp(strlist_string(sl, slsize, 2), "two") == 0);
assert(strcmp(strlist_string(sl, slsize, 3), "") == 0);
assert(strcmp(strlist_string(sl, slsize, 4), "four") == 0);
assert(strcmp(strlist_string(sl, slsize, 5), "") == 0);
assert(strcmp(strlist_string(sl, slsize, 6), "") == 0);
assert(strlist_string(sl, slsize, 7) == NULL);
printf("Testing creating a strlist.\n");
char *newsl = NULL;
size_t newslsize = 0;
assert(strlist_append(&newsl, &newslsize, "zero"));
assert(strlist_append(&newsl, &newslsize, "one"));
assert(strlist_append(&newsl, &newslsize, "two"));
assert(strlist_append(&newsl, &newslsize, "three"));
assert(strlist_append(&newsl, &newslsize, "four"));
assert(strlist_append(&newsl, &newslsize, "five"));
printf("Verifying new strlist.\n");
assert(strlist_count(newsl, newslsize) == 6);
assert(strcmp(strlist_string(newsl, newslsize, 0), "zero") == 0);
assert(strcmp(strlist_string(newsl, newslsize, 1), "one") == 0);
assert(strcmp(strlist_string(newsl, newslsize, 2), "two") == 0);
assert(strcmp(strlist_string(newsl, newslsize, 3), "three") == 0);
assert(strcmp(strlist_string(newsl, newslsize, 4), "four") == 0);
assert(strcmp(strlist_string(newsl, newslsize, 5), "five") == 0);
assert(strlist_string(newsl, newslsize, 6) == NULL);
assert(newslsize == sizeof(nice_blob));
assert(memcmp(newsl, nice_blob, newslsize) == 0);
printf("All tests completed successfully.\n");
return 0;
}
#endif