aboutsummaryrefslogtreecommitdiff
path: root/src/env.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/env.c')
-rw-r--r--src/env.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/env.c b/src/env.c
new file mode 100644
index 0000000..1aa452b
--- /dev/null
+++ b/src/env.c
@@ -0,0 +1,78 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "common.h"
+#include "env.h"
+#include "hashtable.h"
+
+#define ENV_TABLE_CAP (1 << 8)
+
+static unsigned long str_hash(char *str)
+{
+ unsigned long hash = 5381;
+ int c;
+
+ while ((c = *str++))
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+ return hash;
+}
+
+static size_t hash(void *key)
+{
+ return str_hash((char*)key);
+}
+
+static bool equal(void *key1, void *key2)
+{
+ if(strcmp((char *)key1, (char*)key2) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+static void env_add_ref(env_t env);
+
+env_t env_create(env_t parent, env_destroy_func destroy_func)
+{
+ env_t env = malloc(sizeof(*env));
+ env->destroy_func = destroy_func;
+ env->parent = parent;
+ env->refs = 0;
+
+ env_add_ref(env);
+
+ ERR_Z(env->table = hashtable_create(ENV_TABLE_CAP, hash, equal),
+ env_destroy(env));
+
+ return env;
+}
+
+void env_destroy(env_t env)
+{
+ if(!env) return;
+
+ env->refs--;
+ env_destroy(env->parent);
+
+ if(env->refs > 0) return;
+
+
+ hashtable_for_each_item(env->table, item, i) {
+ env->destroy_func((char *)item->key, (value_t)item->data);
+ }
+
+ hashtable_destroy(env->table);
+ free(env);
+}
+
+
+static void env_add_ref(env_t env)
+{
+ env->refs++;
+
+ if(env->parent) {
+ env_add_ref(env->parent);
+ }
+}