BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file value.c |
||
3 | * @author Ambroz Bizjak <ambrop7@gmail.com> |
||
4 | * |
||
5 | * @section LICENSE |
||
6 | * |
||
7 | * Redistribution and use in source and binary forms, with or without |
||
8 | * modification, are permitted provided that the following conditions are met: |
||
9 | * 1. Redistributions of source code must retain the above copyright |
||
10 | * notice, this list of conditions and the following disclaimer. |
||
11 | * 2. Redistributions in binary form must reproduce the above copyright |
||
12 | * notice, this list of conditions and the following disclaimer in the |
||
13 | * documentation and/or other materials provided with the distribution. |
||
14 | * 3. Neither the name of the author nor the |
||
15 | * names of its contributors may be used to endorse or promote products |
||
16 | * derived from this software without specific prior written permission. |
||
17 | * |
||
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||
19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
21 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||
22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
27 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
28 | * |
||
29 | * @section DESCRIPTION |
||
30 | * |
||
31 | * Synopsis: |
||
32 | * value(value) |
||
33 | * value value::get(where) |
||
34 | * value value::try_get(where) |
||
35 | * value value::getpath(list path) |
||
36 | * value value::insert(where, what) |
||
37 | * value value::insert(what) |
||
38 | * value value::replace(where, what) |
||
39 | * value value::replace_this(value) |
||
40 | * value value::insert_undo(where, what) |
||
41 | * value value::insert_undo(what) |
||
42 | * value value::replace_undo(where, what) |
||
43 | * value value::replace_this_undo(value) |
||
44 | * |
||
45 | * Description: |
||
46 | * Value objects allow examining and manipulating values. |
||
47 | * These value objects are actually references to internal value structures, which |
||
48 | * may be shared between value objects. |
||
49 | * |
||
50 | * value(value) constructs a new value object from the given value. |
||
51 | * |
||
52 | * value::get(where) constructs a value object for the element at position 'where' |
||
53 | * (for a list), or the value corresponding to key 'where' (for a map). It is an |
||
54 | * error if the base value is not a list or a map, the index is out of bounds of |
||
55 | * the list, or the key does not exist in the map. |
||
56 | * The resulting value object is NOT a copy, and shares (part of) the same |
||
57 | * underlying value structure as the base value object. Deleting it will remove |
||
58 | * it from the list or map it is part of. |
||
59 | * |
||
60 | * value::try_get(where) is like get(), except that if any restriction on 'where' |
||
61 | * is violated, no error is triggered; instead, the value object is constructed |
||
62 | * as being deleted; this state is exposed via the 'exists' variable. |
||
63 | * This can be used to check for the presence of a key in a map, and in case it |
||
64 | * exists, allow access to the corresponding value without another get() statement. |
||
65 | * |
||
66 | * value::getpath(path) is like get(), except that it performs multiple |
||
67 | * consecutive resolutions. Also, if the path is an empty list, it performs |
||
68 | * no resulution at all. |
||
69 | * |
||
70 | * value::insert(where, what) constructs a value object by inserting into an |
||
71 | * existing value object. |
||
72 | * For lists, 'where' is the index of the element to insert before, or the length |
||
73 | * of the list to append to it. |
||
74 | * For maps, 'where' is the key to insert under. If the key already exists in the |
||
75 | * map, its value is replaced; any references to the old value however remain valid. |
||
76 | * |
||
77 | * value::insert(what) constructs a value object by appending to a list. An error |
||
78 | * is triggered if the base value is not a list. Assuming 'list' is a list value, |
||
79 | * list->insert(X) is equivalent to list->insert(list.length, X). |
||
80 | * |
||
81 | * value::replace(where, what) is like insert(), exept that, when inserting into a |
||
82 | * list, the value at the specified index is replaced with the new value (unless |
||
83 | * the index is equal to the length of the list). |
||
84 | * |
||
85 | * insert_undo() and replace_undo() are versions of insert() and replace() which |
||
86 | * attempt to revert the modifications when they deinitialize. |
||
87 | * Specifically, they work like that: |
||
88 | * - On initiialization, they take an internal reference to the value being replaced |
||
89 | * (if any; note that insert_undo() into a list never replaces a value). |
||
90 | * - On deinitialization, they remove the the inserted value from its parent (if there |
||
91 | * is one), and insert the old replaced value (to which a reference was kept) in that |
||
92 | * place (if any, and assuming it has not been deleted). |
||
93 | * Note that if the inserted value changes parents in between init and deinit, the |
||
94 | * result of undoing may be unexpected. |
||
95 | * |
||
96 | * Variables: |
||
97 | * (empty) - the value stored in the value object |
||
98 | * type - type of the value; "string", "list" or "map" |
||
99 | * length - number of elements in the list or map, or the number of bytes in a |
||
100 | * string |
||
101 | * keys - a list of keys in the map (only if the value is a map) |
||
102 | * exists - "true" or "false", reflecting whether the value object holds a value |
||
103 | * (is not in deleted state) |
||
104 | * |
||
105 | * Synopsis: |
||
106 | * value::remove(where) |
||
107 | * value::delete() |
||
108 | * |
||
109 | * Description: |
||
110 | * value::remove(where) removes from an existing value object. |
||
111 | * For lists, 'where' is the index of the element to remove, and must be in range. |
||
112 | * For maps, 'where' is the key to remove, and must be an existing key. |
||
113 | * In any case, any references to the removed value remain valid. |
||
114 | * |
||
115 | * value::delete() deletes the underlying value data of this value object. |
||
116 | * After delection, the value object enters a deleted state, which will cause any |
||
117 | * operation on it to fail. Any other value objects which referred to the same value |
||
118 | * or parts of it will too enter deleted state. If the value was an element |
||
119 | * in a list or map, is is removed from it. |
||
120 | * |
||
121 | * Synopsis: |
||
122 | * value value::substr(string start [, string length]) |
||
123 | * |
||
124 | * Description: |
||
125 | * Constructs a string value by extracting a part of a string. |
||
126 | * 'start' specifies the index of the character (from zero) where the substring to |
||
127 | * extract starts, and must be <= the length of the string. |
||
128 | * 'length' specifies the maximum number of characters to extract, if given. |
||
129 | * The newly constructed value is a copy of the extracted substring. |
||
130 | * The value must be a string value. |
||
131 | * |
||
132 | * Synopsis: |
||
133 | * value::reset(what) |
||
134 | * |
||
135 | * Description: |
||
136 | * Effectively deconstructs and reconstructs the value object. More precisely, |
||
137 | * it builds a new value structure from 'what', possibly invokes a scheduled undo |
||
138 | * operation (as scheduled by insert_undo() and replace_undo()), sets up this |
||
139 | * value object to reference the newly built value structure, without any scheduled |
||
140 | * undo operation. |
||
141 | * |
||
142 | * Synopsis: |
||
143 | * value::append(append_val) |
||
144 | * |
||
145 | * Description: |
||
146 | * Only defined when the existing value object is a string or list. If it is a string, |
||
147 | * appends the string 'append_val' to this string value; 'append_val' must be a string. |
||
148 | * If is is a list, inserts 'append_val' to the end of this list value. Unlike insert(), |
||
149 | * the resulting append() object is not itself a value object (which in case of insert() |
||
150 | * serves as a reference to the new value). |
||
151 | */ |
||
152 | |||
153 | #include <stdlib.h> |
||
154 | #include <string.h> |
||
155 | #include <stddef.h> |
||
156 | #include <limits.h> |
||
157 | #include <inttypes.h> |
||
158 | |||
159 | #include <misc/offset.h> |
||
160 | #include <misc/debug.h> |
||
161 | #include <misc/balloc.h> |
||
162 | #include <structure/LinkedList0.h> |
||
163 | #include <structure/IndexedList.h> |
||
164 | #include <structure/SAvl.h> |
||
165 | #include <ncd/NCDStringIndex.h> |
||
166 | #include <ncd/extra/NCDRefString.h> |
||
167 | |||
168 | #include <ncd/module_common.h> |
||
169 | |||
170 | #include <generated/blog_channel_ncd_value.h> |
||
171 | |||
172 | #define STOREDSTRING_TYPE (NCDVAL_STRING | (0 << 3)) |
||
173 | #define IDSTRING_TYPE (NCDVAL_STRING | (1 << 3)) |
||
174 | #define EXTERNALSTRING_TYPE (NCDVAL_STRING | (2 << 3)) |
||
175 | |||
176 | struct value; |
||
177 | |||
178 | #include "value_maptree.h" |
||
179 | #include <structure/SAvl_decl.h> |
||
180 | |||
181 | struct valref { |
||
182 | struct value *v; |
||
183 | LinkedList0Node refs_list_node; |
||
184 | }; |
||
185 | |||
186 | typedef void (*value_deinit_func) (void *deinit_data, NCDModuleInst *i); |
||
187 | |||
188 | struct instance { |
||
189 | NCDModuleInst *i; |
||
190 | struct valref ref; |
||
191 | value_deinit_func deinit_func; |
||
192 | void *deinit_data; |
||
193 | }; |
||
194 | |||
195 | struct value { |
||
196 | LinkedList0 refs_list; |
||
197 | |||
198 | struct value *parent; |
||
199 | union { |
||
200 | struct { |
||
201 | IndexedListNode list_contents_il_node; |
||
202 | } list_parent; |
||
203 | struct { |
||
204 | NCDValMem key_mem; |
||
205 | NCDValRef key; |
||
206 | MapTreeNode maptree_node; |
||
207 | } map_parent; |
||
208 | }; |
||
209 | |||
210 | int type; |
||
211 | union { |
||
212 | struct { |
||
213 | NCDRefString *rstr; |
||
214 | size_t length; |
||
215 | size_t size; |
||
216 | } storedstring; |
||
217 | struct { |
||
218 | NCD_string_id_t id; |
||
219 | NCDStringIndex *string_index; |
||
220 | } idstring; |
||
221 | struct { |
||
222 | const char *data; |
||
223 | size_t length; |
||
224 | BRefTarget *ref_target; |
||
225 | } externalstring; |
||
226 | struct { |
||
227 | IndexedList list_contents_il; |
||
228 | } list; |
||
229 | struct { |
||
230 | MapTree map_tree; |
||
231 | } map; |
||
232 | }; |
||
233 | }; |
||
234 | |||
235 | static const char * get_type_str (int type); |
||
236 | static void value_cleanup (struct value *v); |
||
237 | static void value_delete (struct value *v); |
||
238 | static struct value * value_init_storedstring (NCDModuleInst *i, MemRef str); |
||
239 | static struct value * value_init_idstring (NCDModuleInst *i, NCD_string_id_t id, NCDStringIndex *string_index); |
||
240 | static struct value * value_init_externalstring (NCDModuleInst *i, MemRef data, BRefTarget *ref_target); |
||
241 | static int value_is_string (struct value *v); |
||
242 | static MemRef value_string_memref (struct value *v); |
||
243 | static void value_string_set_rstr (struct value *v, NCDRefString *rstr, size_t length, size_t size); |
||
244 | static struct value * value_init_list (NCDModuleInst *i); |
||
245 | static size_t value_list_len (struct value *v); |
||
246 | static struct value * value_list_at (struct value *v, size_t index); |
||
247 | static size_t value_list_indexof (struct value *v, struct value *ev); |
||
248 | static int value_list_insert (NCDModuleInst *i, struct value *list, struct value *v, size_t index); |
||
249 | static void value_list_remove (struct value *list, struct value *v); |
||
250 | static struct value * value_init_map (NCDModuleInst *i); |
||
251 | static size_t value_map_len (struct value *map); |
||
252 | static struct value * value_map_at (struct value *map, size_t index); |
||
253 | static struct value * value_map_find (struct value *map, NCDValRef key); |
||
254 | static int value_map_insert (struct value *map, struct value *v, NCDValMem mem, NCDValSafeRef key, NCDModuleInst *i); |
||
255 | static void value_map_remove (struct value *map, struct value *v); |
||
256 | static void value_map_remove2 (struct value *map, struct value *v, NCDValMem *out_mem, NCDValSafeRef *out_key); |
||
257 | static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValRef value); |
||
258 | static int value_to_value (NCDModuleInst *i, struct value *v, NCDValMem *mem, NCDValRef *out_value); |
||
259 | static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValRef where, int no_error); |
||
260 | static struct value * value_get_path (NCDModuleInst *i, struct value *v, NCDValRef path); |
||
261 | static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValRef where, NCDValRef what, int is_replace, struct value **out_oldv); |
||
262 | static struct value * value_insert_simple (NCDModuleInst *i, struct value *v, NCDValRef what); |
||
263 | static int value_remove (NCDModuleInst *i, struct value *v, NCDValRef where); |
||
264 | static int value_append (NCDModuleInst *i, struct value *v, NCDValRef data); |
||
265 | static void valref_init (struct valref *r, struct value *v); |
||
266 | static void valref_free (struct valref *r); |
||
267 | static struct value * valref_val (struct valref *r); |
||
268 | static void valref_break (struct valref *r); |
||
269 | |||
270 | enum {STRING_EXISTS, STRING_KEYS}; |
||
271 | |||
272 | static const char *strings[] = { |
||
273 | "exists", "keys", NULL |
||
274 | }; |
||
275 | |||
276 | #include "value_maptree.h" |
||
277 | #include <structure/SAvl_impl.h> |
||
278 | |||
279 | static const char * get_type_str (int type) |
||
280 | { |
||
281 | switch (type) { |
||
282 | case STOREDSTRING_TYPE: |
||
283 | case IDSTRING_TYPE: |
||
284 | case EXTERNALSTRING_TYPE: |
||
285 | return "string"; |
||
286 | case NCDVAL_LIST: |
||
287 | return "list"; |
||
288 | case NCDVAL_MAP: |
||
289 | return "map"; |
||
290 | } |
||
291 | ASSERT(0) |
||
292 | return NULL; |
||
293 | } |
||
294 | |||
295 | static void value_cleanup (struct value *v) |
||
296 | { |
||
297 | if (v->parent || !LinkedList0_IsEmpty(&v->refs_list)) { |
||
298 | return; |
||
299 | } |
||
300 | |||
301 | switch (v->type) { |
||
302 | case STOREDSTRING_TYPE: { |
||
303 | BRefTarget_Deref(NCDRefString_RefTarget(v->storedstring.rstr)); |
||
304 | } break; |
||
305 | |||
306 | case IDSTRING_TYPE: { |
||
307 | } break; |
||
308 | |||
309 | case EXTERNALSTRING_TYPE: { |
||
310 | if (v->externalstring.ref_target) { |
||
311 | BRefTarget_Deref(v->externalstring.ref_target); |
||
312 | } |
||
313 | } break; |
||
314 | |||
315 | case NCDVAL_LIST: { |
||
316 | while (value_list_len(v) > 0) { |
||
317 | struct value *ev = value_list_at(v, 0); |
||
318 | value_list_remove(v, ev); |
||
319 | value_cleanup(ev); |
||
320 | } |
||
321 | } break; |
||
322 | |||
323 | case NCDVAL_MAP: { |
||
324 | while (value_map_len(v) > 0) { |
||
325 | struct value *ev = value_map_at(v, 0); |
||
326 | value_map_remove(v, ev); |
||
327 | value_cleanup(ev); |
||
328 | } |
||
329 | } break; |
||
330 | |||
331 | default: ASSERT(0); |
||
332 | } |
||
333 | |||
334 | free(v); |
||
335 | } |
||
336 | |||
337 | static void value_delete (struct value *v) |
||
338 | { |
||
339 | if (v->parent) { |
||
340 | switch (v->parent->type) { |
||
341 | case NCDVAL_LIST: { |
||
342 | value_list_remove(v->parent, v); |
||
343 | } break; |
||
344 | case NCDVAL_MAP: { |
||
345 | value_map_remove(v->parent, v); |
||
346 | } break; |
||
347 | default: ASSERT(0); |
||
348 | } |
||
349 | } |
||
350 | |||
351 | LinkedList0Node *ln; |
||
352 | while (ln = LinkedList0_GetFirst(&v->refs_list)) { |
||
353 | struct valref *r = UPPER_OBJECT(ln, struct valref, refs_list_node); |
||
354 | ASSERT(r->v == v) |
||
355 | valref_break(r); |
||
356 | } |
||
357 | |||
358 | switch (v->type) { |
||
359 | case STOREDSTRING_TYPE: { |
||
360 | BRefTarget_Deref(NCDRefString_RefTarget(v->storedstring.rstr)); |
||
361 | } break; |
||
362 | |||
363 | case IDSTRING_TYPE: { |
||
364 | } break; |
||
365 | |||
366 | case EXTERNALSTRING_TYPE: { |
||
367 | if (v->externalstring.ref_target) { |
||
368 | BRefTarget_Deref(v->externalstring.ref_target); |
||
369 | } |
||
370 | } break; |
||
371 | |||
372 | case NCDVAL_LIST: { |
||
373 | while (value_list_len(v) > 0) { |
||
374 | struct value *ev = value_list_at(v, 0); |
||
375 | value_delete(ev); |
||
376 | } |
||
377 | } break; |
||
378 | |||
379 | case NCDVAL_MAP: { |
||
380 | while (value_map_len(v) > 0) { |
||
381 | struct value *ev = value_map_at(v, 0); |
||
382 | value_delete(ev); |
||
383 | } |
||
384 | } break; |
||
385 | |||
386 | default: ASSERT(0); |
||
387 | } |
||
388 | |||
389 | free(v); |
||
390 | } |
||
391 | |||
392 | static struct value * value_init_storedstring (NCDModuleInst *i, MemRef str) |
||
393 | { |
||
394 | struct value *v = malloc(sizeof(*v)); |
||
395 | if (!v) { |
||
396 | ModuleLog(i, BLOG_ERROR, "malloc failed"); |
||
397 | goto fail0; |
||
398 | } |
||
399 | |||
400 | LinkedList0_Init(&v->refs_list); |
||
401 | v->parent = NULL; |
||
402 | v->type = STOREDSTRING_TYPE; |
||
403 | |||
404 | char *buf; |
||
405 | if (!(v->storedstring.rstr = NCDRefString_New(str.len, &buf))) { |
||
406 | ModuleLog(i, BLOG_ERROR, "NCDRefString_New failed"); |
||
407 | goto fail1; |
||
408 | } |
||
409 | |||
410 | memcpy(buf, str.ptr, str.len); |
||
411 | |||
412 | v->storedstring.length = str.len; |
||
413 | v->storedstring.size = str.len; |
||
414 | |||
415 | return v; |
||
416 | |||
417 | fail1: |
||
418 | free(v); |
||
419 | fail0: |
||
420 | return NULL; |
||
421 | } |
||
422 | |||
423 | static struct value * value_init_idstring (NCDModuleInst *i, NCD_string_id_t id, NCDStringIndex *string_index) |
||
424 | { |
||
425 | ASSERT(string_index == i->params->iparams->string_index) |
||
426 | |||
427 | struct value *v = malloc(sizeof(*v)); |
||
428 | if (!v) { |
||
429 | ModuleLog(i, BLOG_ERROR, "malloc failed"); |
||
430 | goto fail0; |
||
431 | } |
||
432 | |||
433 | LinkedList0_Init(&v->refs_list); |
||
434 | v->parent = NULL; |
||
435 | v->type = IDSTRING_TYPE; |
||
436 | |||
437 | v->idstring.id = id; |
||
438 | v->idstring.string_index = string_index; |
||
439 | |||
440 | return v; |
||
441 | |||
442 | fail0: |
||
443 | return NULL; |
||
444 | } |
||
445 | |||
446 | static struct value * value_init_externalstring (NCDModuleInst *i, MemRef data, BRefTarget *ref_target) |
||
447 | { |
||
448 | struct value *v = malloc(sizeof(*v)); |
||
449 | if (!v) { |
||
450 | ModuleLog(i, BLOG_ERROR, "malloc failed"); |
||
451 | goto fail0; |
||
452 | } |
||
453 | |||
454 | if (ref_target) { |
||
455 | if (!BRefTarget_Ref(ref_target)) { |
||
456 | ModuleLog(i, BLOG_ERROR, "BRefTarget_Ref failed"); |
||
457 | goto fail1; |
||
458 | } |
||
459 | } |
||
460 | |||
461 | LinkedList0_Init(&v->refs_list); |
||
462 | v->parent = NULL; |
||
463 | v->type = EXTERNALSTRING_TYPE; |
||
464 | |||
465 | v->externalstring.data = data.ptr; |
||
466 | v->externalstring.length = data.len; |
||
467 | v->externalstring.ref_target = ref_target; |
||
468 | |||
469 | return v; |
||
470 | |||
471 | fail1: |
||
472 | free(v); |
||
473 | fail0: |
||
474 | return NULL; |
||
475 | } |
||
476 | |||
477 | static int value_is_string (struct value *v) |
||
478 | { |
||
479 | switch (v->type) { |
||
480 | case STOREDSTRING_TYPE: |
||
481 | case IDSTRING_TYPE: |
||
482 | case EXTERNALSTRING_TYPE: |
||
483 | return 1; |
||
484 | default: |
||
485 | return 0; |
||
486 | } |
||
487 | } |
||
488 | |||
489 | static MemRef value_string_memref (struct value *v) |
||
490 | { |
||
491 | ASSERT(value_is_string(v)) |
||
492 | |||
493 | switch (v->type) { |
||
494 | case STOREDSTRING_TYPE: |
||
495 | return MemRef_Make(NCDRefString_GetBuf(v->storedstring.rstr), v->storedstring.length); |
||
496 | case IDSTRING_TYPE: |
||
497 | return NCDStringIndex_Value(v->idstring.string_index, v->idstring.id); |
||
498 | break; |
||
499 | case EXTERNALSTRING_TYPE: |
||
500 | return MemRef_Make(v->externalstring.data, v->externalstring.length); |
||
501 | default: |
||
502 | ASSERT(0); |
||
503 | return MemRef_Make(NULL, 0); |
||
504 | } |
||
505 | } |
||
506 | |||
507 | static void value_string_set_rstr (struct value *v, NCDRefString *rstr, size_t length, size_t size) |
||
508 | { |
||
509 | ASSERT(value_is_string(v)) |
||
510 | ASSERT(rstr) |
||
511 | ASSERT(size >= length) |
||
512 | |||
513 | switch (v->type) { |
||
514 | case STOREDSTRING_TYPE: { |
||
515 | BRefTarget_Deref(NCDRefString_RefTarget(v->storedstring.rstr)); |
||
516 | } break; |
||
517 | |||
518 | case IDSTRING_TYPE: { |
||
519 | } break; |
||
520 | |||
521 | case EXTERNALSTRING_TYPE: { |
||
522 | if (v->externalstring.ref_target) { |
||
523 | BRefTarget_Deref(v->externalstring.ref_target); |
||
524 | } |
||
525 | } break; |
||
526 | |||
527 | default: |
||
528 | ASSERT(0); |
||
529 | } |
||
530 | |||
531 | v->type = STOREDSTRING_TYPE; |
||
532 | v->storedstring.rstr = rstr; |
||
533 | v->storedstring.length = length; |
||
534 | v->storedstring.size = size; |
||
535 | } |
||
536 | |||
537 | static struct value * value_init_list (NCDModuleInst *i) |
||
538 | { |
||
539 | struct value *v = malloc(sizeof(*v)); |
||
540 | if (!v) { |
||
541 | ModuleLog(i, BLOG_ERROR, "malloc failed"); |
||
542 | return NULL; |
||
543 | } |
||
544 | |||
545 | LinkedList0_Init(&v->refs_list); |
||
546 | v->parent = NULL; |
||
547 | v->type = NCDVAL_LIST; |
||
548 | |||
549 | IndexedList_Init(&v->list.list_contents_il); |
||
550 | |||
551 | return v; |
||
552 | } |
||
553 | |||
554 | static size_t value_list_len (struct value *v) |
||
555 | { |
||
556 | ASSERT(v->type == NCDVAL_LIST) |
||
557 | |||
558 | return IndexedList_Count(&v->list.list_contents_il); |
||
559 | } |
||
560 | |||
561 | static struct value * value_list_at (struct value *v, size_t index) |
||
562 | { |
||
563 | ASSERT(v->type == NCDVAL_LIST) |
||
564 | ASSERT(index < value_list_len(v)) |
||
565 | |||
566 | IndexedListNode *iln = IndexedList_GetAt(&v->list.list_contents_il, index); |
||
567 | ASSERT(iln) |
||
568 | |||
569 | struct value *e = UPPER_OBJECT(iln, struct value, list_parent.list_contents_il_node); |
||
570 | ASSERT(e->parent == v) |
||
571 | |||
572 | return e; |
||
573 | } |
||
574 | |||
575 | static size_t value_list_indexof (struct value *v, struct value *ev) |
||
576 | { |
||
577 | ASSERT(v->type == NCDVAL_LIST) |
||
578 | ASSERT(ev->parent == v) |
||
579 | |||
580 | uint64_t index = IndexedList_IndexOf(&v->list.list_contents_il, &ev->list_parent.list_contents_il_node); |
||
581 | ASSERT(index < value_list_len(v)) |
||
582 | |||
583 | return index; |
||
584 | } |
||
585 | |||
586 | static int value_list_insert (NCDModuleInst *i, struct value *list, struct value *v, size_t index) |
||
587 | { |
||
588 | ASSERT(list->type == NCDVAL_LIST) |
||
589 | ASSERT(!v->parent) |
||
590 | ASSERT(index <= value_list_len(list)) |
||
591 | |||
592 | if (value_list_len(list) == SIZE_MAX) { |
||
593 | ModuleLog(i, BLOG_ERROR, "list has too many elements"); |
||
594 | return 0; |
||
595 | } |
||
596 | |||
597 | IndexedList_InsertAt(&list->list.list_contents_il, &v->list_parent.list_contents_il_node, index); |
||
598 | v->parent = list; |
||
599 | |||
600 | return 1; |
||
601 | } |
||
602 | |||
603 | static void value_list_remove (struct value *list, struct value *v) |
||
604 | { |
||
605 | ASSERT(list->type == NCDVAL_LIST) |
||
606 | ASSERT(v->parent == list) |
||
607 | |||
608 | IndexedList_Remove(&list->list.list_contents_il, &v->list_parent.list_contents_il_node); |
||
609 | v->parent = NULL; |
||
610 | } |
||
611 | |||
612 | static struct value * value_init_map (NCDModuleInst *i) |
||
613 | { |
||
614 | struct value *v = malloc(sizeof(*v)); |
||
615 | if (!v) { |
||
616 | ModuleLog(i, BLOG_ERROR, "malloc failed"); |
||
617 | return NULL; |
||
618 | } |
||
619 | |||
620 | LinkedList0_Init(&v->refs_list); |
||
621 | v->parent = NULL; |
||
622 | v->type = NCDVAL_MAP; |
||
623 | |||
624 | MapTree_Init(&v->map.map_tree); |
||
625 | |||
626 | return v; |
||
627 | } |
||
628 | |||
629 | static size_t value_map_len (struct value *map) |
||
630 | { |
||
631 | ASSERT(map->type == NCDVAL_MAP) |
||
632 | |||
633 | return MapTree_Count(&map->map.map_tree, 0); |
||
634 | } |
||
635 | |||
636 | static struct value * value_map_at (struct value *map, size_t index) |
||
637 | { |
||
638 | ASSERT(map->type == NCDVAL_MAP) |
||
639 | ASSERT(index < value_map_len(map)) |
||
640 | |||
641 | struct value *e = MapTree_GetAt(&map->map.map_tree, 0, index); |
||
642 | ASSERT(e) |
||
643 | ASSERT(e->parent == map) |
||
644 | |||
645 | return e; |
||
646 | } |
||
647 | |||
648 | static struct value * value_map_find (struct value *map, NCDValRef key) |
||
649 | { |
||
650 | ASSERT(map->type == NCDVAL_MAP) |
||
651 | ASSERT(NCDVal_Type(key)) |
||
652 | |||
653 | struct value *e = MapTree_LookupExact(&map->map.map_tree, 0, key); |
||
654 | ASSERT(!e || e->parent == map) |
||
655 | |||
656 | return e; |
||
657 | } |
||
658 | |||
659 | static int value_map_insert (struct value *map, struct value *v, NCDValMem mem, NCDValSafeRef key, NCDModuleInst *i) |
||
660 | { |
||
661 | ASSERT(map->type == NCDVAL_MAP) |
||
662 | ASSERT(!v->parent) |
||
663 | ASSERT((NCDVal_Type(NCDVal_FromSafe(&mem, key)), 1)) |
||
664 | ASSERT(!value_map_find(map, NCDVal_FromSafe(&mem, key))) |
||
665 | |||
666 | if (value_map_len(map) == SIZE_MAX) { |
||
667 | ModuleLog(i, BLOG_ERROR, "map has too many elements"); |
||
668 | return 0; |
||
669 | } |
||
670 | |||
671 | v->map_parent.key_mem = mem; |
||
672 | v->map_parent.key = NCDVal_FromSafe(&v->map_parent.key_mem, key); |
||
673 | int res = MapTree_Insert(&map->map.map_tree, 0, v, NULL); |
||
674 | ASSERT_EXECUTE(res) |
||
675 | v->parent = map; |
||
676 | |||
677 | return 1; |
||
678 | } |
||
679 | |||
680 | static void value_map_remove (struct value *map, struct value *v) |
||
681 | { |
||
682 | ASSERT(map->type == NCDVAL_MAP) |
||
683 | ASSERT(v->parent == map) |
||
684 | |||
685 | MapTree_Remove(&map->map.map_tree, 0, v); |
||
686 | NCDValMem_Free(&v->map_parent.key_mem); |
||
687 | v->parent = NULL; |
||
688 | } |
||
689 | |||
690 | static void value_map_remove2 (struct value *map, struct value *v, NCDValMem *out_mem, NCDValSafeRef *out_key) |
||
691 | { |
||
692 | ASSERT(map->type == NCDVAL_MAP) |
||
693 | ASSERT(v->parent == map) |
||
694 | ASSERT(out_mem) |
||
695 | ASSERT(out_key) |
||
696 | |||
697 | MapTree_Remove(&map->map.map_tree, 0, v); |
||
698 | *out_mem = v->map_parent.key_mem; |
||
699 | *out_key = NCDVal_ToSafe(v->map_parent.key); |
||
700 | v->parent = NULL; |
||
701 | } |
||
702 | |||
703 | static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValRef value) |
||
704 | { |
||
705 | ASSERT((NCDVal_Type(value), 1)) |
||
706 | |||
707 | struct value *v; |
||
708 | |||
709 | switch (NCDVal_Type(value)) { |
||
710 | case NCDVAL_STRING: { |
||
711 | if (NCDVal_IsIdString(value)) { |
||
712 | v = value_init_idstring(i, NCDVal_IdStringId(value), NCDValMem_StringIndex(value.mem)); |
||
713 | } else if (NCDVal_IsExternalString(value)) { |
||
714 | v = value_init_externalstring(i, NCDVal_StringMemRef(value), NCDVal_ExternalStringTarget(value)); |
||
715 | } else { |
||
716 | v = value_init_storedstring(i, NCDVal_StringMemRef(value)); |
||
717 | } |
||
718 | if (!v) { |
||
719 | goto fail0; |
||
720 | } |
||
721 | } break; |
||
722 | |||
723 | case NCDVAL_LIST: { |
||
724 | if (!(v = value_init_list(i))) { |
||
725 | goto fail0; |
||
726 | } |
||
727 | |||
728 | size_t count = NCDVal_ListCount(value); |
||
729 | |||
730 | for (size_t j = 0; j < count; j++) { |
||
731 | struct value *ev = value_init_fromvalue(i, NCDVal_ListGet(value, j)); |
||
732 | if (!ev) { |
||
733 | goto fail1; |
||
734 | } |
||
735 | |||
736 | if (!value_list_insert(i, v, ev, value_list_len(v))) { |
||
737 | value_cleanup(ev); |
||
738 | goto fail1; |
||
739 | } |
||
740 | } |
||
741 | } break; |
||
742 | |||
743 | case NCDVAL_MAP: { |
||
744 | if (!(v = value_init_map(i))) { |
||
745 | goto fail0; |
||
746 | } |
||
747 | |||
748 | for (NCDValMapElem e = NCDVal_MapFirst(value); !NCDVal_MapElemInvalid(e); e = NCDVal_MapNext(value, e)) { |
||
749 | NCDValRef ekey = NCDVal_MapElemKey(value, e); |
||
750 | NCDValRef eval = NCDVal_MapElemVal(value, e); |
||
751 | |||
752 | NCDValMem key_mem; |
||
753 | NCDValMem_Init(&key_mem, i->params->iparams->string_index); |
||
754 | |||
755 | NCDValRef key = NCDVal_NewCopy(&key_mem, ekey); |
||
756 | if (NCDVal_IsInvalid(key)) { |
||
757 | NCDValMem_Free(&key_mem); |
||
758 | goto fail1; |
||
759 | } |
||
760 | |||
761 | struct value *ev = value_init_fromvalue(i, eval); |
||
762 | if (!ev) { |
||
763 | NCDValMem_Free(&key_mem); |
||
764 | goto fail1; |
||
765 | } |
||
766 | |||
767 | if (!value_map_insert(v, ev, key_mem, NCDVal_ToSafe(key), i)) { |
||
768 | NCDValMem_Free(&key_mem); |
||
769 | value_cleanup(ev); |
||
770 | goto fail1; |
||
771 | } |
||
772 | } |
||
773 | } break; |
||
774 | |||
775 | default: |
||
776 | ASSERT(0); |
||
777 | return NULL; |
||
778 | } |
||
779 | |||
780 | return v; |
||
781 | |||
782 | fail1: |
||
783 | value_cleanup(v); |
||
784 | fail0: |
||
785 | return NULL; |
||
786 | } |
||
787 | |||
788 | static int value_to_value (NCDModuleInst *i, struct value *v, NCDValMem *mem, NCDValRef *out_value) |
||
789 | { |
||
790 | ASSERT(mem) |
||
791 | ASSERT(out_value) |
||
792 | |||
793 | switch (v->type) { |
||
794 | case STOREDSTRING_TYPE: { |
||
795 | *out_value = NCDVal_NewExternalString(mem, NCDRefString_GetBuf(v->storedstring.rstr), v->storedstring.length, NCDRefString_RefTarget(v->storedstring.rstr)); |
||
796 | if (NCDVal_IsInvalid(*out_value)) { |
||
797 | goto fail; |
||
798 | } |
||
799 | } break; |
||
800 | |||
801 | case IDSTRING_TYPE: { |
||
802 | *out_value = NCDVal_NewIdString(mem, v->idstring.id); |
||
803 | if (NCDVal_IsInvalid(*out_value)) { |
||
804 | goto fail; |
||
805 | } |
||
806 | } break; |
||
807 | |||
808 | case EXTERNALSTRING_TYPE: { |
||
809 | *out_value = NCDVal_NewExternalString(mem, v->externalstring.data, v->externalstring.length, v->externalstring.ref_target); |
||
810 | if (NCDVal_IsInvalid(*out_value)) { |
||
811 | goto fail; |
||
812 | } |
||
813 | } break; |
||
814 | |||
815 | case NCDVAL_LIST: { |
||
816 | *out_value = NCDVal_NewList(mem, value_list_len(v)); |
||
817 | if (NCDVal_IsInvalid(*out_value)) { |
||
818 | goto fail; |
||
819 | } |
||
820 | |||
821 | for (size_t index = 0; index < value_list_len(v); index++) { |
||
822 | NCDValRef eval; |
||
823 | if (!value_to_value(i, value_list_at(v, index), mem, &eval)) { |
||
824 | goto fail; |
||
825 | } |
||
826 | |||
827 | if (!NCDVal_ListAppend(*out_value, eval)) { |
||
828 | goto fail; |
||
829 | } |
||
830 | } |
||
831 | } break; |
||
832 | |||
833 | case NCDVAL_MAP: { |
||
834 | *out_value = NCDVal_NewMap(mem, value_map_len(v)); |
||
835 | if (NCDVal_IsInvalid(*out_value)) { |
||
836 | goto fail; |
||
837 | } |
||
838 | |||
839 | for (size_t index = 0; index < value_map_len(v); index++) { |
||
840 | struct value *ev = value_map_at(v, index); |
||
841 | |||
842 | NCDValRef key = NCDVal_NewCopy(mem, ev->map_parent.key); |
||
843 | if (NCDVal_IsInvalid(key)) { |
||
844 | goto fail; |
||
845 | } |
||
846 | |||
847 | NCDValRef val; |
||
848 | if (!value_to_value(i, ev, mem, &val)) { |
||
849 | goto fail; |
||
850 | } |
||
851 | |||
852 | int inserted; |
||
853 | if (!NCDVal_MapInsert(*out_value, key, val, &inserted)) { |
||
854 | goto fail; |
||
855 | } |
||
856 | ASSERT_EXECUTE(inserted) |
||
857 | } |
||
858 | } break; |
||
859 | |||
860 | default: ASSERT(0); |
||
861 | } |
||
862 | |||
863 | return 1; |
||
864 | |||
865 | fail: |
||
866 | return 0; |
||
867 | } |
||
868 | |||
869 | static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValRef where, int no_error) |
||
870 | { |
||
871 | ASSERT((NCDVal_Type(where), 1)) |
||
872 | |||
873 | switch (v->type) { |
||
874 | case STOREDSTRING_TYPE: |
||
875 | case IDSTRING_TYPE: |
||
876 | case EXTERNALSTRING_TYPE: { |
||
877 | if (!no_error) ModuleLog(i, BLOG_ERROR, "cannot resolve into a string"); |
||
878 | goto fail; |
||
879 | } break; |
||
880 | |||
881 | case NCDVAL_LIST: { |
||
882 | uintmax_t index; |
||
883 | if (!ncd_read_uintmax(where, &index)) { |
||
884 | if (!no_error) ModuleLog(i, BLOG_ERROR, "index is not a valid number (resolving into list)"); |
||
885 | goto fail; |
||
886 | } |
||
887 | |||
888 | if (index >= value_list_len(v)) { |
||
889 | if (!no_error) ModuleLog(i, BLOG_ERROR, "index is out of bounds (resolving into list)"); |
||
890 | goto fail; |
||
891 | } |
||
892 | |||
893 | v = value_list_at(v, index); |
||
894 | } break; |
||
895 | |||
896 | case NCDVAL_MAP: { |
||
897 | v = value_map_find(v, where); |
||
898 | if (!v) { |
||
899 | if (!no_error) ModuleLog(i, BLOG_ERROR, "key does not exist (resolving into map)"); |
||
900 | goto fail; |
||
901 | } |
||
902 | } break; |
||
903 | |||
904 | default: ASSERT(0); |
||
905 | } |
||
906 | |||
907 | return v; |
||
908 | |||
909 | fail: |
||
910 | return NULL; |
||
911 | } |
||
912 | |||
913 | static struct value * value_get_path (NCDModuleInst *i, struct value *v, NCDValRef path) |
||
914 | { |
||
915 | ASSERT(NCDVal_IsList(path)) |
||
916 | |||
917 | size_t count = NCDVal_ListCount(path); |
||
918 | |||
919 | for (size_t j = 0; j < count; j++) { |
||
920 | if (!(v = value_get(i, v, NCDVal_ListGet(path, j), 0))) { |
||
921 | goto fail; |
||
922 | } |
||
923 | } |
||
924 | |||
925 | return v; |
||
926 | |||
927 | fail: |
||
928 | return NULL; |
||
929 | } |
||
930 | |||
931 | static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValRef where, NCDValRef what, int is_replace, struct value **out_oldv) |
||
932 | { |
||
933 | ASSERT(v) |
||
934 | ASSERT((NCDVal_Type(where), 1)) |
||
935 | ASSERT((NCDVal_Type(what), 1)) |
||
936 | ASSERT(is_replace == !!is_replace) |
||
937 | |||
938 | struct value *nv = value_init_fromvalue(i, what); |
||
939 | if (!nv) { |
||
940 | goto fail0; |
||
941 | } |
||
942 | |||
943 | struct value *oldv = NULL; |
||
944 | |||
945 | switch (v->type) { |
||
946 | case STOREDSTRING_TYPE: |
||
947 | case IDSTRING_TYPE: |
||
948 | case EXTERNALSTRING_TYPE: { |
||
949 | ModuleLog(i, BLOG_ERROR, "cannot insert into a string"); |
||
950 | goto fail1; |
||
951 | } break; |
||
952 | |||
953 | case NCDVAL_LIST: { |
||
954 | uintmax_t index; |
||
955 | if (!ncd_read_uintmax(where, &index)) { |
||
956 | ModuleLog(i, BLOG_ERROR, "index is not a valid number (inserting into list)"); |
||
957 | goto fail1; |
||
958 | } |
||
959 | |||
960 | if (index > value_list_len(v)) { |
||
961 | ModuleLog(i, BLOG_ERROR, "index is out of bounds (inserting into list)"); |
||
962 | goto fail1; |
||
963 | } |
||
964 | |||
965 | if (is_replace && index < value_list_len(v)) { |
||
966 | oldv = value_list_at(v, index); |
||
967 | |||
968 | value_list_remove(v, oldv); |
||
969 | |||
970 | int res = value_list_insert(i, v, nv, index); |
||
971 | ASSERT_EXECUTE(res) |
||
972 | } else { |
||
973 | if (!value_list_insert(i, v, nv, index)) { |
||
974 | goto fail1; |
||
975 | } |
||
976 | } |
||
977 | } break; |
||
978 | |||
979 | case NCDVAL_MAP: { |
||
980 | oldv = value_map_find(v, where); |
||
981 | |||
982 | if (!oldv && value_map_len(v) == SIZE_MAX) { |
||
983 | ModuleLog(i, BLOG_ERROR, "map has too many elements"); |
||
984 | goto fail1; |
||
985 | } |
||
986 | |||
987 | NCDValMem key_mem; |
||
988 | NCDValMem_Init(&key_mem, i->params->iparams->string_index); |
||
989 | |||
990 | NCDValRef key = NCDVal_NewCopy(&key_mem, where); |
||
991 | if (NCDVal_IsInvalid(key)) { |
||
992 | NCDValMem_Free(&key_mem); |
||
993 | goto fail1; |
||
994 | } |
||
995 | |||
996 | if (oldv) { |
||
997 | value_map_remove(v, oldv); |
||
998 | } |
||
999 | |||
1000 | int res = value_map_insert(v, nv, key_mem, NCDVal_ToSafe(key), i); |
||
1001 | ASSERT_EXECUTE(res) |
||
1002 | } break; |
||
1003 | |||
1004 | default: ASSERT(0); |
||
1005 | } |
||
1006 | |||
1007 | if (out_oldv) { |
||
1008 | *out_oldv = oldv; |
||
1009 | } |
||
1010 | else if (oldv) { |
||
1011 | value_cleanup(oldv); |
||
1012 | } |
||
1013 | |||
1014 | return nv; |
||
1015 | |||
1016 | fail1: |
||
1017 | value_cleanup(nv); |
||
1018 | fail0: |
||
1019 | return NULL; |
||
1020 | } |
||
1021 | |||
1022 | static struct value * value_insert_simple (NCDModuleInst *i, struct value *v, NCDValRef what) |
||
1023 | { |
||
1024 | ASSERT(v) |
||
1025 | ASSERT((NCDVal_Type(what), 1)) |
||
1026 | |||
1027 | struct value *nv = value_init_fromvalue(i, what); |
||
1028 | if (!nv) { |
||
1029 | goto fail0; |
||
1030 | } |
||
1031 | |||
1032 | switch (v->type) { |
||
1033 | case NCDVAL_LIST: { |
||
1034 | if (!value_list_insert(i, v, nv, value_list_len(v))) { |
||
1035 | goto fail1; |
||
1036 | } |
||
1037 | } break; |
||
1038 | |||
1039 | default: |
||
1040 | ModuleLog(i, BLOG_ERROR, "one-argument insert is only defined for lists"); |
||
1041 | return NULL; |
||
1042 | } |
||
1043 | |||
1044 | return nv; |
||
1045 | |||
1046 | fail1: |
||
1047 | value_cleanup(nv); |
||
1048 | fail0: |
||
1049 | return NULL; |
||
1050 | } |
||
1051 | |||
1052 | static int value_remove (NCDModuleInst *i, struct value *v, NCDValRef where) |
||
1053 | { |
||
1054 | ASSERT(v) |
||
1055 | ASSERT((NCDVal_Type(where), 1)) |
||
1056 | |||
1057 | switch (v->type) { |
||
1058 | case STOREDSTRING_TYPE: |
||
1059 | case IDSTRING_TYPE: |
||
1060 | case EXTERNALSTRING_TYPE: { |
||
1061 | ModuleLog(i, BLOG_ERROR, "cannot remove from a string"); |
||
1062 | goto fail; |
||
1063 | } break; |
||
1064 | |||
1065 | case NCDVAL_LIST: { |
||
1066 | uintmax_t index; |
||
1067 | if (!ncd_read_uintmax(where, &index)) { |
||
1068 | ModuleLog(i, BLOG_ERROR, "index is not a valid number (removing from list)"); |
||
1069 | goto fail; |
||
1070 | } |
||
1071 | |||
1072 | if (index >= value_list_len(v)) { |
||
1073 | ModuleLog(i, BLOG_ERROR, "index is out of bounds (removing from list)"); |
||
1074 | goto fail; |
||
1075 | } |
||
1076 | |||
1077 | struct value *ov = value_list_at(v, index); |
||
1078 | |||
1079 | value_list_remove(v, ov); |
||
1080 | value_cleanup(ov); |
||
1081 | } break; |
||
1082 | |||
1083 | case NCDVAL_MAP: { |
||
1084 | struct value *ov = value_map_find(v, where); |
||
1085 | if (!ov) { |
||
1086 | ModuleLog(i, BLOG_ERROR, "key does not exist (removing from map)"); |
||
1087 | goto fail; |
||
1088 | } |
||
1089 | |||
1090 | value_map_remove(v, ov); |
||
1091 | value_cleanup(ov); |
||
1092 | } break; |
||
1093 | |||
1094 | default: ASSERT(0); |
||
1095 | } |
||
1096 | |||
1097 | return 1; |
||
1098 | |||
1099 | fail: |
||
1100 | return 0; |
||
1101 | } |
||
1102 | |||
1103 | static int value_append (NCDModuleInst *i, struct value *v, NCDValRef data) |
||
1104 | { |
||
1105 | ASSERT(v) |
||
1106 | ASSERT((NCDVal_Type(data), 1)) |
||
1107 | |||
1108 | switch (v->type) { |
||
1109 | case STOREDSTRING_TYPE: |
||
1110 | case IDSTRING_TYPE: |
||
1111 | case EXTERNALSTRING_TYPE: { |
||
1112 | if (!NCDVal_IsString(data)) { |
||
1113 | ModuleLog(i, BLOG_ERROR, "cannot append non-string to string"); |
||
1114 | return 0; |
||
1115 | } |
||
1116 | |||
1117 | MemRef v_str = value_string_memref(v); |
||
1118 | size_t append_length = NCDVal_StringLength(data); |
||
1119 | |||
1120 | if (append_length > SIZE_MAX - v_str.len) { |
||
1121 | ModuleLog(i, BLOG_ERROR, "too much data to append"); |
||
1122 | return 0; |
||
1123 | } |
||
1124 | size_t new_length = v_str.len + append_length; |
||
1125 | |||
1126 | if (v->type == STOREDSTRING_TYPE && new_length <= v->storedstring.size) { |
||
1127 | char *existing_buf = (char *)NCDRefString_GetBuf(v->storedstring.rstr); |
||
1128 | NCDVal_StringCopyOut(data, 0, append_length, existing_buf + v_str.len); |
||
1129 | v->storedstring.length = new_length; |
||
1130 | } else { |
||
1131 | // only allocate power-of-two sizez |
||
1132 | size_t new_size = 16; |
||
1133 | while (new_size < new_length) { |
||
1134 | if (new_size > SIZE_MAX / 2) { |
||
1135 | ModuleLog(i, BLOG_ERROR, "too much data to append"); |
||
1136 | return 0; |
||
1137 | } |
||
1138 | new_size *= 2; |
||
1139 | } |
||
1140 | |||
1141 | char *new_buf; |
||
1142 | NCDRefString *new_rstr = NCDRefString_New(new_size, &new_buf); |
||
1143 | if (!new_rstr) { |
||
1144 | ModuleLog(i, BLOG_ERROR, "NCDRefString_New failed"); |
||
1145 | return 0; |
||
1146 | } |
||
1147 | |||
1148 | MemRef_CopyOut(v_str, new_buf); |
||
1149 | NCDVal_StringCopyOut(data, 0, append_length, new_buf + v_str.len); |
||
1150 | |||
1151 | value_string_set_rstr(v, new_rstr, new_length, new_size); |
||
1152 | } |
||
1153 | } break; |
||
1154 | |||
1155 | case NCDVAL_LIST: { |
||
1156 | struct value *nv = value_init_fromvalue(i, data); |
||
1157 | if (!nv) { |
||
1158 | return 0; |
||
1159 | } |
||
1160 | |||
1161 | if (!value_list_insert(i, v, nv, value_list_len(v))) { |
||
1162 | value_cleanup(nv); |
||
1163 | return 0; |
||
1164 | } |
||
1165 | } break; |
||
1166 | |||
1167 | default: |
||
1168 | ModuleLog(i, BLOG_ERROR, "append is only defined for strings and lists"); |
||
1169 | return 0; |
||
1170 | } |
||
1171 | |||
1172 | return 1; |
||
1173 | } |
||
1174 | |||
1175 | static void valref_init (struct valref *r, struct value *v) |
||
1176 | { |
||
1177 | r->v = v; |
||
1178 | |||
1179 | if (v) { |
||
1180 | LinkedList0_Prepend(&v->refs_list, &r->refs_list_node); |
||
1181 | } |
||
1182 | } |
||
1183 | |||
1184 | static void valref_free (struct valref *r) |
||
1185 | { |
||
1186 | if (r->v) { |
||
1187 | LinkedList0_Remove(&r->v->refs_list, &r->refs_list_node); |
||
1188 | value_cleanup(r->v); |
||
1189 | } |
||
1190 | } |
||
1191 | |||
1192 | static struct value * valref_val (struct valref *r) |
||
1193 | { |
||
1194 | return r->v; |
||
1195 | } |
||
1196 | |||
1197 | static void valref_break (struct valref *r) |
||
1198 | { |
||
1199 | ASSERT(r->v) |
||
1200 | |||
1201 | LinkedList0_Remove(&r->v->refs_list, &r->refs_list_node); |
||
1202 | r->v = NULL; |
||
1203 | } |
||
1204 | |||
1205 | static void func_new_common (void *vo, NCDModuleInst *i, struct value *v, value_deinit_func deinit_func, void *deinit_data) |
||
1206 | { |
||
1207 | struct instance *o = vo; |
||
1208 | o->i = i; |
||
1209 | |||
1210 | // init value references |
||
1211 | valref_init(&o->ref, v); |
||
1212 | |||
1213 | // remember deinit |
||
1214 | o->deinit_func = deinit_func; |
||
1215 | o->deinit_data = deinit_data; |
||
1216 | |||
1217 | NCDModuleInst_Backend_Up(i); |
||
1218 | return; |
||
1219 | } |
||
1220 | |||
1221 | static void func_die (void *vo) |
||
1222 | { |
||
1223 | struct instance *o = vo; |
||
1224 | |||
1225 | // deinit |
||
1226 | if (o->deinit_func) { |
||
1227 | o->deinit_func(o->deinit_data, o->i); |
||
1228 | } |
||
1229 | |||
1230 | // free value reference |
||
1231 | valref_free(&o->ref); |
||
1232 | |||
1233 | NCDModuleInst_Backend_Dead(o->i); |
||
1234 | } |
||
1235 | |||
1236 | static int func_getvar2 (void *vo, NCD_string_id_t name, NCDValMem *mem, NCDValRef *out) |
||
1237 | { |
||
1238 | struct instance *o = vo; |
||
1239 | struct value *v = valref_val(&o->ref); |
||
1240 | |||
1241 | if (name == ModuleString(o->i, STRING_EXISTS)) { |
||
1242 | *out = ncd_make_boolean(mem, !!v); |
||
1243 | return 1; |
||
1244 | } |
||
1245 | |||
1246 | if (name != NCD_STRING_TYPE && name != NCD_STRING_LENGTH && |
||
1247 | name != ModuleString(o->i, STRING_KEYS) && name != NCD_STRING_EMPTY) { |
||
1248 | return 0; |
||
1249 | } |
||
1250 | |||
1251 | if (!v) { |
||
1252 | ModuleLog(o->i, BLOG_ERROR, "value was deleted"); |
||
1253 | return 0; |
||
1254 | } |
||
1255 | |||
1256 | if (name == NCD_STRING_TYPE) { |
||
1257 | *out = NCDVal_NewString(mem, get_type_str(v->type)); |
||
1258 | } |
||
1259 | else if (name == NCD_STRING_LENGTH) { |
||
1260 | size_t len = 0; // to remove warning |
||
1261 | switch (v->type) { |
||
1262 | case NCDVAL_LIST: |
||
1263 | len = value_list_len(v); |
||
1264 | break; |
||
1265 | case NCDVAL_MAP: |
||
1266 | len = value_map_len(v); |
||
1267 | break; |
||
1268 | default: |
||
1269 | ASSERT(value_is_string(v)) |
||
1270 | len = value_string_memref(v).len; |
||
1271 | break; |
||
1272 | } |
||
1273 | |||
1274 | *out = ncd_make_uintmax(mem, len); |
||
1275 | } |
||
1276 | else if (name == ModuleString(o->i, STRING_KEYS)) { |
||
1277 | if (v->type != NCDVAL_MAP) { |
||
1278 | ModuleLog(o->i, BLOG_ERROR, "value is not a map (reading keys variable)"); |
||
1279 | return 0; |
||
1280 | } |
||
1281 | |||
1282 | *out = NCDVal_NewList(mem, value_map_len(v)); |
||
1283 | if (NCDVal_IsInvalid(*out)) { |
||
1284 | goto fail; |
||
1285 | } |
||
1286 | |||
1287 | for (size_t j = 0; j < value_map_len(v); j++) { |
||
1288 | struct value *ev = value_map_at(v, j); |
||
1289 | |||
1290 | NCDValRef key = NCDVal_NewCopy(mem, ev->map_parent.key); |
||
1291 | if (NCDVal_IsInvalid(key)) { |
||
1292 | goto fail; |
||
1293 | } |
||
1294 | |||
1295 | if (!NCDVal_ListAppend(*out, key)) { |
||
1296 | goto fail; |
||
1297 | } |
||
1298 | } |
||
1299 | } |
||
1300 | else if (name == NCD_STRING_EMPTY) { |
||
1301 | if (!value_to_value(o->i, v, mem, out)) { |
||
1302 | return 0; |
||
1303 | } |
||
1304 | } |
||
1305 | else { |
||
1306 | ASSERT(0); |
||
1307 | } |
||
1308 | |||
1309 | return 1; |
||
1310 | |||
1311 | fail: |
||
1312 | *out = NCDVal_NewInvalid(); |
||
1313 | return 1; |
||
1314 | } |
||
1315 | |||
1316 | static void func_new_value (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1317 | { |
||
1318 | NCDValRef value_arg; |
||
1319 | if (!NCDVal_ListRead(params->args, 1, &value_arg)) { |
||
1320 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1321 | goto fail0; |
||
1322 | } |
||
1323 | |||
1324 | struct value *v = value_init_fromvalue(i, value_arg); |
||
1325 | if (!v) { |
||
1326 | goto fail0; |
||
1327 | } |
||
1328 | |||
1329 | func_new_common(vo, i, v, NULL, NULL); |
||
1330 | return; |
||
1331 | |||
1332 | fail0: |
||
1333 | NCDModuleInst_Backend_DeadError(i); |
||
1334 | } |
||
1335 | |||
1336 | static void func_new_get (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1337 | { |
||
1338 | NCDValRef where_arg; |
||
1339 | if (!NCDVal_ListRead(params->args, 1, &where_arg)) { |
||
1340 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1341 | goto fail0; |
||
1342 | } |
||
1343 | |||
1344 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1345 | struct value *mov = valref_val(&mo->ref); |
||
1346 | |||
1347 | if (!mov) { |
||
1348 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1349 | goto fail0; |
||
1350 | } |
||
1351 | |||
1352 | struct value *v = value_get(i, mov, where_arg, 0); |
||
1353 | if (!v) { |
||
1354 | goto fail0; |
||
1355 | } |
||
1356 | |||
1357 | func_new_common(vo, i, v, NULL, NULL); |
||
1358 | return; |
||
1359 | |||
1360 | fail0: |
||
1361 | NCDModuleInst_Backend_DeadError(i); |
||
1362 | } |
||
1363 | |||
1364 | static void func_new_try_get (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1365 | { |
||
1366 | NCDValRef where_arg; |
||
1367 | if (!NCDVal_ListRead(params->args, 1, &where_arg)) { |
||
1368 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1369 | goto fail0; |
||
1370 | } |
||
1371 | |||
1372 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1373 | struct value *mov = valref_val(&mo->ref); |
||
1374 | |||
1375 | if (!mov) { |
||
1376 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1377 | goto fail0; |
||
1378 | } |
||
1379 | |||
1380 | struct value *v = value_get(i, mov, where_arg, 1); |
||
1381 | |||
1382 | func_new_common(vo, i, v, NULL, NULL); |
||
1383 | return; |
||
1384 | |||
1385 | fail0: |
||
1386 | NCDModuleInst_Backend_DeadError(i); |
||
1387 | } |
||
1388 | |||
1389 | static void func_new_getpath (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1390 | { |
||
1391 | NCDValRef path_arg; |
||
1392 | if (!NCDVal_ListRead(params->args, 1, &path_arg)) { |
||
1393 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1394 | goto fail0; |
||
1395 | } |
||
1396 | if (!NCDVal_IsList(path_arg)) { |
||
1397 | ModuleLog(i, BLOG_ERROR, "wrong type"); |
||
1398 | goto fail0; |
||
1399 | } |
||
1400 | |||
1401 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1402 | struct value *mov = valref_val(&mo->ref); |
||
1403 | |||
1404 | if (!mov) { |
||
1405 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1406 | goto fail0; |
||
1407 | } |
||
1408 | |||
1409 | struct value *v = value_get_path(i, mov, path_arg); |
||
1410 | if (!v) { |
||
1411 | goto fail0; |
||
1412 | } |
||
1413 | |||
1414 | func_new_common(vo, i, v, NULL, NULL); |
||
1415 | return; |
||
1416 | |||
1417 | fail0: |
||
1418 | NCDModuleInst_Backend_DeadError(i); |
||
1419 | } |
||
1420 | |||
1421 | static void func_new_insert_replace_common (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, int is_replace) |
||
1422 | { |
||
1423 | NCDValRef where_arg = NCDVal_NewInvalid(); |
||
1424 | NCDValRef what_arg; |
||
1425 | if (!(!is_replace && NCDVal_ListRead(params->args, 1, &what_arg)) && |
||
1426 | !NCDVal_ListRead(params->args, 2, &where_arg, &what_arg)) { |
||
1427 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1428 | goto fail0; |
||
1429 | } |
||
1430 | |||
1431 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1432 | struct value *mov = valref_val(&mo->ref); |
||
1433 | |||
1434 | if (!mov) { |
||
1435 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1436 | goto fail0; |
||
1437 | } |
||
1438 | |||
1439 | struct value *v; |
||
1440 | |||
1441 | if (NCDVal_IsInvalid(where_arg)) { |
||
1442 | v = value_insert_simple(i, mov, what_arg); |
||
1443 | } else { |
||
1444 | v = value_insert(i, mov, where_arg, what_arg, is_replace, NULL); |
||
1445 | } |
||
1446 | if (!v) { |
||
1447 | goto fail0; |
||
1448 | } |
||
1449 | |||
1450 | func_new_common(vo, i, v, NULL, NULL); |
||
1451 | return; |
||
1452 | |||
1453 | fail0: |
||
1454 | NCDModuleInst_Backend_DeadError(i); |
||
1455 | } |
||
1456 | |||
1457 | static void func_new_insert (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1458 | { |
||
1459 | func_new_insert_replace_common(vo, i, params, 0); |
||
1460 | } |
||
1461 | |||
1462 | static void func_new_replace (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1463 | { |
||
1464 | func_new_insert_replace_common(vo, i, params, 1); |
||
1465 | } |
||
1466 | |||
1467 | struct insert_undo_deinit_data { |
||
1468 | struct valref val_ref; |
||
1469 | struct valref oldval_ref; |
||
1470 | }; |
||
1471 | |||
1472 | static void undo_deinit_func (struct insert_undo_deinit_data *data, NCDModuleInst *i) |
||
1473 | { |
||
1474 | struct value *val = valref_val(&data->val_ref); |
||
1475 | struct value *oldval = valref_val(&data->oldval_ref); |
||
1476 | |||
1477 | if (val && val->parent && (!oldval || !oldval->parent)) { |
||
1478 | // get parent |
||
1479 | struct value *parent = val->parent; |
||
1480 | |||
1481 | // remove this value from parent and restore saved one (or none) |
||
1482 | switch (parent->type) { |
||
1483 | case NCDVAL_LIST: { |
||
1484 | size_t index = value_list_indexof(parent, val); |
||
1485 | value_list_remove(parent, val); |
||
1486 | if (oldval) { |
||
1487 | int res = value_list_insert(i, parent, oldval, index); |
||
1488 | ASSERT_EXECUTE(res) |
||
1489 | } |
||
1490 | } break; |
||
1491 | |||
1492 | case NCDVAL_MAP: { |
||
1493 | NCDValMem key_mem; |
||
1494 | NCDValSafeRef key; |
||
1495 | value_map_remove2(parent, val, &key_mem, &key); |
||
1496 | if (oldval) { |
||
1497 | int res = value_map_insert(parent, oldval, key_mem, key, i); |
||
1498 | ASSERT_EXECUTE(res) |
||
1499 | } else { |
||
1500 | NCDValMem_Free(&key_mem); |
||
1501 | } |
||
1502 | } break; |
||
1503 | |||
1504 | default: ASSERT(0); |
||
1505 | } |
||
1506 | } |
||
1507 | |||
1508 | valref_free(&data->oldval_ref); |
||
1509 | valref_free(&data->val_ref); |
||
1510 | free(data); |
||
1511 | } |
||
1512 | |||
1513 | static void func_new_insert_replace_undo_common (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, int is_replace) |
||
1514 | { |
||
1515 | NCDValRef where_arg = NCDVal_NewInvalid(); |
||
1516 | NCDValRef what_arg; |
||
1517 | if (!(!is_replace && NCDVal_ListRead(params->args, 1, &what_arg)) && |
||
1518 | !NCDVal_ListRead(params->args, 2, &where_arg, &what_arg)) { |
||
1519 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1520 | goto fail0; |
||
1521 | } |
||
1522 | |||
1523 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1524 | struct value *mov = valref_val(&mo->ref); |
||
1525 | |||
1526 | if (!mov) { |
||
1527 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1528 | goto fail0; |
||
1529 | } |
||
1530 | |||
1531 | struct insert_undo_deinit_data *data = malloc(sizeof(*data)); |
||
1532 | if (!data) { |
||
1533 | ModuleLog(i, BLOG_ERROR, "malloc failed"); |
||
1534 | goto fail0; |
||
1535 | } |
||
1536 | |||
1537 | struct value *oldv; |
||
1538 | struct value *v; |
||
1539 | |||
1540 | if (NCDVal_IsInvalid(where_arg)) { |
||
1541 | oldv = NULL; |
||
1542 | v = value_insert_simple(i, mov, what_arg); |
||
1543 | } else { |
||
1544 | v = value_insert(i, mov, where_arg, what_arg, is_replace, &oldv); |
||
1545 | } |
||
1546 | if (!v) { |
||
1547 | goto fail1; |
||
1548 | } |
||
1549 | |||
1550 | valref_init(&data->val_ref, v); |
||
1551 | valref_init(&data->oldval_ref, oldv); |
||
1552 | |||
1553 | func_new_common(vo, i, v, (value_deinit_func)undo_deinit_func, data); |
||
1554 | return; |
||
1555 | |||
1556 | fail1: |
||
1557 | free(data); |
||
1558 | fail0: |
||
1559 | NCDModuleInst_Backend_DeadError(i); |
||
1560 | } |
||
1561 | |||
1562 | static void func_new_insert_undo (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1563 | { |
||
1564 | func_new_insert_replace_undo_common(vo, i, params, 0); |
||
1565 | } |
||
1566 | |||
1567 | static void func_new_replace_undo (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1568 | { |
||
1569 | func_new_insert_replace_undo_common(vo, i, params, 1); |
||
1570 | } |
||
1571 | |||
1572 | static void func_new_replace_this (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1573 | { |
||
1574 | NCDValRef value_arg; |
||
1575 | if (!NCDVal_ListRead(params->args, 1, &value_arg)) { |
||
1576 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1577 | goto fail0; |
||
1578 | } |
||
1579 | |||
1580 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1581 | struct value *mov = valref_val(&mo->ref); |
||
1582 | |||
1583 | if (!mov) { |
||
1584 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1585 | goto fail0; |
||
1586 | } |
||
1587 | |||
1588 | struct value *v = value_init_fromvalue(i, value_arg); |
||
1589 | if (!v) { |
||
1590 | goto fail0; |
||
1591 | } |
||
1592 | |||
1593 | if (mov->parent) { |
||
1594 | struct value *parent = mov->parent; |
||
1595 | |||
1596 | switch (parent->type) { |
||
1597 | case NCDVAL_LIST: { |
||
1598 | size_t index = value_list_indexof(parent, mov); |
||
1599 | value_list_remove(parent, mov); |
||
1600 | int res = value_list_insert(i, parent, v, index); |
||
1601 | ASSERT_EXECUTE(res) |
||
1602 | } break; |
||
1603 | |||
1604 | case NCDVAL_MAP: { |
||
1605 | NCDValMem key_mem; |
||
1606 | NCDValSafeRef key; |
||
1607 | value_map_remove2(parent, mov, &key_mem, &key); |
||
1608 | int res = value_map_insert(parent, v, key_mem, key, i); |
||
1609 | ASSERT_EXECUTE(res) |
||
1610 | } break; |
||
1611 | |||
1612 | default: ASSERT(0); |
||
1613 | } |
||
1614 | |||
1615 | value_cleanup(mov); |
||
1616 | } |
||
1617 | |||
1618 | func_new_common(vo, i, v, NULL, NULL); |
||
1619 | return; |
||
1620 | |||
1621 | fail0: |
||
1622 | NCDModuleInst_Backend_DeadError(i); |
||
1623 | } |
||
1624 | |||
1625 | static void func_new_replace_this_undo (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1626 | { |
||
1627 | NCDValRef value_arg; |
||
1628 | if (!NCDVal_ListRead(params->args, 1, &value_arg)) { |
||
1629 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1630 | goto fail0; |
||
1631 | } |
||
1632 | |||
1633 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1634 | struct value *mov = valref_val(&mo->ref); |
||
1635 | |||
1636 | if (!mov) { |
||
1637 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1638 | goto fail0; |
||
1639 | } |
||
1640 | |||
1641 | struct value *v = value_init_fromvalue(i, value_arg); |
||
1642 | if (!v) { |
||
1643 | goto fail0; |
||
1644 | } |
||
1645 | |||
1646 | struct insert_undo_deinit_data *data = malloc(sizeof(*data)); |
||
1647 | if (!data) { |
||
1648 | ModuleLog(i, BLOG_ERROR, "malloc failed"); |
||
1649 | goto fail1; |
||
1650 | } |
||
1651 | |||
1652 | valref_init(&data->val_ref, v); |
||
1653 | valref_init(&data->oldval_ref, mov); |
||
1654 | |||
1655 | if (mov->parent) { |
||
1656 | struct value *parent = mov->parent; |
||
1657 | |||
1658 | switch (parent->type) { |
||
1659 | case NCDVAL_LIST: { |
||
1660 | size_t index = value_list_indexof(parent, mov); |
||
1661 | value_list_remove(parent, mov); |
||
1662 | int res = value_list_insert(i, parent, v, index); |
||
1663 | ASSERT_EXECUTE(res) |
||
1664 | } break; |
||
1665 | |||
1666 | case NCDVAL_MAP: { |
||
1667 | NCDValMem key_mem; |
||
1668 | NCDValSafeRef key; |
||
1669 | value_map_remove2(parent, mov, &key_mem, &key); |
||
1670 | int res = value_map_insert(parent, v, key_mem, key, i); |
||
1671 | ASSERT_EXECUTE(res) |
||
1672 | } break; |
||
1673 | |||
1674 | default: ASSERT(0); |
||
1675 | } |
||
1676 | } |
||
1677 | |||
1678 | func_new_common(vo, i, v, (value_deinit_func)undo_deinit_func, data); |
||
1679 | return; |
||
1680 | |||
1681 | fail1: |
||
1682 | value_cleanup(v); |
||
1683 | fail0: |
||
1684 | NCDModuleInst_Backend_DeadError(i); |
||
1685 | } |
||
1686 | |||
1687 | static void func_new_substr (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1688 | { |
||
1689 | NCDValRef start_arg; |
||
1690 | NCDValRef length_arg = NCDVal_NewInvalid(); |
||
1691 | if (!NCDVal_ListRead(params->args, 1, &start_arg) && |
||
1692 | !NCDVal_ListRead(params->args, 2, &start_arg, &length_arg)) { |
||
1693 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1694 | goto fail0; |
||
1695 | } |
||
1696 | |||
1697 | uintmax_t start; |
||
1698 | if (!ncd_read_uintmax(start_arg, &start)) { |
||
1699 | ModuleLog(i, BLOG_ERROR, "start is not a number"); |
||
1700 | goto fail0; |
||
1701 | } |
||
1702 | |||
1703 | uintmax_t length = UINTMAX_MAX; |
||
1704 | if (!NCDVal_IsInvalid(length_arg) && !ncd_read_uintmax(length_arg, &length)) { |
||
1705 | ModuleLog(i, BLOG_ERROR, "length is not a number"); |
||
1706 | goto fail0; |
||
1707 | } |
||
1708 | |||
1709 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1710 | struct value *mov = valref_val(&mo->ref); |
||
1711 | |||
1712 | if (!mov) { |
||
1713 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1714 | goto fail0; |
||
1715 | } |
||
1716 | |||
1717 | if (!value_is_string(mov)) { |
||
1718 | ModuleLog(i, BLOG_ERROR, "value is not a string"); |
||
1719 | goto fail0; |
||
1720 | } |
||
1721 | |||
1722 | MemRef string = value_string_memref(mov); |
||
1723 | |||
1724 | if (start > string.len) { |
||
1725 | ModuleLog(i, BLOG_ERROR, "start is out of range"); |
||
1726 | goto fail0; |
||
1727 | } |
||
1728 | |||
1729 | size_t remain = string.len - start; |
||
1730 | size_t amount = length < remain ? length : remain; |
||
1731 | |||
1732 | MemRef sub_string = MemRef_Sub(string, start, amount); |
||
1733 | |||
1734 | struct value *v = NULL; |
||
1735 | switch (mov->type) { |
||
1736 | case STOREDSTRING_TYPE: { |
||
1737 | v = value_init_externalstring(i, sub_string, NCDRefString_RefTarget(mov->storedstring.rstr)); |
||
1738 | } break; |
||
1739 | case IDSTRING_TYPE: { |
||
1740 | v = value_init_storedstring(i, sub_string); |
||
1741 | } break; |
||
1742 | case EXTERNALSTRING_TYPE: { |
||
1743 | v = value_init_externalstring(i, sub_string, mov->externalstring.ref_target); |
||
1744 | } break; |
||
1745 | default: |
||
1746 | ASSERT(0); |
||
1747 | } |
||
1748 | |||
1749 | if (!v) { |
||
1750 | goto fail0; |
||
1751 | } |
||
1752 | |||
1753 | func_new_common(vo, i, v, NULL, NULL); |
||
1754 | return; |
||
1755 | |||
1756 | fail0: |
||
1757 | NCDModuleInst_Backend_DeadError(i); |
||
1758 | } |
||
1759 | |||
1760 | static void remove_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1761 | { |
||
1762 | NCDValRef where_arg; |
||
1763 | if (!NCDVal_ListRead(params->args, 1, &where_arg)) { |
||
1764 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1765 | goto fail0; |
||
1766 | } |
||
1767 | |||
1768 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1769 | struct value *mov = valref_val(&mo->ref); |
||
1770 | |||
1771 | if (!mov) { |
||
1772 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1773 | goto fail0; |
||
1774 | } |
||
1775 | |||
1776 | if (!value_remove(i, mov, where_arg)) { |
||
1777 | goto fail0; |
||
1778 | } |
||
1779 | |||
1780 | NCDModuleInst_Backend_Up(i); |
||
1781 | return; |
||
1782 | |||
1783 | fail0: |
||
1784 | NCDModuleInst_Backend_DeadError(i); |
||
1785 | } |
||
1786 | |||
1787 | static void delete_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1788 | { |
||
1789 | if (!NCDVal_ListRead(params->args, 0)) { |
||
1790 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1791 | goto fail0; |
||
1792 | } |
||
1793 | |||
1794 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1795 | struct value *mov = valref_val(&mo->ref); |
||
1796 | |||
1797 | if (!mov) { |
||
1798 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1799 | goto fail0; |
||
1800 | } |
||
1801 | |||
1802 | value_delete(mov); |
||
1803 | |||
1804 | NCDModuleInst_Backend_Up(i); |
||
1805 | return; |
||
1806 | |||
1807 | fail0: |
||
1808 | NCDModuleInst_Backend_DeadError(i); |
||
1809 | } |
||
1810 | |||
1811 | static void reset_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1812 | { |
||
1813 | NCDValRef what_arg; |
||
1814 | if (!NCDVal_ListRead(params->args, 1, &what_arg)) { |
||
1815 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1816 | goto fail0; |
||
1817 | } |
||
1818 | |||
1819 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1820 | |||
1821 | // build value from argument |
||
1822 | struct value *newv = value_init_fromvalue(i, what_arg); |
||
1823 | if (!newv) { |
||
1824 | goto fail0; |
||
1825 | } |
||
1826 | |||
1827 | // deinit |
||
1828 | if (mo->deinit_func) { |
||
1829 | mo->deinit_func(mo->deinit_data, i); |
||
1830 | } |
||
1831 | |||
1832 | // free value reference |
||
1833 | valref_free(&mo->ref); |
||
1834 | |||
1835 | // set up value reference |
||
1836 | valref_init(&mo->ref, newv); |
||
1837 | |||
1838 | // set no deinit function |
||
1839 | mo->deinit_func = NULL; |
||
1840 | |||
1841 | NCDModuleInst_Backend_Up(i); |
||
1842 | return; |
||
1843 | |||
1844 | fail0: |
||
1845 | NCDModuleInst_Backend_DeadError(i); |
||
1846 | } |
||
1847 | |||
1848 | static void append_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params) |
||
1849 | { |
||
1850 | NCDValRef data_arg; |
||
1851 | if (!NCDVal_ListRead(params->args, 1, &data_arg)) { |
||
1852 | ModuleLog(i, BLOG_ERROR, "wrong arity"); |
||
1853 | goto fail0; |
||
1854 | } |
||
1855 | |||
1856 | struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user); |
||
1857 | struct value *mov = valref_val(&mo->ref); |
||
1858 | |||
1859 | if (!mov) { |
||
1860 | ModuleLog(i, BLOG_ERROR, "value was deleted"); |
||
1861 | goto fail0; |
||
1862 | } |
||
1863 | |||
1864 | if (!value_append(i, mov, data_arg)) { |
||
1865 | goto fail0; |
||
1866 | } |
||
1867 | |||
1868 | NCDModuleInst_Backend_Up(i); |
||
1869 | return; |
||
1870 | |||
1871 | fail0: |
||
1872 | NCDModuleInst_Backend_DeadError(i); |
||
1873 | } |
||
1874 | |||
1875 | static struct NCDModule modules[] = { |
||
1876 | { |
||
1877 | .type = "value", |
||
1878 | .func_new2 = func_new_value, |
||
1879 | .func_die = func_die, |
||
1880 | .func_getvar2 = func_getvar2, |
||
1881 | .alloc_size = sizeof(struct instance) |
||
1882 | }, { |
||
1883 | .type = "value::get", |
||
1884 | .base_type = "value", |
||
1885 | .func_new2 = func_new_get, |
||
1886 | .func_die = func_die, |
||
1887 | .func_getvar2 = func_getvar2, |
||
1888 | .alloc_size = sizeof(struct instance) |
||
1889 | }, { |
||
1890 | .type = "value::try_get", |
||
1891 | .base_type = "value", |
||
1892 | .func_new2 = func_new_try_get, |
||
1893 | .func_die = func_die, |
||
1894 | .func_getvar2 = func_getvar2, |
||
1895 | .alloc_size = sizeof(struct instance) |
||
1896 | }, { |
||
1897 | .type = "value::getpath", |
||
1898 | .base_type = "value", |
||
1899 | .func_new2 = func_new_getpath, |
||
1900 | .func_die = func_die, |
||
1901 | .func_getvar2 = func_getvar2, |
||
1902 | .alloc_size = sizeof(struct instance) |
||
1903 | }, { |
||
1904 | .type = "value::insert", |
||
1905 | .base_type = "value", |
||
1906 | .func_new2 = func_new_insert, |
||
1907 | .func_die = func_die, |
||
1908 | .func_getvar2 = func_getvar2, |
||
1909 | .alloc_size = sizeof(struct instance) |
||
1910 | }, { |
||
1911 | .type = "value::replace", |
||
1912 | .base_type = "value", |
||
1913 | .func_new2 = func_new_replace, |
||
1914 | .func_die = func_die, |
||
1915 | .func_getvar2 = func_getvar2, |
||
1916 | .alloc_size = sizeof(struct instance) |
||
1917 | }, { |
||
1918 | .type = "value::replace_this", |
||
1919 | .base_type = "value", |
||
1920 | .func_new2 = func_new_replace_this, |
||
1921 | .func_die = func_die, |
||
1922 | .func_getvar2 = func_getvar2, |
||
1923 | .alloc_size = sizeof(struct instance) |
||
1924 | }, { |
||
1925 | .type = "value::insert_undo", |
||
1926 | .base_type = "value", |
||
1927 | .func_new2 = func_new_insert_undo, |
||
1928 | .func_die = func_die, |
||
1929 | .func_getvar2 = func_getvar2, |
||
1930 | .alloc_size = sizeof(struct instance) |
||
1931 | }, { |
||
1932 | .type = "value::replace_undo", |
||
1933 | .base_type = "value", |
||
1934 | .func_new2 = func_new_replace_undo, |
||
1935 | .func_die = func_die, |
||
1936 | .func_getvar2 = func_getvar2, |
||
1937 | .alloc_size = sizeof(struct instance) |
||
1938 | }, { |
||
1939 | .type = "value::replace_this_undo", |
||
1940 | .base_type = "value", |
||
1941 | .func_new2 = func_new_replace_this_undo, |
||
1942 | .func_die = func_die, |
||
1943 | .func_getvar2 = func_getvar2, |
||
1944 | .alloc_size = sizeof(struct instance) |
||
1945 | }, { |
||
1946 | .type = "value::remove", |
||
1947 | .func_new2 = remove_func_new |
||
1948 | }, { |
||
1949 | .type = "value::delete", |
||
1950 | .func_new2 = delete_func_new |
||
1951 | }, { |
||
1952 | .type = "value::reset", |
||
1953 | .func_new2 = reset_func_new |
||
1954 | }, { |
||
1955 | .type = "value::substr", |
||
1956 | .base_type = "value", |
||
1957 | .func_new2 = func_new_substr, |
||
1958 | .func_die = func_die, |
||
1959 | .func_getvar2 = func_getvar2, |
||
1960 | .alloc_size = sizeof(struct instance) |
||
1961 | }, { |
||
1962 | .type = "value::append", |
||
1963 | .func_new2 = append_func_new |
||
1964 | }, { |
||
1965 | .type = NULL |
||
1966 | } |
||
1967 | }; |
||
1968 | |||
1969 | const struct NCDModuleGroup ncdmodule_value = { |
||
1970 | .modules = modules, |
||
1971 | .strings = strings |
||
1972 | }; |