MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1#include <stdlib.h>
2#include <string.h>
3#include <uthash.h>
4
5#include "ant.h"
6#include "errors.h"
7#include "runtime.h"
8#include "internal.h"
9#include "descriptors.h"
10
11#include "modules/symbol.h"
12#include "modules/sessionstorage.h"
13
14typedef struct storage_entry {
15 char *key;
16 char *value;
17 UT_hash_handle hh;
18} storage_entry_t;
19
20static storage_entry_t *session_storage = NULL;
21
22static void storage_set_item(const char *key, size_t key_len, const char *value, size_t value_len) {
23 storage_entry_t *entry = NULL;
24
25 HASH_FIND(hh, session_storage, key, key_len, entry);
26
27 if (entry) {
28 HASH_DEL(session_storage, entry);
29 free(entry);
30 }
31
32 entry = ant_calloc(sizeof(storage_entry_t) + key_len + 1 + value_len + 1);
33 if (!entry) return;
34
35 entry->key = (char *)(entry + 1);
36 entry->value = entry->key + key_len + 1;
37
38 memcpy(entry->key, key, key_len);
39 entry->key[key_len] = '\0';
40 memcpy(entry->value, value, value_len);
41 entry->value[value_len] = '\0';
42
43 HASH_ADD_KEYPTR(hh, session_storage, entry->key, key_len, entry);
44}
45
46static char *storage_get_item(const char *key, size_t key_len) {
47 storage_entry_t *entry = NULL;
48 HASH_FIND(hh, session_storage, key, key_len, entry);
49 return entry ? entry->value : NULL;
50}
51
52static void storage_remove_item(const char *key, size_t key_len) {
53 storage_entry_t *entry = NULL;
54 HASH_FIND(hh, session_storage, key, key_len, entry);
55
56 if (entry) {
57 HASH_DEL(session_storage, entry);
58 free(entry);
59 }
60}
61
62static void storage_clear(void) {
63 storage_entry_t *entry, *tmp;
64 HASH_ITER(hh, session_storage, entry, tmp) {
65 HASH_DEL(session_storage, entry);
66 free(entry);
67 }
68}
69
70static size_t storage_length(void) {
71 return HASH_COUNT(session_storage);
72}
73
74static char *storage_key(size_t index) {
75 storage_entry_t *entry;
76 size_t i = 0;
77
78 for (entry = session_storage; entry != NULL; entry = entry->hh.next) {
79 if (i == index) return entry->key;
80 i++;
81 }
82
83 return NULL;
84}
85
86// sessionStorage.setItem(key, value)
87static ant_value_t js_sessionstorage_setItem(ant_t *js, ant_value_t *args, int nargs) {
88 if (nargs < 2) {
89 return js_mkerr(js, "Failed to execute 'setItem' on 'Storage': 2 arguments required");
90 }
91
92 size_t key_len, value_len;
93 char *key = js_getstr(js, args[0], &key_len);
94 char *value = js_getstr(js, js_tostring_val(js, args[1]), &value_len);
95
96 storage_set_item(key, key_len, value, value_len);
97
98 return js_mkundef();
99}
100
101// sessionStorage.getItem(key)
102static ant_value_t js_sessionstorage_getItem(ant_t *js, ant_value_t *args, int nargs) {
103 if (nargs < 1) {
104 return js_mkerr(js, "Failed to execute 'getItem' on 'Storage': 1 argument required");
105 }
106
107 size_t key_len;
108 char *key = js_getstr(js, args[0], &key_len);
109 char *value = storage_get_item(key, key_len);
110
111 if (!value) return js_mknull();
112
113 return js_mkstr(js, value, strlen(value));
114}
115
116// sessionStorage.removeItem(key)
117static ant_value_t js_sessionstorage_removeItem(ant_t *js, ant_value_t *args, int nargs) {
118 if (nargs < 1) {
119 return js_mkerr(js, "Failed to execute 'removeItem' on 'Storage': 1 argument required");
120 }
121
122 size_t key_len;
123 char *key = js_getstr(js, args[0], &key_len);
124 storage_remove_item(key, key_len);
125
126 return js_mkundef();
127}
128
129// sessionStorage.clear()
130static ant_value_t js_sessionstorage_clear(ant_params_t) {
131 storage_clear();
132 return js_mkundef();
133}
134
135// sessionStorage.key(index)
136static ant_value_t js_sessionstorage_key(ant_t *js, ant_value_t *args, int nargs) {
137 if (nargs < 1) {
138 return js_mkerr(js, "Failed to execute 'key' on 'Storage': 1 argument required");
139 }
140
141 if (vtype(args[0]) != T_NUM) {
142 return js_mknull();
143 }
144
145 double idx = js_getnum(args[0]);
146 if (idx < 0) return js_mknull();
147
148 size_t index = (size_t)idx;
149 char *key = storage_key(index);
150
151 if (!key) return js_mknull();
152
153 return js_mkstr(js, key, strlen(key));
154}
155
156// sessionStorage.length
157static ant_value_t js_sessionstorage_length(ant_params_t) {
158 return js_mknum((double)storage_length());
159}
160
161void init_sessionstorage_module(void) {
162 ant_t *js = rt->js;
163
164 ant_value_t glob = js_glob(js);
165 ant_value_t storage_obj = js_mkobj(js);
166
167 js_set(js, storage_obj, "setItem", js_mkfun(js_sessionstorage_setItem));
168 js_set(js, storage_obj, "getItem", js_mkfun(js_sessionstorage_getItem));
169 js_set(js, storage_obj, "removeItem", js_mkfun(js_sessionstorage_removeItem));
170 js_set(js, storage_obj, "clear", js_mkfun(js_sessionstorage_clear));
171 js_set(js, storage_obj, "key", js_mkfun(js_sessionstorage_key));
172
173 ant_value_t length_getter = js_mkfun(js_sessionstorage_length);
174 js_set_getter_desc(js, storage_obj, "length", 6, length_getter, JS_DESC_E);
175
176 js_set_sym(js, storage_obj, get_toStringTag_sym(), ANT_STRING("Storage"));
177 js_set(js, glob, "sessionStorage", storage_obj);
178}