BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
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 };