Skip to content

Commit

Permalink
Add keywordset module
Browse files Browse the repository at this point in the history
Add a utility module which can store a set of keywords. The set can be
created and update from a string and can be serialized into a string.

The string representation is a space-separated list of keywordis. Strings
created by this utility contain the keywords stored in the set sorted in
lexical order separated by a single space character.

Input strings used to create or update a keyword set contain keywords
separated by whitespace. Words from the string are added to the set
unless a word starts with '-' in which case it will be removed from the

Usage example:

    struct keywordset *kws = keywordset_new("xxx yyy")
    keywordset_update(kws, "-yyy aaaa")

    char *s = keywordset_get(kws):   // s now "aaaaa xxx"
    free(s);                         // caller must free()

    if (keywordset_ismember(kws,"xxx")) ... // true

    keywordset_free(kws);
  • Loading branch information
donald committed Apr 13, 2020
1 parent 181c5b5 commit 472ea70
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 0 deletions.
133 changes: 133 additions & 0 deletions keywordset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#include "keywordset.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "xmalloc.h"

#define KEYWORDSET_INITIAL_SLOTS (4-2)

struct keywordset {
int nr_slots;
int used;
char **names;
};

static int find_name(struct keywordset *kws, char *name, size_t len) {
int i;
int j;
for ( i = 0; i < kws->used ; i++ ) {
j = 0;
while(1) {
if (kws->names[i][j] == 0)
break;
if (kws->names[i][j] != name[j])
break;
j++;
if (j==len)
return i;
}
}
return -1;
}

static void expand(struct keywordset *kws) {
int new_slots=(kws->nr_slots+2)*2-2;
kws->names=realloc(kws->names,new_slots*sizeof(*kws->names));
kws->nr_slots=new_slots;
}

static void add_name(struct keywordset *kws, char *name, size_t len) {
int i=find_name(kws, name, len);
if (i>=0) {
free(kws->names[i]);
kws->names[i] = xstrndup(name, len);
} else {
if (kws->used == kws->nr_slots)
expand(kws);
kws->names[kws->used++] = xstrndup(name, len);
}
}

static void remove_name(struct keywordset *kws, char *name, size_t len) {
int i=find_name(kws, name, len);
if (i>=0) {
free(kws->names[i]);
memmove(&(kws->names[i]), &(kws->names[i+1]), (kws->used-i-1)*sizeof(*kws->names));
kws->used--;
}
}

void keywordset_update(struct keywordset *kws, char *input) {
char *c=input;
char *name_start;
int add;
while (*c) {
while (*c && isspace(*c))
c++;
if (*c == '-') {
add = 0;
c++;
} else
add = 1;
if (*c) {
name_start=c++;
while (*c && !isspace(*c))
c++;
if (add)
add_name(kws, name_start, c-name_start);
else
remove_name(kws, name_start, c-name_start);
}
}
}

struct keywordset *keywordset_new(char *input) {
struct keywordset *kws = xmalloc(sizeof(*kws));
kws->nr_slots = KEYWORDSET_INITIAL_SLOTS;
kws->used = 0;
kws->names = xmalloc(KEYWORDSET_INITIAL_SLOTS*sizeof(*kws->names));
if (input)
keywordset_update(kws, input);
return kws;
}

static int cmp(const void *a, const void *b) {
return strcmp(*(char **)a, *(char **)b);
}

char *keywordset_get(struct keywordset *kws) {
char **names=xmalloc(kws->used * sizeof(*names));
memcpy(names, kws->names, kws->used * sizeof(*names));
qsort(names, kws->used, sizeof(*names), cmp);
size_t len = 0;
int i;
for (i=0; i<kws->used; i++) {
len += strlen(names[i]);
}
size_t outlen = len + (kws->used >= 2 ? kws->used-1 : 0);
char *out=xmalloc(outlen + 1 );
char *p=out;
for ( i = 0 ; i < kws->used ; i++) {
p=stpcpy(p, names[i]);
*p++ = ' ';
}
out[outlen] = 0;
free(names);
return(out);
}

int keywordset_ismember(struct keywordset *kws, char *name) {
if (find_name(kws, name, strlen(name)) >= 0)
return 1;
else
return 0;
}

void keywordset_free(struct keywordset *kws) {
int i;
for ( i = 0 ; i < kws->used ; i++)
free(kws->names[i]);
free(kws->names);
free(kws);
}
10 changes: 10 additions & 0 deletions keywordset.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef _KEYWORDSET_H
#define _KEYWORDSET_H

struct keywordset *keywordset_new(char *input);
void keywordset_update(struct keywordset *kws, char *input);
char *keywordset_get(struct keywordset *kws);
int keywordset_ismember(struct keywordset *kwd, char *name);
void keywordset_free(struct keywordset *kws);

#endif
39 changes: 39 additions & 0 deletions test_keywordset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include <assert.h>
#include <string.h>
#include "keywordset.h"
#include <stdlib.h>

int main() {
struct keywordset *kws = keywordset_new("avaritia theinternet");
char *s;

keywordset_update(kws, "-avaritia deadbird null void xx XX");

s=keywordset_get(kws);
assert(strcmp(s, "XX deadbird null theinternet void xx")==0);
free(s);

assert(keywordset_ismember(kws, "avaritia") == 0);
assert(keywordset_ismember(kws, "deadpool") == 0);
assert(keywordset_ismember(kws, "deadbird") == 1);
assert(keywordset_ismember(kws, "theinternet") == 1);
assert(keywordset_ismember(kws, "DEADBIRD") == 0);
assert(keywordset_ismember(kws, "xx") == 1);
assert(keywordset_ismember(kws, "XX") == 1);

keywordset_free(kws);

kws=keywordset_new(NULL);
s=keywordset_get(kws);
assert(strcmp(s, "")==0);
free(s);
keywordset_free(kws);

kws=keywordset_new("");
s=keywordset_get(kws);
assert(strcmp(s, "")==0);
free(s);
keywordset_free(kws);


}

0 comments on commit 472ea70

Please sign in to comment.