Initial import
[project/ufp.git] / src / ucode.c
1 #include <ucode/module.h>
2 #include "uht.h"
3
4 static uc_resource_type_t *reader_type, *hashtbl_type;
5 static char *hash_key;
6
7 static uint32_t
8 writer_store_data(struct uht_writer *wr, uc_value_t *val)
9 {
10 uint32_t *data, ret;
11 size_t i, len;
12
13 switch (ucv_type(val)) {
14 case UC_STRING:
15 return uht_writer_add_string(wr, ucv_string_get(val));
16 case UC_INTEGER:
17 return uht_writer_add_int(wr, ucv_int64_get(val));
18 case UC_DOUBLE:
19 return uht_writer_add_double(wr, ucv_double_get(val));
20 case UC_BOOLEAN:
21 return uht_writer_add_bool(wr, ucv_boolean_get(val));
22 case UC_ARRAY:
23 len = ucv_array_length(val);
24 data = calloc(len, sizeof(*data));
25 for (i = 0; i < len; i++)
26 data[i] = writer_store_data(wr, ucv_array_get(val, i));
27 ret = uht_writer_add_array(wr, data, len);
28 free(data);
29 return ret;
30 case UC_OBJECT:
31 len = ucv_object_length(val);
32 if (ucv_is_truish(ucv_object_get(val, hash_key, NULL))) {
33 ret = uht_writer_hashtbl_alloc(wr, len - 1);
34 ucv_object_foreach(val, key, value) {
35 if (!strcmp(key, hash_key))
36 continue;
37 uht_writer_hashtbl_add_element(wr, ret, key,
38 writer_store_data(wr, value));
39 }
40 uht_writer_hashtbl_done(wr, ret);
41 return ret;
42 }
43 data = calloc(2 * len, sizeof(*data));
44 i = 0;
45 ucv_object_foreach(val, key, value) {
46 data[i] = uht_writer_add_string(wr, key);
47 data[len + i] = writer_store_data(wr, value);
48 i++;
49 }
50 ret = uht_writer_add_object(wr, data, data + len, len);
51 free(data);
52 return ret;
53 default:
54 return 0;
55 }
56 }
57
58 static uc_value_t *
59 writer_save(uc_vm_t *vm, size_t nargs)
60 {
61 struct uht_writer wr = {};
62 uc_value_t *file = uc_fn_arg(0);
63 uc_value_t *data = uc_fn_arg(1);
64 uint32_t val;
65 int ret = -1;
66 FILE *f;
67
68 if (ucv_type(file) != UC_STRING || !data)
69 return NULL;
70
71 f = fopen(ucv_string_get(file), "w");
72 if (!f)
73 return NULL;
74
75 uht_writer_init(&wr);
76 val = writer_store_data(&wr, data);
77 if (val)
78 ret = uht_writer_save(&wr, f, val);
79 fflush(f);
80 fclose(f);
81 uht_writer_free(&wr);
82
83 return ucv_boolean_new(ret == 0);
84 }
85
86 static uc_value_t *
87 __reader_get_value(uc_vm_t *vm, struct uht_reader *r, uint32_t attr, bool dump)
88 {
89 enum uht_type type = uht_entry_type(attr);
90 uc_value_t *val;
91 size_t i;
92
93 switch (type) {
94 case UHT_NULL:
95 return NULL;
96 case UHT_STRING:
97 return ucv_string_new(uht_reader_get_string(r, attr));
98 case UHT_INT:
99 return ucv_int64_new(uht_reader_get_int(r, attr));
100 case UHT_DOUBLE:
101 return ucv_double_new(uht_reader_get_double(r, attr));
102 case UHT_BOOL:
103 return ucv_boolean_new(uht_reader_get_bool(r, attr));
104 case UHT_HASHTBL:
105 if (!dump)
106 return ucv_resource_new(hashtbl_type, (void *)(uintptr_t)attr);
107 /* fallthrough */
108 case UHT_OBJECT:
109 val = ucv_object_new(vm);
110 if (type == UHT_HASHTBL)
111 ucv_object_add(val, hash_key, ucv_boolean_new(true));
112 uht_for_each(r, iter, attr)
113 ucv_object_add(val, iter.key, ucv_get(__reader_get_value(vm, r, iter.val, dump)));
114 return val;
115 case UHT_ARRAY:
116 val = ucv_array_new(vm);
117 i = 0;
118 uht_for_each(r, iter, attr)
119 ucv_array_set(val, i++, ucv_get(__reader_get_value(vm, r, iter.val, dump)));
120 return val;
121 }
122
123 return NULL;
124 }
125
126 static uc_value_t *
127 reader_open(uc_vm_t *vm, size_t nargs)
128 {
129 uc_value_t *file = uc_fn_arg(0);
130 struct uht_reader *r;
131
132 if (ucv_type(file) != UC_STRING)
133 return NULL;
134
135 r = calloc(1, sizeof(*r));
136 if (uht_reader_open(r, ucv_string_get(file))) {
137 free(r);
138 return NULL;
139 }
140
141 return ucv_resource_new(reader_type, r);
142 }
143
144 static void
145 reader_free(void *ptr)
146 {
147 struct uht_reader *r = ptr;
148
149 uht_reader_close(r);
150 free(r);
151 }
152
153 static uc_value_t *
154 set_hashtbl_key(uc_vm_t *vm, size_t nargs)
155 {
156 uc_value_t *key = uc_fn_arg(0);
157
158 if (ucv_type(key) != UC_STRING)
159 return NULL;
160
161 free(hash_key);
162 hash_key = strdup(ucv_string_get(key));
163
164 return ucv_boolean_new(true);
165 }
166
167 static uc_value_t *
168 mark_hashtbl(uc_vm_t *vm, size_t nargs)
169 {
170 uc_value_t *obj = uc_fn_arg(0);
171
172 if (ucv_type(obj) != UC_OBJECT)
173 return NULL;
174
175 ucv_object_add(obj, hash_key, ucv_boolean_new(true));
176 return ucv_boolean_new(true);
177 }
178
179 static uint32_t
180 reader_get_htable(uc_value_t *tbl)
181 {
182 void *htbl;
183
184 if (ucv_type(tbl) != UC_RESOURCE)
185 return 0;
186
187 htbl = ucv_resource_data(tbl, "uht.hashtbl");
188 if (!htbl)
189 return 0;
190
191 return (uint32_t)(uintptr_t)htbl;
192 }
193
194 static uc_value_t *
195 reader_get(uc_vm_t *vm, size_t nargs)
196 {
197 struct uht_reader *r = uc_fn_thisval("uht.reader");
198 uc_value_t *tbl = uc_fn_arg(0);
199 uc_value_t *key = uc_fn_arg(1);
200 uc_value_t *dump = uc_fn_arg(2);
201 uint32_t val;
202
203 if (!r)
204 return NULL;
205
206 if (tbl)
207 val = reader_get_htable(tbl);
208 else
209 val = r->val;
210
211 if (key) {
212 if (uht_entry_type(val) != UHT_HASHTBL)
213 return 0;
214
215 val = uht_reader_hashtbl_lookup(r, val, ucv_string_get(key));
216 }
217
218 return __reader_get_value(vm, r, val, ucv_is_truish(dump));
219 }
220
221 static const uc_function_list_t no_fns[] = {};
222
223 static const uc_function_list_t reader_fns[] = {
224 { "get", reader_get },
225 };
226
227 static const uc_function_list_t hashtbl_fns[] = {
228 { "save", writer_save },
229 { "open", reader_open },
230 { "mark_hashtable", mark_hashtbl },
231 { "set_hashtable_key", set_hashtbl_key },
232 };
233
234 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
235 {
236 hash_key = strdup("##hash_table");
237 reader_type = uc_type_declare(vm, "uht.reader", reader_fns, reader_free);
238 hashtbl_type = uc_type_declare(vm, "uht.hashtbl", no_fns, NULL);
239 uc_function_list_register(scope, hashtbl_fns);
240 }