-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathsetstr.c
134 lines (116 loc) · 2.84 KB
/
setstr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*-
* xnumon - monitor macOS for malicious activity
* https://www.roe.ch/xnumon
*
* Copyright (c) 2017-2018, Daniel Roethlisberger <[email protected]>.
* All rights reserved.
*
* Licensed under the Open Software License version 3.0.
*/
/*
* setstr - static set of strings
*/
#include "setstr.h"
#include "tommy_ext.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
typedef struct setstr_obj {
tommy_hashtable_node h_node;
char *str;
} setstr_obj_t;
static int
setstr_obj_cmp(const void *str, const void *vobj) {
const setstr_obj_t *obj = vobj;
return strcmp(obj->str, str);
}
static void
setstr_obj_free(void *vobj) {
setstr_obj_t *obj = vobj;
free(obj->str);
free(obj);
}
/*
* strings may be (and must be) NULL if buckets is 0.
* Guarantees to deep free strings even on errors.
*/
int
setstr_init(setstr_t *this, size_t buckets, char **strings) {
this->bucket_max = bucket_max_for_buckets(buckets);
this->size = buckets;
if (buckets == 0) {
assert(this->bucket_max == 0);
assert(strings == NULL);
return 0;
}
tommy_hashtable_init(&this->hashtable, this->bucket_max);
for (size_t i = 0; i < buckets; i++) {
setstr_obj_t *obj;
tommy_hash_t h;
if (setstr_contains(this, strings[i])) {
free(strings[i]);
continue;
}
obj = malloc(sizeof(setstr_obj_t));
if (!obj)
goto errout;
obj->str = strings[i];
strings[i] = NULL;
h = tommy_strhash_u32(0, obj->str);
tommy_hashtable_insert(&this->hashtable, &obj->h_node,
obj, h);
}
if (strings)
free(strings);
return 0;
errout:
for (size_t i = 0; i < buckets; i++) {
if (strings[i])
free(strings[i]);
}
if (strings)
free(strings);
return -1;
}
bool
setstr_contains(setstr_t *this, const char *str) {
if (this->bucket_max == 0)
return false;
return tommy_hashtable_search(&this->hashtable, setstr_obj_cmp, str,
tommy_strhash_u32(0, str));
}
/*
* Alterantive version of setstr_contains() that supports scopes.
*/
bool
setstr_contains3(setstr_t *this, const char *str, const char *scope) {
if (this->bucket_max == 0)
return false;
/* TODO May be further optimized by keeping track of whether setstr
* contains no scoped entries, or setstr contains only scoped entries,
* and skipping the respective lookup accordingly */
if (scope) {
const size_t sz = strlen(str) + strlen(scope) + 2;
char key[sz];
snprintf(key, sz, "%s@%s", str, scope);
if (setstr_contains(this, key))
return true;
}
return setstr_contains(this, str);
}
size_t
setstr_size(setstr_t *this) {
return this->size;
}
/*
* Safe to be called on a bzero'ed setstr_t that was never initialized with
* setstr_init().
*/
void
setstr_destroy(setstr_t *this) {
if (this->bucket_max != 0) {
tommy_hashtable_foreach(&this->hashtable, setstr_obj_free);
tommy_hashtable_done(&this->hashtable);
}
bzero(this, sizeof(setstr_t));
}