Jelajahi Sumber

ncd: make a new more efficient value storage object NCDVal, and migrate things from NCDValue to NCDVal

ambrop7 14 tahun lalu
induk
melakukan
27c36e7859
80 mengubah file dengan 3107 tambahan dan 1635 penghapusan
  1. 3 0
      examples/CMakeLists.txt
  2. 98 0
      examples/ncdval_test.c
  3. 12 3
      ncd/CMakeLists.txt
  4. 33 37
      ncd/NCDModule.c
  5. 21 28
      ncd/NCDModule.h
  6. 9 11
      ncd/NCDObject.c
  7. 5 5
      ncd/NCDObject.h
  8. 729 0
      ncd/NCDVal.c
  9. 151 0
      ncd/NCDVal.h
  10. 161 0
      ncd/NCDValCompat.c
  11. 56 0
      ncd/NCDValCompat.h
  12. 13 0
      ncd/NCDVal_maptree.h
  13. 153 0
      ncd/NCDValueGenerator.c
  14. 4 0
      ncd/NCDValueGenerator.h
  15. 21 0
      ncd/NCDValueParser.c
  16. 3 0
      ncd/NCDValueParser.h
  17. 4 4
      ncd/modules/alias.c
  18. 9 9
      ncd/modules/arithmetic.c
  19. 4 4
      ncd/modules/blocker.c
  20. 17 9
      ncd/modules/call.c
  21. 60 73
      ncd/modules/call2.c
  22. 22 21
      ncd/modules/choose.c
  23. 10 11
      ncd/modules/concat.c
  24. 13 14
      ncd/modules/concatv.c
  25. 18 13
      ncd/modules/daemon.c
  26. 12 12
      ncd/modules/depend.c
  27. 12 12
      ncd/modules/dynamic_depend.c
  28. 4 5
      ncd/modules/event_template.c
  29. 1 1
      ncd/modules/event_template.h
  30. 4 4
      ncd/modules/exit.c
  31. 13 13
      ncd/modules/file.c
  32. 26 39
      ncd/modules/foreach.c
  33. 19 13
      ncd/modules/from_string.c
  34. 3 3
      ncd/modules/getargs.c
  35. 6 6
      ncd/modules/if.c
  36. 18 27
      ncd/modules/imperative.c
  37. 16 14
      ncd/modules/implode.c
  38. 8 9
      ncd/modules/index.c
  39. 12 13
      ncd/modules/ip_in_network.c
  40. 284 179
      ncd/modules/list.c
  41. 19 19
      ncd/modules/logical.c
  42. 18 17
      ncd/modules/multidepend.c
  43. 22 23
      ncd/modules/net_backend_badvpn.c
  44. 6 6
      ncd/modules/net_backend_rfkill.c
  45. 4 4
      ncd/modules/net_backend_waitdevice.c
  46. 4 4
      ncd/modules/net_backend_waitlink.c
  47. 27 29
      ncd/modules/net_backend_wpa_supplicant.c
  48. 11 11
      ncd/modules/net_dns.c
  49. 29 29
      ncd/modules/net_iptables.c
  50. 8 8
      ncd/modules/net_ipv4_addr.c
  51. 11 12
      ncd/modules/net_ipv4_arp_probe.c
  52. 43 46
      ncd/modules/net_ipv4_dhcp.c
  53. 14 14
      ncd/modules/net_ipv4_route.c
  54. 11 11
      ncd/modules/net_ipv6_wait_dynamic_addr.c
  55. 4 4
      ncd/modules/net_up.c
  56. 4 4
      ncd/modules/net_watch_interfaces.c
  57. 22 24
      ncd/modules/netmask.c
  58. 9 17
      ncd/modules/ondemand.c
  59. 31 27
      ncd/modules/parse.c
  60. 11 6
      ncd/modules/print.c
  61. 57 38
      ncd/modules/process_manager.c
  62. 2 2
      ncd/modules/ref.c
  63. 35 38
      ncd/modules/regex_match.c
  64. 15 13
      ncd/modules/run.c
  65. 29 22
      ncd/modules/runonce.c
  66. 6 6
      ncd/modules/sleep.c
  67. 6 16
      ncd/modules/spawn.c
  68. 22 46
      ncd/modules/strcmp.c
  69. 18 23
      ncd/modules/sys_evdev.c
  70. 82 72
      ncd/modules/sys_request_client.c
  71. 59 61
      ncd/modules/sys_request_server.c
  72. 21 21
      ncd/modules/sys_watch_directory.c
  73. 8 8
      ncd/modules/sys_watch_input.c
  74. 4 4
      ncd/modules/sys_watch_usb.c
  75. 8 8
      ncd/modules/to_string.c
  76. 15 22
      ncd/modules/try.c
  77. 216 206
      ncd/modules/value.c
  78. 20 20
      ncd/modules/valuemetic.c
  79. 35 23
      ncd/modules/var.c
  80. 74 79
      ncd/ncd.c

+ 3 - 0
examples/CMakeLists.txt

@@ -39,6 +39,9 @@ if (BUILD_NCD)
 
     add_executable(ncdinterfacemonitor_test ncdinterfacemonitor_test.c)
     target_link_libraries(ncdinterfacemonitor_test ncdinterfacemonitor)
+
+    add_executable(ncdval_test ncdval_test.c)
+    target_link_libraries(ncdval_test ncdval)
 endif ()
 
 if (BUILDING_UDEVMONITOR)

+ 98 - 0
examples/ncdval_test.c

@@ -0,0 +1,98 @@
+#include <stdio.h>
+
+#include <ncd/NCDVal.h>
+#include <misc/debug.h>
+
+#define FORCE(cmd) if (!(cmd)) { fprintf(stderr, "failed\n"); exit(1); }
+
+static void print_indent (int indent)
+{
+    for (int i = 0; i < indent; i++) {
+        printf("  ");
+    }
+}
+
+static void print_value (NCDValRef val, unsigned int indent)
+{
+    switch (NCDVal_Type(val)) {
+        case NCDVAL_STRING: {
+            print_indent(indent);
+            printf("string(%zu) %s\n", NCDVal_StringLength(val), NCDVal_StringValue(val));
+        } break;
+        
+        case NCDVAL_LIST: {
+            size_t count = NCDVal_ListCount(val);
+            
+            print_indent(indent);
+            printf("list(%zu)\n", NCDVal_ListCount(val));
+            
+            for (size_t i = 0; i < count; i++) {
+                NCDValRef elem_val = NCDVal_ListGet(val, i);
+                print_value(elem_val, indent + 1);
+            }
+        } break;
+        
+        case NCDVAL_MAP: {
+            print_indent(indent);
+            printf("map\n");
+            
+            for (NCDValMapElem e = NCDVal_MapFirst(val); !NCDVal_MapElemInvalid(e); e = NCDVal_MapNext(val, e)) {
+                NCDValRef ekey = NCDVal_MapElemKey(val, e);
+                NCDValRef eval = NCDVal_MapElemVal(val, e);
+                
+                print_indent(indent + 1);
+                printf("key=\n");
+                print_value(ekey, indent + 2);
+                
+                print_indent(indent + 1);
+                printf("val=\n");
+                print_value(eval, indent + 2);
+            }
+        } break;
+    }
+}
+
+int main ()
+{
+    NCDValMem mem;
+    NCDValMem_Init(&mem);
+    
+    NCDValRef s1 = NCDVal_NewString(&mem, "Hello World");
+    FORCE( !NCDVal_IsInvalid(s1) )
+    
+    NCDValRef s2 = NCDVal_NewString(&mem, "This is reeeeeeeeeeeeeallllllllyyyyy fun!");
+    FORCE( !NCDVal_IsInvalid(s2) )
+    
+    printf("%s. %s\n", NCDVal_StringValue(s1), NCDVal_StringValue(s2));
+    
+    NCDValRef l1 = NCDVal_NewList(&mem, 10);
+    FORCE( !NCDVal_IsInvalid(l1) )
+    
+    NCDVal_ListAppend(l1, s1);
+    NCDVal_ListAppend(l1, s2);
+    
+    print_value(s1, 0);
+    print_value(s2, 0);
+    print_value(l1, 0);
+    
+    NCDValRef k1 = NCDVal_NewString(&mem, "K1");
+    FORCE( !NCDVal_IsInvalid(k1) )
+    NCDValRef v1 = NCDVal_NewString(&mem, "V1");
+    FORCE( !NCDVal_IsInvalid(v1) )
+    
+    NCDValRef k2 = NCDVal_NewString(&mem, "K2");
+    FORCE( !NCDVal_IsInvalid(k2) )
+    NCDValRef v2 = NCDVal_NewString(&mem, "V2");
+    FORCE( !NCDVal_IsInvalid(v2) )
+    
+    NCDValRef m1 = NCDVal_NewMap(&mem, 2);
+    FORCE( !NCDVal_IsInvalid(m1) )
+    
+    FORCE( NCDVal_MapInsert(m1, k1, v1) )
+    FORCE( NCDVal_MapInsert(m1, k2, v2) )
+    
+    print_value(m1, 0);
+    
+    NCDValMem_Free(&mem);
+    return 0;
+}

+ 12 - 3
ncd/CMakeLists.txt

@@ -30,16 +30,25 @@ add_library(ncdvalue
     NCDValue.c
 )
 
+add_library(ncdval
+    NCDVal.c
+)
+
+add_library(ncdvalcompat
+    NCDValCompat.c
+)
+target_link_libraries(ncdvalcompat ncdvalue ncdval)
+
 add_library(ncdvaluegenerator
     NCDValueGenerator.c
 )
-target_link_libraries(ncdvaluegenerator base ncdvalue)
+target_link_libraries(ncdvaluegenerator base ncdvalue ncdval)
 
 add_library(ncdvalueparser
     NCDConfig.c
     NCDValueParser.c
 )
-target_link_libraries(ncdvalueparser base ncdvalue ncdtokenizer)
+target_link_libraries(ncdvalueparser base ncdvalue ncdval ncdtokenizer ncdvalcompat)
 
 add_library(ncdast
     NCDAst.c
@@ -134,7 +143,7 @@ add_executable(badvpn-ncd
     modules/call2.c
     ${NCD_ADDITIONAL_SOURCES}
 )
-target_link_libraries(badvpn-ncd system flow flowextra dhcpclient arpprobe ncdvalue ncdvaluegenerator ncdvalueparser ncdconfigparser udevmonitor ncdinterfacemonitor ncdrequest)
+target_link_libraries(badvpn-ncd system flow flowextra dhcpclient arpprobe ncdvalue ncdval ncdvalcompat ncdvaluegenerator ncdvalueparser ncdconfigparser udevmonitor ncdinterfacemonitor ncdrequest)
 
 if (BADVPN_USE_LINUX_INPUT)
     string(REPLACE " " ";" FLAGS_LIST "${CMAKE_C_FLAGS}")

+ 33 - 37
ncd/NCDModule.c

@@ -30,6 +30,8 @@
 #include <stdarg.h>
 #include <string.h>
 #include <stddef.h>
+#include <inttypes.h>
+#include <limits.h>
 
 #include <misc/string_begins_with.h>
 #include <misc/parse_number.h>
@@ -58,10 +60,10 @@
 #define PROCESS_STATE_TERMINATED_PENDING 9
 #define PROCESS_STATE_TERMINATED 10
 
-static int object_func_getvar (NCDModuleInst *n, const char *name, NCDValue *out_value);
+static int object_func_getvar (NCDModuleInst *n, const char *name, NCDValMem *mem, NCDValRef *out_value);
 static int object_func_getobj (NCDModuleInst *n, const char *name, NCDObject *out_object);
-static int process_args_object_func_getvar (NCDModuleProcess *o, const char *name, NCDValue *out_value);
-static int process_arg_object_func_getvar2 (NCDModuleProcess *o, NCDValue *arg, const char *name, NCDValue *out_value);
+static int process_args_object_func_getvar (NCDModuleProcess *o, const char *name, NCDValMem *mem, NCDValRef *out_value);
+static int process_arg_object_func_getvar2 (NCDModuleProcess *o, void *n_ptr, const char *name, NCDValMem *mem, NCDValRef *out_value);
 
 static void frontend_event (NCDModuleInst *n, int event)
 {
@@ -156,11 +158,10 @@ static void inst_assert_backend (NCDModuleInst *n)
            n->state == STATE_DYING)
 }
 
-void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, const NCDObject *method_object, NCDValue *args, void *user, const struct NCDModuleInst_params *params, const struct NCDModuleInst_iparams *iparams)
+void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, const NCDObject *method_object, NCDValRef args, void *user, const struct NCDModuleInst_params *params, const struct NCDModuleInst_iparams *iparams)
 {
     ASSERT(m)
-    ASSERT(args)
-    ASSERT(NCDValue_Type(args) == NCDVALUE_LIST)
+    ASSERT(NCDVal_IsList(args))
     ASSERT(params)
     ASSERT(params->func_event)
     ASSERT(params->func_getobj)
@@ -278,7 +279,7 @@ static int can_resolve (NCDModuleInst *n)
     }
 }
 
-static int object_func_getvar (NCDModuleInst *n, const char *name, NCDValue *out_value)
+static int object_func_getvar (NCDModuleInst *n, const char *name, NCDValMem *mem, NCDValRef *out_value)
 {
     DebugObject_Access(&n->d_obj);
     
@@ -286,8 +287,9 @@ static int object_func_getvar (NCDModuleInst *n, const char *name, NCDValue *out
         return 0;
     }
     
-    int res = n->m->func_getvar(n->inst_user, name, out_value);
+    int res = n->m->func_getvar(n->inst_user, name, mem, out_value);
     ASSERT(res == 0 || res == 1)
+    ASSERT(res == 0 || (NCDVal_Assert(*out_value), 1))
     
     return res;
 }
@@ -451,15 +453,16 @@ void NCDModuleInst_Backend_InterpExit (NCDModuleInst *n, int exit_code)
     n->iparams->func_interp_exit(n->user, exit_code);
 }
 
-int NCDModuleInst_Backend_InterpGetArgs (NCDModuleInst *n, NCDValue *out_value)
+int NCDModuleInst_Backend_InterpGetArgs (NCDModuleInst *n, NCDValMem *mem, NCDValRef *out_value)
 {
     DebugObject_Access(&n->d_obj);
     inst_assert_backend(n);
+    ASSERT(mem)
     ASSERT(out_value)
     
-    int res = n->iparams->func_interp_getargs(n->user, out_value);
+    int res = n->iparams->func_interp_getargs(n->user, mem, out_value);
     ASSERT(res == 0 || res == 1)
-    ASSERT(!res || (NCDValue_Type(out_value), 1))
+    ASSERT(res == 0 || (NCDVal_Assert(*out_value), 1))
     
     return res;
 }
@@ -472,14 +475,14 @@ btime_t NCDModuleInst_Backend_InterpGetRetryTime (NCDModuleInst *n)
     return n->iparams->func_interp_getretrytime(n->user);
 }
 
-int NCDModuleProcess_Init (NCDModuleProcess *o, NCDModuleInst *n, const char *template_name, NCDValue args, void *user, NCDModuleProcess_handler_event handler_event)
+int NCDModuleProcess_Init (NCDModuleProcess *o, NCDModuleInst *n, const char *template_name, NCDValRef args, void *user, NCDModuleProcess_handler_event handler_event)
 {
     DebugObject_Access(&n->d_obj);
     ASSERT(n->state == STATE_DOWN_PCLEAN || n->state == STATE_DOWN_UNCLEAN || n->state == STATE_DOWN_CLEAN ||
            n->state == STATE_UP || n->state == STATE_DOWN_DIE || n->state == STATE_UP_DIE ||
            n->state == STATE_DYING)
     ASSERT(template_name)
-    ASSERT(NCDValue_Type(&args) == NCDVALUE_LIST)
+    ASSERT(NCDVal_IsInvalid(args) || NCDVal_IsList(args))
     ASSERT(handler_event)
     
     // init arguments
@@ -496,9 +499,6 @@ int NCDModuleProcess_Init (NCDModuleProcess *o, NCDModuleInst *n, const char *te
     // set state
     o->state = PROCESS_STATE_INIT;
     
-    // set not no args
-    o->no_args = 0;
-    
     // clear interp functions so we can assert they were set
     o->interp_func_event = NULL;
     o->interp_func_getobj = NULL;
@@ -529,9 +529,6 @@ void NCDModuleProcess_Free (NCDModuleProcess *o)
     
     // free event job
     BPending_Free(&o->event_job);
-    
-    // free arguments
-    NCDValue_Free(&o->args);
 }
 
 void NCDModuleProcess_AssertFree (NCDModuleProcess *o)
@@ -547,13 +544,6 @@ void NCDModuleProcess_SetSpecialFuncs (NCDModuleProcess *o, NCDModuleProcess_fun
     o->func_getspecialobj = func_getspecialobj;
 }
 
-void NCDModuleProcess_SetNoArgs (NCDModuleProcess *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    o->no_args = 1;
-}
-
 void NCDModuleProcess_Continue (NCDModuleProcess *o)
 {
     DebugObject_Access(&o->d_obj);
@@ -665,7 +655,7 @@ int NCDModuleProcess_Interp_GetSpecialObj (NCDModuleProcess *o, const char *name
     ASSERT(name)
     ASSERT(out_object)
     
-    if (!o->no_args) {
+    if (!NCDVal_IsInvalid(o->args)) {
         if (!strcmp(name, "_args")) {
             *out_object = NCDObject_Build(NULL, o, (NCDObject_func_getvar)process_args_object_func_getvar, NULL);
             return 1;
@@ -673,8 +663,8 @@ int NCDModuleProcess_Interp_GetSpecialObj (NCDModuleProcess *o, const char *name
         
         size_t len;
         uintmax_t n;
-        if ((len = string_begins_with(name, "_arg")) && parse_unsigned_integer(name + len, &n) && n < NCDValue_ListCount(&o->args)) {
-            *out_object = NCDObject_Build2(NULL, o, NCDValue_ListGet(&o->args, n), (NCDObject_func_getvar2)process_arg_object_func_getvar2, NULL);
+        if ((len = string_begins_with(name, "_arg")) && parse_unsigned_integer(name + len, &n) && n < NCDVal_ListCount(o->args) && n < UINTPTR_MAX) {
+            *out_object = NCDObject_Build2(NULL, o, (void *)((uintptr_t)(n + 1)), (NCDObject_func_getvar2)process_arg_object_func_getvar2, NULL);
             return 1;
         }
     }
@@ -689,32 +679,38 @@ int NCDModuleProcess_Interp_GetSpecialObj (NCDModuleProcess *o, const char *name
     return res;
 }
 
-static int process_args_object_func_getvar (NCDModuleProcess *o, const char *name, NCDValue *out_value)
+static int process_args_object_func_getvar (NCDModuleProcess *o, const char *name, NCDValMem *mem, NCDValRef *out_value)
 {
     DebugObject_Access(&o->d_obj);
     process_assert_interp(o);
+    ASSERT(!NCDVal_IsInvalid(o->args))
     
     if (strcmp(name, "")) {
         return 0;
     }
     
-    if (!NCDValue_InitCopy(out_value, &o->args)) {
-        BLog_LogToChannel(BLOG_CHANNEL_NCDModuleProcess, BLOG_ERROR, "NCDValue_InitCopy failed");
-        return 0;
+    *out_value = NCDVal_NewCopy(mem, o->args);
+    if (NCDVal_IsInvalid(*out_value)) {
+        BLog_LogToChannel(BLOG_CHANNEL_NCDModuleProcess, BLOG_ERROR, "NCDVal_NewCopy failed");
     }
-    
     return 1;
 }
 
-static int process_arg_object_func_getvar2 (NCDModuleProcess *o, NCDValue *arg, const char *name, NCDValue *out_value)
+static int process_arg_object_func_getvar2 (NCDModuleProcess *o, void *n_ptr, const char *name, NCDValMem *mem, NCDValRef *out_value)
 {
     DebugObject_Access(&o->d_obj);
     process_assert_interp(o);
+    ASSERT(!NCDVal_IsInvalid(o->args))
     
-    if (!NCDValue_InitCopy(out_value, arg)) {
-        BLog_LogToChannel(BLOG_CHANNEL_NCDModuleProcess, BLOG_ERROR, "NCDValue_InitCopy failed");
+    if (strcmp(name, "")) {
         return 0;
     }
     
+    uintmax_t n = (uintmax_t)n_ptr - 1;
+    
+    *out_value = NCDVal_NewCopy(mem, NCDVal_ListGet(o->args, n));
+    if (NCDVal_IsInvalid(*out_value)) {
+        BLog_LogToChannel(BLOG_CHANNEL_NCDModuleProcess, BLOG_ERROR, "NCDVal_NewCopy failed");
+    }
     return 1;
 }

+ 21 - 28
ncd/NCDModule.h

@@ -36,7 +36,6 @@
 #include <base/BLog.h>
 #include <system/BProcess.h>
 #include <udevmonitor/NCDUdevManager.h>
-#include <ncd/NCDValue.h>
 #include <ncd/NCDObject.h>
 
 #define NCDMODULE_EVENT_UP 1
@@ -125,12 +124,12 @@ typedef void (*NCDModuleInst_func_interp_exit) (void *user, int exit_code);
  * provide its extra command line arguments.
  * 
  * @param user as in {@link NCDModuleInst_Init}
- * @param out_value on success, the interpreter will write the list of extra command
- *                  line arguments here
- * @return 1 on success, 0 on failure
- *   
+ * @param mem value memory to use
+ * @param out_value write value reference here on success
+ * @return 1 if available, 0 if not available. If available, but out of memory, return 1
+ *         and an invalid value.
  */
-typedef int (*NCDModuleInst_func_interp_getargs) (void *user, NCDValue *out_value);
+typedef int (*NCDModuleInst_func_interp_getargs) (void *user, NCDValMem *mem, NCDValRef *out_value);
 
 /**
  * Function called when the module instance wants the interpreter to
@@ -292,7 +291,7 @@ struct NCDModuleInst_iparams {
 typedef struct NCDModuleInst_s {
     const struct NCDModule *m;
     void *method_user;
-    NCDValue *args;
+    NCDValRef args;
     void *user;
     const struct NCDModuleInst_params *params;
     const struct NCDModuleInst_iparams *iparams;
@@ -308,13 +307,12 @@ typedef struct NCDModuleInst_s {
  * instance, implemented by the interpreter.
  */
 typedef struct NCDModuleProcess_s {
-    NCDValue args;
+    NCDValRef args;
     void *user;
     NCDModuleProcess_handler_event handler_event;
     NCDModuleProcess_func_getspecialobj func_getspecialobj;
     BPending event_job;
     int state;
-    int no_args;
     void *interp_user;
     NCDModuleProcess_interp_func_event interp_func_event;
     NCDModuleProcess_interp_func_getobj interp_func_getobj;
@@ -334,13 +332,13 @@ typedef struct NCDModuleProcess_s {
  * @param method_object the base object if the module being initialized is a method, otherwise NULL.
  *                      The caller must ensure that this object is of the type expected by the module
  *                      being initialized.
- * @param args arguments to the module. Must be a NCDVALUE_LIST value. Must be available as long as
- *             the instance is freed.
+ * @param args arguments to the module. Must be a list value. Must be available and unchanged
+ *             as long as the instance exists.
  * @param user argument to callback functions
  * @param params more parameters, see {@link NCDModuleInst_params}
  * @param iparams more parameters, see {@link NCDModuleInst_iparams}
  */
-void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, const NCDObject *method_object, NCDValue *args, void *user, const struct NCDModuleInst_params *params, const struct NCDModuleInst_iparams *iparams);
+void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, const NCDObject *method_object, NCDValRef args, void *user, const struct NCDModuleInst_params *params, const struct NCDModuleInst_iparams *iparams);
 
 /**
  * Frees the instance.
@@ -475,10 +473,12 @@ void NCDModuleInst_Backend_InterpExit (NCDModuleInst *n, int exit_code);
  * Retrieves extra command line arguments passed to the interpreter.
  * 
  * @param n backend instance handle
+ * @param mem value memory to use
  * @param out_value the arguments will be written here on success as a list value
- * @return 1 on success, 0 on failure
+ * @return 1 if available, 0 if not available. If available, but out of memory, returns 1
+ *         and an invalid value.
  */
-int NCDModuleInst_Backend_InterpGetArgs (NCDModuleInst *n, NCDValue *out_value);
+int NCDModuleInst_Backend_InterpGetArgs (NCDModuleInst *n, NCDValMem *mem, NCDValRef *out_value);
 
 /**
  * Returns the retry time of the intepreter.
@@ -496,14 +496,14 @@ btime_t NCDModuleInst_Backend_InterpGetRetryTime (NCDModuleInst *n);
  * @param o the process
  * @param n backend instance whose interpreter will be providing the process
  * @param template_name name of the process template
- * @param args arguments to the process. On success, the arguments become owned
- *             by the interpreter. On failure, they are left untouched.
+ * @param args arguments to the process. Must be an invalid value or a list value.
+ *             The value must be available and unchanged while the process exists.
  * @param user argument to handlers
  * @param handler_event handler which reports events about the process from the
  *                      interpreter
  * @return 1 on success, 0 on failure
  */
-int NCDModuleProcess_Init (NCDModuleProcess *o, NCDModuleInst *n, const char *template_name, NCDValue args, void *user, NCDModuleProcess_handler_event handler_event) WARN_UNUSED;
+int NCDModuleProcess_Init (NCDModuleProcess *o, NCDModuleInst *n, const char *template_name, NCDValRef args, void *user, NCDModuleProcess_handler_event handler_event) WARN_UNUSED;
 
 /**
  * Frees the process.
@@ -529,15 +529,6 @@ void NCDModuleProcess_AssertFree (NCDModuleProcess *o);
  */
 void NCDModuleProcess_SetSpecialFuncs (NCDModuleProcess *o, NCDModuleProcess_func_getspecialobj func_getspecialobj);
 
-/**
- * Makes the process itself not resolve the _args and _argN special objects.
- * After calling this, the only special objects the interpreter can resolve
- * are those provided by the creator of the process via {@link NCDModuleProcess_SetSpecialFuncs}.
- * 
- * @param o the process
- */
-void NCDModuleProcess_SetNoArgs (NCDModuleProcess *o);
-
 /**
  * Continues the process after the process went down.
  * The process must be in waiting state.
@@ -675,10 +666,12 @@ typedef void (*NCDModule_func_die) (void *o);
  * 
  * @param o as in {@link NCDModuleInst_Backend_SetUser}, or NULL by default
  * @param name name of the variable to resolve
+ * @param mem value memory to use
  * @param out on success, the backend should initialize the value here
- * @return 1 on success, 0 on failure
+ * @return 1 if exists, 0 if not exists. If exists, but out of memory, return 1
+ *         and an invalid value.
  */
-typedef int (*NCDModule_func_getvar) (void *o, const char *name, NCDValue *out);
+typedef int (*NCDModule_func_getvar) (void *o, const char *name, NCDValMem *mem, NCDValRef *out);
 
 /**
  * Function called to resolve an object within a backend instance.

+ 9 - 11
ncd/NCDObject.c

@@ -79,24 +79,21 @@ int NCDObject_GetObj (NCDObject *o, const char *name, NCDObject *out_object)
     return res;
 }
 
-int NCDObject_GetVar (NCDObject *o, const char *name, NCDValue *out_value)
+int NCDObject_GetVar (NCDObject *o, const char *name, NCDValMem *mem, NCDValRef *out_value)
 {
     ASSERT(name)
+    ASSERT(mem)
     ASSERT(out_value)
     
     int res;
     if (o->user2) {
-        res = (!o->uv.func_getvar2 ? 0 : o->uv.func_getvar2(o->user, o->user2, name, out_value));
+        res = (!o->uv.func_getvar2 ? 0 : o->uv.func_getvar2(o->user, o->user2, name, mem, out_value));
     } else {
-        res = (!o->uv.func_getvar ? 0 : o->uv.func_getvar(o->user, name, out_value));
+        res = (!o->uv.func_getvar ? 0 : o->uv.func_getvar(o->user, name, mem, out_value));
     }
     
     ASSERT(res == 0 || res == 1)
-#ifndef NDEBUG
-    if (res) {
-        NCDValue_Type(out_value);
-    }
-#endif
+    ASSERT(res == 0 || (NCDVal_Assert(*out_value), 1))
     
     return res;
 }
@@ -155,9 +152,10 @@ int NCDObject_ResolveObjExprCompact (NCDObject *o, const char *names, int num_na
     return 1;
 }
 
-int NCDObject_ResolveVarExpr (NCDObject *o, char **names, NCDValue *out_value)
+int NCDObject_ResolveVarExpr (NCDObject *o, char **names, NCDValMem *mem, NCDValRef *out_value)
 {
     ASSERT(names)
+    ASSERT(mem)
     ASSERT(out_value)
     
     NCDObject object = dig_into_object(*o);
@@ -165,7 +163,7 @@ int NCDObject_ResolveVarExpr (NCDObject *o, char **names, NCDValue *out_value)
     for (size_t i = 0; names[i]; i++) {
         NCDObject obj2;
         if (!NCDObject_GetObj(&object, names[i], &obj2)) {
-            if (!names[i + 1] && NCDObject_GetVar(&object, names[i], out_value)) {
+            if (!names[i + 1] && NCDObject_GetVar(&object, names[i], mem, out_value)) {
                 return 1;
             }
             
@@ -175,5 +173,5 @@ int NCDObject_ResolveVarExpr (NCDObject *o, char **names, NCDValue *out_value)
         object = dig_into_object(obj2);
     }
     
-    return NCDObject_GetVar(&object, "", out_value);
+    return NCDObject_GetVar(&object, "", mem, out_value);
 }

+ 5 - 5
ncd/NCDObject.h

@@ -31,13 +31,13 @@
 #define BADVPN_NCDOBJECT_H
 
 #include <misc/debug.h>
-#include <ncd/NCDValue.h>
+#include <ncd/NCDVal.h>
 
 typedef struct NCDObject_s NCDObject;
 
-typedef int (*NCDObject_func_getvar) (void *user, const char *name, NCDValue *out_value);
+typedef int (*NCDObject_func_getvar) (void *user, const char *name, NCDValMem *mem, NCDValRef *out_value);
 typedef int (*NCDObject_func_getobj) (void *user, const char *name, NCDObject *out_object);
-typedef int (*NCDObject_func_getvar2) (void *user, void *user2, const char *name, NCDValue *out_value);
+typedef int (*NCDObject_func_getvar2) (void *user, void *user2, const char *name, NCDValMem *mem, NCDValRef *out_value);
 typedef int (*NCDObject_func_getobj2) (void *user, void *user2, const char *name, NCDObject *out_object);
 
 struct NCDObject_s {
@@ -58,9 +58,9 @@ NCDObject NCDObject_Build (const char *type, void *user, NCDObject_func_getvar f
 NCDObject NCDObject_Build2 (const char *type, void *user, void *user2, NCDObject_func_getvar2 func_getvar2, NCDObject_func_getobj2 func_getobj2);
 const char * NCDObject_Type (NCDObject *o);
 int NCDObject_GetObj (NCDObject *o, const char *name, NCDObject *out_object) WARN_UNUSED;
-int NCDObject_GetVar (NCDObject *o, const char *name, NCDValue *out_value) WARN_UNUSED;
+int NCDObject_GetVar (NCDObject *o, const char *name, NCDValMem *mem, NCDValRef *out_value) WARN_UNUSED;
 int NCDObject_ResolveObjExpr (NCDObject *o, char **names, NCDObject *out_object) WARN_UNUSED;
 int NCDObject_ResolveObjExprCompact (NCDObject *o, const char *names, int num_names, NCDObject *out_object) WARN_UNUSED;
-int NCDObject_ResolveVarExpr (NCDObject *o, char **names, NCDValue *out_value) WARN_UNUSED;
+int NCDObject_ResolveVarExpr (NCDObject *o, char **names, NCDValMem *mem, NCDValRef *out_value) WARN_UNUSED;
 
 #endif

+ 729 - 0
ncd/NCDVal.c

@@ -0,0 +1,729 @@
+/**
+ * @file NCDVal.c
+ * @author Ambroz Bizjak <[email protected]>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+#include <misc/bsize.h>
+
+#include "NCDVal.h"
+
+static void * NCDValMem__BufAt (NCDValMem *o, NCDVal__idx idx)
+{
+    ASSERT(idx < o->used)
+    
+    return (o->buf ? o->buf : o->fastbuf) + idx;
+}
+
+static NCDVal__idx NCDValMem__Alloc (NCDValMem *o, bsize_t alloc_size, NCDVal__idx align)
+{
+    if (alloc_size.is_overflow) {
+        return -1;
+    }
+    
+    NCDVal__idx mod = o->used % align;
+    NCDVal__idx align_extra = mod ? (align - mod) : 0;
+    
+    if (alloc_size.value > NCDVAL_MAXIDX - align_extra) {
+        return -1;
+    }
+    NCDVal__idx aligned_alloc_size = align_extra + alloc_size.value;
+    
+    if (aligned_alloc_size > o->size - o->used) {
+        NCDVal__idx newsize = (o->buf ? o->size : NCDVAL_FIRST_SIZE);
+        while (aligned_alloc_size > newsize - o->used) {
+            if (newsize > NCDVAL_MAXIDX / 2) {
+                return -1;
+            }
+            newsize *= 2;
+        }
+        
+        char *newbuf;
+        
+        if (!o->buf) {
+            newbuf = malloc(newsize);
+            if (!newbuf) {
+                return -1;
+            }
+            memcpy(newbuf, o->fastbuf, o->used);
+        } else {
+            newbuf = realloc(o->buf, newsize);
+            if (!newbuf) {
+                return -1;
+            }
+        }
+        
+        o->buf = newbuf;
+        o->size = newsize;
+    }
+    
+    NCDVal__idx idx = o->used + align_extra;
+    o->used += aligned_alloc_size;
+    
+    return idx;
+}
+
+static NCDValRef NCDVal__Ref (NCDValMem *mem, NCDVal__idx idx)
+{
+    ASSERT(idx >= 0 || idx == -1)
+    ASSERT(idx == -1 || mem)
+    
+    NCDValRef ref = {mem, idx};
+    return ref;
+}
+
+static void NCDVal__AssertMem (NCDValMem *mem)
+{
+    ASSERT(mem)
+    ASSERT(mem->size >= 0)
+    ASSERT(mem->used >= 0)
+    ASSERT(mem->used <= mem->size)
+    ASSERT(mem->buf || mem->size == NCDVAL_FASTBUF_SIZE)
+    ASSERT(!mem->buf || mem->size >= NCDVAL_FIRST_SIZE)
+}
+
+static void NCDVal__AssertValOnly (NCDValMem *mem, NCDVal__idx idx)
+{
+    ASSERT(idx >= 0)
+    ASSERT(idx + sizeof(uint8_t) <= mem->used)
+    
+#ifndef NDEBUG
+    uint8_t *type_ptr = NCDValMem__BufAt(mem, idx);
+    
+    switch (*type_ptr) {
+        case NCDVAL_STRING: {
+            ASSERT(idx + sizeof(struct NCDVal__string) <= mem->used)
+            struct NCDVal__string *str_e = NCDValMem__BufAt(mem, idx);
+            ASSERT(str_e->length >= 0)
+            ASSERT(idx + sizeof(struct NCDVal__string) + str_e->length + 1 <= mem->used)
+        } break;
+        case NCDVAL_LIST: {
+            ASSERT(idx + sizeof(struct NCDVal__list) <= mem->used)
+            struct NCDVal__list *list_e = NCDValMem__BufAt(mem, idx);
+            ASSERT(list_e->maxcount >= 0)
+            ASSERT(list_e->count >= 0)
+            ASSERT(list_e->count <= list_e->maxcount)
+            ASSERT(idx + sizeof(struct NCDVal__list) + list_e->maxcount * sizeof(NCDVal__idx) <= mem->used)
+        } break;
+        case NCDVAL_MAP: {
+            ASSERT(idx + sizeof(struct NCDVal__map) <= mem->used)
+            struct NCDVal__map *map_e = NCDValMem__BufAt(mem, idx);
+            ASSERT(map_e->maxcount >= 0)
+            ASSERT(map_e->count >= 0)
+            ASSERT(map_e->count <= map_e->maxcount)
+            ASSERT(idx + sizeof(struct NCDVal__map) + map_e->maxcount * sizeof(struct NCDVal__mapelem) <= mem->used)
+        } break;
+        default: ASSERT(0);
+    }
+#endif
+}
+
+static void NCDVal__AssertVal (NCDValRef val)
+{
+    NCDVal__AssertMem(val.mem);
+    NCDVal__AssertValOnly(val.mem, val.idx);
+}
+
+static NCDValMapElem NCDVal__MapElem (NCDVal__idx elemidx)
+{
+    ASSERT(elemidx >= 0 || elemidx == -1)
+    
+    NCDValMapElem me = {elemidx};
+    return me;
+}
+
+static void NCDVal__MapAssertElem (NCDValRef map, NCDValMapElem me)
+{
+    ASSERT(NCDVal_IsMap(map))
+    ASSERT(me.elemidx >= map.idx + offsetof(struct NCDVal__map, elems))
+    ASSERT(me.elemidx < map.idx + offsetof(struct NCDVal__map, elems) + NCDVal_MapCount(map) * sizeof(struct NCDVal__mapelem))
+    
+    struct NCDVal__mapelem *me_e = NCDValMem__BufAt(map.mem, me.elemidx);
+    NCDVal__AssertValOnly(map.mem, me_e->key_idx);
+    NCDVal__AssertValOnly(map.mem, me_e->val_idx);
+}
+
+#include "NCDVal_maptree.h"
+#include <structure/CAvl_impl.h>
+
+void NCDValMem_Init (NCDValMem *o)
+{
+    o->buf = NULL;
+    o->size = NCDVAL_FASTBUF_SIZE;
+    o->used = 0;
+}
+
+void NCDValMem_Free (NCDValMem *o)
+{
+    free(o->buf);
+}
+
+void NCDVal_Assert (NCDValRef val)
+{
+    ASSERT(val.idx == -1 || (NCDVal__AssertVal(val), 1))
+}
+
+int NCDVal_IsInvalid (NCDValRef val)
+{
+    NCDVal_Assert(val);
+    
+    return val.idx < 0;
+}
+
+int NCDVal_Type (NCDValRef val)
+{
+    NCDVal__AssertVal(val);
+    
+    uint8_t *type_ptr = NCDValMem__BufAt(val.mem, val.idx);
+    
+    return *type_ptr;
+}
+
+NCDValRef NCDVal_NewInvalid (void)
+{
+    NCDValRef ref = {NULL, -1};
+    return ref;
+}
+
+NCDValRef NCDVal_NewCopy (NCDValMem *mem, NCDValRef val)
+{
+    NCDVal__AssertMem(mem);
+    NCDVal__AssertVal(val);
+    
+    switch (NCDVal_Type(val)) {
+        case NCDVAL_STRING: {
+            return NCDVal_NewStringBin(mem, (const uint8_t *)NCDVal_StringValue(val), NCDVal_StringLength(val));
+        } break;
+        
+        case NCDVAL_LIST: {
+            size_t count = NCDVal_ListCount(val);
+            
+            NCDValRef copy = NCDVal_NewList(mem, count);
+            if (NCDVal_IsInvalid(copy)) {
+                goto fail;
+            }
+            
+            for (size_t i = 0; i < count; i++) {
+                NCDValRef elem_copy = NCDVal_NewCopy(mem, NCDVal_ListGet(val, i));
+                if (NCDVal_IsInvalid(elem_copy)) {
+                    goto fail;
+                }
+                
+                NCDVal_ListAppend(copy, elem_copy);
+            }
+            
+            return copy;
+        } break;
+        
+        case NCDVAL_MAP: {
+            size_t count = NCDVal_MapCount(val);
+            
+            NCDValRef copy = NCDVal_NewMap(mem, count);
+            if (NCDVal_IsInvalid(copy)) {
+                goto fail;
+            }
+            
+            for (NCDValMapElem e = NCDVal_MapFirst(val); !NCDVal_MapElemInvalid(e); e = NCDVal_MapNext(val, e)) {
+                NCDValRef key_copy = NCDVal_NewCopy(mem, NCDVal_MapElemKey(val, e));
+                NCDValRef val_copy = NCDVal_NewCopy(mem, NCDVal_MapElemVal(val, e));
+                if (NCDVal_IsInvalid(key_copy) || NCDVal_IsInvalid(val_copy)) {
+                    goto fail;
+                }
+                
+                int res = NCDVal_MapInsert(copy, key_copy, val_copy);
+                ASSERT(res)
+            }
+            
+            return copy;
+        } break;
+        
+        default: ASSERT(0);
+    }
+    
+    ASSERT(0);
+    
+fail:
+    return NCDVal_NewInvalid();
+}
+
+int NCDVal_Compare (NCDValRef val1, NCDValRef val2)
+{
+    NCDVal__AssertVal(val1);
+    NCDVal__AssertVal(val2);
+    
+    int type1 = NCDVal_Type(val1);
+    int type2 = NCDVal_Type(val2);
+    
+    if (type1 != type2) {
+        return (type1 > type2) - (type1 < type2);
+    }
+    
+    switch (type1) {
+        case NCDVAL_STRING: {
+            size_t len1 = NCDVal_StringLength(val1);
+            size_t len2 = NCDVal_StringLength(val2);
+            size_t min_len = len1 < len2 ? len1 : len2;
+            
+            int cmp = memcmp(NCDVal_StringValue(val1), NCDVal_StringValue(val2), min_len);
+            if (cmp) {
+                return (cmp > 0) - (cmp < 0);
+            }
+            
+            return (len1 > len2) - (len1 < len2);
+        } break;
+        
+        case NCDVAL_LIST: {
+            size_t count1 = NCDVal_ListCount(val1);
+            size_t count2 = NCDVal_ListCount(val2);
+            size_t min_count = count1 < count2 ? count1 : count2;
+            
+            for (size_t i = 0; i < min_count; i++) {
+                NCDValRef ev1 = NCDVal_ListGet(val1, i);
+                NCDValRef ev2 = NCDVal_ListGet(val2, i);
+                
+                int cmp = NCDVal_Compare(ev1, ev2);
+                if (cmp) {
+                    return cmp;
+                }
+            }
+            
+            return (count1 > count2) - (count1 < count2);
+        } break;
+        
+        case NCDVAL_MAP: {
+            NCDValMapElem e1 = NCDVal_MapFirst(val1);
+            NCDValMapElem e2 = NCDVal_MapFirst(val2);
+            
+            while (1) {
+                int inv1 = NCDVal_MapElemInvalid(e1);
+                int inv2 = NCDVal_MapElemInvalid(e2);
+                if (inv1 + inv2 < 2) {
+                    return inv2 - inv1;
+                }
+                
+                NCDValRef key1 = NCDVal_MapElemKey(val1, e1);
+                NCDValRef key2 = NCDVal_MapElemKey(val2, e2);
+                
+                int cmp = NCDVal_Compare(key1, key2);
+                if (cmp) {
+                    return cmp;
+                }
+                
+                NCDValRef value1 = NCDVal_MapElemVal(val1, e1);
+                NCDValRef value2 = NCDVal_MapElemVal(val2, e2);
+                
+                cmp = NCDVal_Compare(value1, value2);
+                if (cmp) {
+                    return cmp;
+                }
+                
+                e1 = NCDVal_MapNext(val1, e1);
+                e2 = NCDVal_MapNext(val2, e2);
+            }
+        } break;
+        
+        default:
+            ASSERT(0);
+            return 0;
+    }
+}
+
+NCDValSafeRef NCDVal_ToSafe (NCDValRef val)
+{
+    NCDVal_Assert(val);
+    
+    NCDValSafeRef sval = {val.idx};
+    return sval;
+}
+
+NCDValRef NCDVal_FromSafe (NCDValMem *mem, NCDValSafeRef sval)
+{
+    NCDVal__AssertMem(mem);
+    ASSERT(sval.idx == -1 || (NCDVal__AssertValOnly(mem, sval.idx), 1))
+    
+    NCDValRef val = {mem, sval.idx};
+    return val;
+}
+
+NCDValRef NCDVal_Moved (NCDValMem *mem, NCDValRef val)
+{
+    NCDVal__AssertMem(mem);
+    ASSERT(val.idx == -1 || (NCDVal__AssertValOnly(mem, val.idx), 1))
+    
+    NCDValRef val2 = {mem, val.idx};
+    return val2;
+}
+
+int NCDVal_IsString (NCDValRef val)
+{
+    NCDVal__AssertVal(val);
+    
+    return NCDVal_Type(val) == NCDVAL_STRING;
+}
+
+int NCDVal_IsStringNoNulls (NCDValRef val)
+{
+    NCDVal__AssertVal(val);
+    
+    return NCDVal_Type(val) == NCDVAL_STRING && strlen(NCDVal_StringValue(val)) == NCDVal_StringLength(val);
+}
+
+NCDValRef NCDVal_NewString (NCDValMem *mem, const char *data)
+{
+    NCDVal__AssertMem(mem);
+    ASSERT(data)
+    
+    return NCDVal_NewStringBin(mem, (const uint8_t *)data, strlen(data));
+}
+
+NCDValRef NCDVal_NewStringBin (NCDValMem *mem, const uint8_t *data, size_t len)
+{
+    NCDVal__AssertMem(mem);
+    ASSERT(len == 0 || data)
+    
+    if (len == SIZE_MAX) {
+        goto fail;
+    }
+    
+    bsize_t size = bsize_add(bsize_fromsize(sizeof(struct NCDVal__string)), bsize_fromsize(len + 1));
+    NCDVal__idx idx = NCDValMem__Alloc(mem, size, __alignof(struct NCDVal__string));
+    if (idx < 0) {
+        goto fail;
+    }
+    
+    struct NCDVal__string *str_e = NCDValMem__BufAt(mem, idx);
+    str_e->type = NCDVAL_STRING;
+    str_e->length = len;
+    if (len > 0) {
+        memcpy(str_e->data, data, len);
+    }
+    str_e->data[len] = '\0';
+    
+    return NCDVal__Ref(mem, idx);
+    
+fail:
+    return NCDVal_NewInvalid();
+}
+
+const char * NCDVal_StringValue (NCDValRef string)
+{
+    ASSERT(NCDVal_IsString(string))
+    
+    struct NCDVal__string *str_e = NCDValMem__BufAt(string.mem, string.idx);
+    
+    return str_e->data;
+}
+
+size_t NCDVal_StringLength (NCDValRef string)
+{
+    ASSERT(NCDVal_IsString(string))
+    
+    struct NCDVal__string *str_e = NCDValMem__BufAt(string.mem, string.idx);
+    
+    return str_e->length;
+}
+
+int NCDVal_StringHasNulls (NCDValRef string)
+{
+    ASSERT(NCDVal_IsString(string))
+    
+    return strlen(NCDVal_StringValue(string)) != NCDVal_StringLength(string);
+}
+
+int NCDVal_StringEquals (NCDValRef string, const char *data)
+{
+    ASSERT(NCDVal_IsString(string))
+    ASSERT(data)
+    
+    return !NCDVal_StringHasNulls(string) && !strcmp(NCDVal_StringValue(string), data);
+}
+
+int NCDVal_IsList (NCDValRef val)
+{
+    NCDVal__AssertVal(val);
+    
+    return NCDVal_Type(val) == NCDVAL_LIST;
+}
+
+NCDValRef NCDVal_NewList (NCDValMem *mem, size_t maxcount)
+{
+    NCDVal__AssertMem(mem);
+    
+    bsize_t size = bsize_add(bsize_fromsize(sizeof(struct NCDVal__list)), bsize_mul(bsize_fromsize(maxcount), bsize_fromsize(sizeof(NCDVal__idx))));
+    NCDVal__idx idx = NCDValMem__Alloc(mem, size, __alignof(struct NCDVal__list));
+    if (idx < 0) {
+        goto fail;
+    }
+    
+    struct NCDVal__list *list_e = NCDValMem__BufAt(mem, idx);
+    list_e->type = NCDVAL_LIST;
+    list_e->maxcount = maxcount;
+    list_e->count = 0;
+    
+    return NCDVal__Ref(mem, idx);
+    
+fail:
+    return NCDVal_NewInvalid();
+}
+
+void NCDVal_ListAppend (NCDValRef list, NCDValRef elem)
+{
+    ASSERT(NCDVal_IsList(list))
+    ASSERT(NCDVal_ListCount(list) < NCDVal_ListMaxCount(list))
+    ASSERT(elem.mem == list.mem)
+    NCDVal__AssertValOnly(list.mem, elem.idx);
+    
+    struct NCDVal__list *list_e = NCDValMem__BufAt(list.mem, list.idx);
+    
+    list_e->elem_indices[list_e->count++] = elem.idx;
+}
+
+size_t NCDVal_ListCount (NCDValRef list)
+{
+    ASSERT(NCDVal_IsList(list))
+    
+    struct NCDVal__list *list_e = NCDValMem__BufAt(list.mem, list.idx);
+    
+    return list_e->count;
+}
+
+size_t NCDVal_ListMaxCount (NCDValRef list)
+{
+    ASSERT(NCDVal_IsList(list))
+    
+    struct NCDVal__list *list_e = NCDValMem__BufAt(list.mem, list.idx);
+    
+    return list_e->maxcount;
+}
+
+NCDValRef NCDVal_ListGet (NCDValRef list, size_t pos)
+{
+    ASSERT(NCDVal_IsList(list))
+    ASSERT(pos < NCDVal_ListCount(list))
+    
+    struct NCDVal__list *list_e = NCDValMem__BufAt(list.mem, list.idx);
+    
+    ASSERT(pos < list_e->count)
+    NCDVal__AssertValOnly(list.mem, list_e->elem_indices[pos]);
+    
+    return NCDVal__Ref(list.mem, list_e->elem_indices[pos]);
+}
+
+int NCDVal_ListRead (NCDValRef list, int num, ...)
+{
+    ASSERT(NCDVal_IsList(list))
+    ASSERT(num >= 0)
+    
+    size_t count = NCDVal_ListCount(list);
+    
+    if (num != count) {
+        return 0;
+    }
+    
+    va_list ap;
+    va_start(ap, num);
+    
+    for (size_t i = 0; i < num; i++) {
+        NCDValRef elem = NCDVal_ListGet(list, i);
+        
+        NCDValRef *dest = va_arg(ap, NCDValRef *);
+        *dest = elem;
+    }
+    
+    va_end(ap);
+    
+    return 1;
+}
+
+int NCDVal_ListReadHead (NCDValRef list, int num, ...)
+{
+    ASSERT(NCDVal_IsList(list))
+    ASSERT(num >= 0)
+    
+    size_t count = NCDVal_ListCount(list);
+    
+    if (num > count) {
+        return 0;
+    }
+    
+    va_list ap;
+    va_start(ap, num);
+    
+    for (size_t i = 0; i < num; i++) {
+        NCDValRef elem = NCDVal_ListGet(list, i);
+        
+        NCDValRef *dest = va_arg(ap, NCDValRef *);
+        *dest = elem;
+    }
+    
+    va_end(ap);
+    
+    return 1;
+}
+
+int NCDVal_IsMap (NCDValRef val)
+{
+    NCDVal__AssertVal(val);
+    
+    return NCDVal_Type(val) == NCDVAL_MAP;
+}
+
+NCDValRef NCDVal_NewMap (NCDValMem *mem, size_t maxcount)
+{
+    NCDVal__AssertMem(mem);
+    
+    bsize_t size = bsize_add(bsize_fromsize(sizeof(struct NCDVal__map)), bsize_mul(bsize_fromsize(maxcount), bsize_fromsize(sizeof(struct NCDVal__mapelem))));
+    NCDVal__idx idx = NCDValMem__Alloc(mem, size, __alignof(struct NCDVal__map));
+    if (idx < 0) {
+        goto fail;
+    }
+    
+    struct NCDVal__map *map_e = NCDValMem__BufAt(mem, idx);
+    map_e->type = NCDVAL_MAP;
+    map_e->maxcount = maxcount;
+    map_e->count = 0;
+    NCDVal__MapTree_Init(&map_e->tree);
+    
+    return NCDVal__Ref(mem, idx);
+    
+fail:
+    return NCDVal_NewInvalid();
+}
+
+int NCDVal_MapInsert (NCDValRef map, NCDValRef key, NCDValRef val)
+{
+    ASSERT(NCDVal_IsMap(map))
+    ASSERT(NCDVal_MapCount(map) < NCDVal_MapMaxCount(map))
+    ASSERT(key.mem == map.mem)
+    ASSERT(val.mem == map.mem)
+    NCDVal__AssertValOnly(map.mem, key.idx);
+    NCDVal__AssertValOnly(map.mem, val.idx);
+    
+    struct NCDVal__map *map_e = NCDValMem__BufAt(map.mem, map.idx);
+    
+    NCDVal__idx elemidx = map.idx + offsetof(struct NCDVal__map, elems) + map_e->count * sizeof(struct NCDVal__mapelem);
+    
+    struct NCDVal__mapelem *me_e = NCDValMem__BufAt(map.mem, elemidx);
+    ASSERT(me_e == &map_e->elems[map_e->count])
+    me_e->key_idx = key.idx;
+    me_e->val_idx = val.idx;
+    
+    int res = NCDVal__MapTree_Insert(&map_e->tree, map.mem, NCDVal__MapTree_Deref(map.mem, elemidx), NULL);
+    if (!res) {
+        return 0;
+    }
+    
+    map_e->count++;
+    
+    return 1;
+}
+
+size_t NCDVal_MapCount (NCDValRef map)
+{
+    ASSERT(NCDVal_IsMap(map))
+    
+    struct NCDVal__map *map_e = NCDValMem__BufAt(map.mem, map.idx);
+    
+    return map_e->count;
+}
+
+size_t NCDVal_MapMaxCount (NCDValRef map)
+{
+    ASSERT(NCDVal_IsMap(map))
+    
+    struct NCDVal__map *map_e = NCDValMem__BufAt(map.mem, map.idx);
+    
+    return map_e->maxcount;
+}
+
+int NCDVal_MapElemInvalid (NCDValMapElem me)
+{
+    ASSERT(me.elemidx >= 0 || me.elemidx == -1)
+    
+    return me.elemidx < 0;
+}
+
+NCDValMapElem NCDVal_MapFirst (NCDValRef map)
+{
+    ASSERT(NCDVal_IsMap(map))
+    
+    struct NCDVal__map *map_e = NCDValMem__BufAt(map.mem, map.idx);
+    
+    NCDVal__MapTreeNode ref = NCDVal__MapTree_GetFirst(&map_e->tree, map.mem);
+    
+    return NCDVal__MapElem(ref.link);
+}
+
+NCDValMapElem NCDVal_MapNext (NCDValRef map, NCDValMapElem me)
+{
+    NCDVal__MapAssertElem(map, me);
+    
+    struct NCDVal__map *map_e = NCDValMem__BufAt(map.mem, map.idx);
+    
+    NCDVal__MapTreeNode ref = NCDVal__MapTree_GetNext(&map_e->tree, map.mem, NCDVal__MapTree_Deref(map.mem, me.elemidx));
+    
+    return NCDVal__MapElem(ref.link);
+}
+
+NCDValRef NCDVal_MapElemKey (NCDValRef map, NCDValMapElem me)
+{
+    NCDVal__MapAssertElem(map, me);
+    
+    struct NCDVal__mapelem *me_e = NCDValMem__BufAt(map.mem, me.elemidx);
+    NCDVal__AssertValOnly(map.mem, me_e->key_idx);
+    NCDVal__AssertValOnly(map.mem, me_e->val_idx);
+    
+    return NCDVal__Ref(map.mem, me_e->key_idx);
+}
+
+NCDValRef NCDVal_MapElemVal (NCDValRef map, NCDValMapElem me)
+{
+    NCDVal__MapAssertElem(map, me);
+    
+    struct NCDVal__mapelem *me_e = NCDValMem__BufAt(map.mem, me.elemidx);
+    NCDVal__AssertValOnly(map.mem, me_e->key_idx);
+    NCDVal__AssertValOnly(map.mem, me_e->val_idx);
+    
+    return NCDVal__Ref(map.mem, me_e->val_idx);
+}
+
+NCDValMapElem NCDVal_MapFindKey (NCDValRef map, NCDValRef key)
+{
+    ASSERT(NCDVal_IsMap(map))
+    NCDVal__AssertVal(key);
+    
+    struct NCDVal__map *map_e = NCDValMem__BufAt(map.mem, map.idx);
+    
+    NCDVal__MapTreeNode ref = NCDVal__MapTree_LookupExact(&map_e->tree, map.mem, key);
+    
+    return NCDVal__MapElem(ref.link);
+}

+ 151 - 0
ncd/NCDVal.h

@@ -0,0 +1,151 @@
+/**
+ * @file NCDVal.h
+ * @author Ambroz Bizjak <[email protected]>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BADVPN_NCDVAL_H
+#define BADVPN_NCDVAL_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <misc/debug.h>
+#include <structure/CAvl.h>
+
+#define NCDVAL_FASTBUF_SIZE 64
+#define NCDVAL_FIRST_SIZE 256
+
+#define NCDVAL_MAXIDX INT_MAX
+
+typedef int NCDVal__idx;
+
+typedef struct {
+    char *buf;
+    NCDVal__idx size;
+    NCDVal__idx used;
+    char fastbuf[NCDVAL_FASTBUF_SIZE];
+} NCDValMem;
+
+typedef struct {
+    NCDValMem *mem;
+    NCDVal__idx idx;
+} NCDValRef;
+
+typedef struct {
+    NCDVal__idx idx;
+} NCDValSafeRef;
+
+struct NCDVal__string {
+    uint8_t type;
+    NCDVal__idx length;
+    char data[];
+};
+
+struct NCDVal__list {
+    uint8_t type;
+    NCDVal__idx maxcount;
+    NCDVal__idx count;
+    NCDVal__idx elem_indices[];
+};
+
+struct NCDVal__mapelem {
+    NCDVal__idx key_idx;
+    NCDVal__idx val_idx;
+    NCDVal__idx tree_link[2];
+    NCDVal__idx tree_parent;
+    int8_t tree_balance;
+};
+
+typedef struct NCDVal__mapelem NCDVal__maptree_entry;
+typedef NCDValMem *NCDVal__maptree_arg;
+
+#include "NCDVal_maptree.h"
+#include <structure/CAvl_decl.h>
+
+struct NCDVal__map {
+    uint8_t type;
+    NCDVal__idx maxcount;
+    NCDVal__idx count;
+    NCDVal__MapTree tree;
+    struct NCDVal__mapelem elems[];
+};
+
+typedef struct {
+    NCDVal__idx elemidx;
+} NCDValMapElem;
+
+//
+
+#define NCDVAL_STRING 1
+#define NCDVAL_LIST 2
+#define NCDVAL_MAP 3
+
+void NCDValMem_Init (NCDValMem *o);
+void NCDValMem_Free (NCDValMem *o);
+
+void NCDVal_Assert (NCDValRef val);
+int NCDVal_IsInvalid (NCDValRef val);
+int NCDVal_Type (NCDValRef val);
+NCDValRef NCDVal_NewInvalid (void);
+NCDValRef NCDVal_NewCopy (NCDValMem *mem, NCDValRef val);
+int NCDVal_Compare (NCDValRef val1, NCDValRef val2);
+
+NCDValSafeRef NCDVal_ToSafe (NCDValRef val);
+NCDValRef NCDVal_FromSafe (NCDValMem *mem, NCDValSafeRef sval);
+NCDValRef NCDVal_Moved (NCDValMem *mem, NCDValRef val);
+
+int NCDVal_IsString (NCDValRef val);
+int NCDVal_IsStringNoNulls (NCDValRef val);
+NCDValRef NCDVal_NewString (NCDValMem *mem, const char *data);
+NCDValRef NCDVal_NewStringBin (NCDValMem *mem, const uint8_t *data, size_t len);
+const char * NCDVal_StringValue (NCDValRef string);
+size_t NCDVal_StringLength (NCDValRef string);
+int NCDVal_StringHasNulls (NCDValRef string);
+int NCDVal_StringEquals (NCDValRef string, const char *data);
+
+int NCDVal_IsList (NCDValRef val);
+NCDValRef NCDVal_NewList (NCDValMem *mem, size_t maxcount);
+void NCDVal_ListAppend (NCDValRef list, NCDValRef elem);
+size_t NCDVal_ListCount (NCDValRef list);
+size_t NCDVal_ListMaxCount (NCDValRef list);
+NCDValRef NCDVal_ListGet (NCDValRef list, size_t pos);
+int NCDVal_ListRead (NCDValRef list, int num, ...);
+int NCDVal_ListReadHead (NCDValRef list, int num, ...);
+
+int NCDVal_IsMap (NCDValRef val);
+NCDValRef NCDVal_NewMap (NCDValMem *mem, size_t maxcount);
+int NCDVal_MapInsert (NCDValRef map, NCDValRef key, NCDValRef val);
+size_t NCDVal_MapCount (NCDValRef map);
+size_t NCDVal_MapMaxCount (NCDValRef map);
+int NCDVal_MapElemInvalid (NCDValMapElem me);
+NCDValMapElem NCDVal_MapFirst (NCDValRef map);
+NCDValMapElem NCDVal_MapNext (NCDValRef map, NCDValMapElem me);
+NCDValRef NCDVal_MapElemKey (NCDValRef map, NCDValMapElem me);
+NCDValRef NCDVal_MapElemVal (NCDValRef map, NCDValMapElem me);
+NCDValMapElem NCDVal_MapFindKey (NCDValRef map, NCDValRef key);
+
+#endif

+ 161 - 0
ncd/NCDValCompat.c

@@ -0,0 +1,161 @@
+/**
+ * @file NCDValCompat.c
+ * @author Ambroz Bizjak <[email protected]>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "NCDValCompat.h"
+
+int NCDValCompat_ValueToVal (NCDValue *value, NCDValMem *mem, NCDValRef *out)
+{
+    ASSERT((NCDValue_Type(value), 1))
+    ASSERT(mem)
+    ASSERT(out)
+    
+    switch (NCDValue_Type(value)) {
+        case NCDVALUE_STRING: {
+            *out = NCDVal_NewStringBin(mem, (const uint8_t *)NCDValue_StringValue(value), NCDValue_StringLength(value));
+            if (NCDVal_IsInvalid(*out)) {
+                goto fail;
+            }
+        } break;
+        
+        case NCDVALUE_LIST: {
+            *out = NCDVal_NewList(mem, NCDValue_ListCount(value));
+            if (NCDVal_IsInvalid(*out)) {
+                goto fail;
+            }
+            
+            for (NCDValue *e = NCDValue_ListFirst(value); e; e = NCDValue_ListNext(value, e)) {
+                NCDValRef vval;
+                if (!NCDValCompat_ValueToVal(e, mem, &vval)) {
+                    goto fail;
+                }
+                
+                NCDVal_ListAppend(*out, vval);
+            }
+        } break;
+        
+        case NCDVALUE_MAP: {
+            *out = NCDVal_NewMap(mem, NCDValue_MapCount(value));
+            if (NCDVal_IsInvalid(*out)) {
+                goto fail;
+            }
+            
+            for (NCDValue *ekey = NCDValue_MapFirstKey(value); ekey; ekey = NCDValue_MapNextKey(value, ekey)) {
+                NCDValue *eval = NCDValue_MapKeyValue(value, ekey);
+                
+                NCDValRef vkey;
+                NCDValRef vval;
+                if (!NCDValCompat_ValueToVal(ekey, mem, &vkey) || !NCDValCompat_ValueToVal(eval, mem, &vval)) {
+                    goto fail;
+                }
+                
+                int res = NCDVal_MapInsert(*out, vkey, vval);
+                ASSERT(res)
+            }
+        } break;
+        
+        default:
+            goto fail;
+    }
+    
+    return 1;
+    
+fail:
+    return 0;
+}
+
+int NCDValCompat_ValToValue (NCDValRef value, NCDValue *out)
+{
+    ASSERT(!NCDVal_IsInvalid(value))
+    ASSERT(out)
+    
+    switch (NCDVal_Type(value)) {
+        case NCDVAL_STRING: {
+            if (!NCDValue_InitStringBin(out, (const uint8_t *)NCDVal_StringValue(value), NCDVal_StringLength(value))) {
+                goto fail0;
+            }
+        } break;
+        
+        case NCDVAL_LIST: {
+            NCDValue_InitList(out);
+            
+            size_t count = NCDVal_ListCount(value);
+            
+            for (size_t j = 0; j < count; j++) {
+                NCDValRef velem = NCDVal_ListGet(value, j);
+                
+                NCDValue elem;
+                if (!NCDValCompat_ValToValue(velem, &elem)) {
+                    goto fail1;
+                }
+                
+                if (!NCDValue_ListAppend(out, elem)) {
+                    NCDValue_Free(&elem);
+                    goto fail1;
+                }
+            }
+        } break;
+        
+        case NCDVAL_MAP: {
+            NCDValue_InitMap(out);
+            
+            for (NCDValMapElem e = NCDVal_MapFirst(value); !NCDVal_MapElemInvalid(e); e = NCDVal_MapNext(value, e)) {
+                NCDValRef vkey = NCDVal_MapElemKey(value, e);
+                NCDValRef vval = NCDVal_MapElemVal(value, e);
+                
+                NCDValue key;
+                if (!NCDValCompat_ValToValue(vkey, &key)) {
+                    goto fail1;
+                }
+                
+                NCDValue val;
+                if (!NCDValCompat_ValToValue(vval, &val)) {
+                    NCDValue_Free(&key);
+                    goto fail1;
+                }
+                
+                if (!NCDValue_MapInsert(out, key, val)) {
+                    NCDValue_Free(&key);
+                    NCDValue_Free(&val);
+                    goto fail1;
+                }
+            }
+        } break;
+        
+        default:
+            ASSERT(0);
+            return 0;
+    }
+    
+    return 1;
+    
+fail1:
+    NCDValue_Free(out);
+fail0:
+    return 0;
+}

+ 56 - 0
ncd/NCDValCompat.h

@@ -0,0 +1,56 @@
+/**
+ * @file NCDValCompat.h
+ * @author Ambroz Bizjak <[email protected]>
+ * 
+ * @section LICENSE
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BADVPN_NCDVALCOMPAT_H
+#define BADVPN_NCDVALCOMPAT_H
+
+#include <misc/debug.h>
+#include <ncd/NCDValue.h>
+#include <ncd/NCDVal.h>
+
+/**
+ * Converts an old NCDValue-form value into the new NCDVal-form.
+ * 
+ * @param value input value
+ * @param mem value memory to use
+ * @param out on success, a non-invalid converted value will be returned here
+ * @return 1 on success, 0 on failure
+ */
+int NCDValCompat_ValueToVal (NCDValue *value, NCDValMem *mem, NCDValRef *out) WARN_UNUSED;
+
+/**
+ * Converts a new NCDVal-form value into the old NCDValue-form.
+ * 
+ * @param value non-invalid input value
+ * @param out on success, the converted value will be returned here
+ * @return 1 on success, 0 on failure
+ */
+int NCDValCompat_ValToValue (NCDValRef value, NCDValue *out) WARN_UNUSED;
+
+#endif

+ 13 - 0
ncd/NCDVal_maptree.h

@@ -0,0 +1,13 @@
+#define CAVL_PARAM_USE_COUNTS 0
+#define CAVL_PARAM_NAME NCDVal__MapTree
+#define CAVL_PARAM_ENTRY NCDVal__maptree_entry
+#define CAVL_PARAM_LINK NCDVal__idx
+#define CAVL_PARAM_KEY NCDValRef
+#define CAVL_PARAM_ARG NCDVal__maptree_arg
+#define CAVL_PARAM_NULL ((NCDVal__idx)-1)
+#define CAVL_PARAM_DEREF(arg, link) ((struct NCDVal__mapelem *)NCDValMem__BufAt((arg), (link)))
+#define CAVL_PARAM_COMPARE_NODES(arg, node1, node2) NCDVal_Compare(NCDVal__Ref((arg), (node1).ptr->key_idx), NCDVal__Ref((arg), (node2).ptr->key_idx))
+#define CAVL_PARAM_COMPARE_KEY_NODE(arg, key1, node2) NCDVal_Compare((key1), NCDVal__Ref((arg), (node2).ptr->key_idx))
+#define CAVL_PARAM_NODE_LINK tree_link
+#define CAVL_PARAM_NODE_BALANCE tree_balance
+#define CAVL_PARAM_NODE_PARENT tree_parent

+ 153 - 0
ncd/NCDValueGenerator.c

@@ -168,6 +168,129 @@ fail:
     return 0;
 }
 
+static int generate_val (NCDValRef value, ExpString *out_str)
+{
+    ASSERT(!NCDVal_IsInvalid(value))
+    
+    switch (NCDVal_Type(value)) {
+        case NCDVAL_STRING: {
+            const char *str = NCDVal_StringValue(value);
+            size_t len = NCDVal_StringLength(value);
+            
+            if (!ExpString_AppendChar(out_str, '"')) {
+                BLog(BLOG_ERROR, "ExpString_AppendChar failed");
+                goto fail;
+            }
+            
+            for (size_t i = 0; i < len; i++) {
+                if (str[i] == '\0') {
+                    char buf[5];
+                    snprintf(buf, sizeof(buf), "\\x%02"PRIx8, (uint8_t)str[i]);
+                    
+                    if (!ExpString_Append(out_str, buf)) {
+                        BLog(BLOG_ERROR, "ExpString_Append failed");
+                        goto fail;
+                    }
+                    
+                    continue;
+                }
+                
+                if (str[i] == '"' || str[i] == '\\') {
+                    if (!ExpString_AppendChar(out_str, '\\')) {
+                        BLog(BLOG_ERROR, "ExpString_AppendChar failed");
+                        goto fail;
+                    }
+                }
+                
+                if (!ExpString_AppendChar(out_str, str[i])) {
+                    BLog(BLOG_ERROR, "ExpString_AppendChar failed");
+                    goto fail;
+                }
+            }
+            
+            if (!ExpString_AppendChar(out_str, '"')) {
+                BLog(BLOG_ERROR, "ExpString_AppendChar failed");
+                goto fail;
+            }
+        } break;
+        
+        case NCDVAL_LIST: {
+            size_t count = NCDVal_ListCount(value);
+            
+            if (!ExpString_AppendChar(out_str, '{')) {
+                BLog(BLOG_ERROR, "ExpString_AppendChar failed");
+                goto fail;
+            }
+            
+            for (size_t i = 0; i < count; i++) {
+                if (i > 0) {
+                    if (!ExpString_Append(out_str, ", ")) {
+                        BLog(BLOG_ERROR, "ExpString_Append failed");
+                        goto fail;
+                    }
+                }
+                
+                if (!generate_val(NCDVal_ListGet(value, i), out_str)) {
+                    goto fail;
+                }
+            }
+            
+            if (!ExpString_AppendChar(out_str, '}')) {
+                BLog(BLOG_ERROR, "ExpString_AppendChar failed");
+                goto fail;
+            }
+        } break;
+        
+        case NCDVAL_MAP: {
+            if (!ExpString_AppendChar(out_str, '[')) {
+                BLog(BLOG_ERROR, "ExpString_AppendChar failed");
+                goto fail;
+            }
+            
+            int is_first = 1;
+            
+            for (NCDValMapElem e = NCDVal_MapFirst(value); !NCDVal_MapElemInvalid(e); e = NCDVal_MapNext(value, e)) {
+                NCDValRef ekey = NCDVal_MapElemKey(value, e);
+                NCDValRef eval = NCDVal_MapElemVal(value, e);
+                
+                if (!is_first) {
+                    if (!ExpString_Append(out_str, ", ")) {
+                        BLog(BLOG_ERROR, "ExpString_Append failed");
+                        goto fail;
+                    }
+                }
+                
+                if (!generate_val(ekey, out_str)) {
+                    goto fail;
+                }
+                
+                if (!ExpString_AppendChar(out_str, ':')) {
+                    BLog(BLOG_ERROR, "ExpString_AppendChar failed");
+                    goto fail;
+                }
+                
+                if (!generate_val(eval, out_str)) {
+                    goto fail;
+                }
+                
+                is_first = 0;
+            }
+            
+            if (!ExpString_AppendChar(out_str, ']')) {
+                BLog(BLOG_ERROR, "ExpString_AppendChar failed");
+                goto fail;
+            }
+        } break;
+        
+        default: ASSERT(0);
+    }
+    
+    return 1;
+    
+fail:
+    return 0;
+}
+
 char * NCDValueGenerator_Generate (NCDValue *value)
 {
     NCDValue_Type(value);
@@ -197,3 +320,33 @@ int NCDValueGenerator_AppendGenerate (NCDValue *value, ExpString *str)
     
     return generate_value(value, str);
 }
+
+char * NCDValGenerator_Generate (NCDValRef value)
+{
+    ASSERT(!NCDVal_IsInvalid(value))
+    
+    ExpString str;
+    if (!ExpString_Init(&str)) {
+        BLog(BLOG_ERROR, "ExpString_Init failed");
+        goto fail0;
+    }
+    
+    if (!generate_val(value, &str)) {
+        goto fail1;
+    }
+    
+    return ExpString_Get(&str);
+    
+fail1:
+    ExpString_Free(&str);
+fail0:
+    return NULL;
+}
+
+int NCDValGenerator_AppendGenerate (NCDValRef value, ExpString *str)
+{
+    ASSERT(!NCDVal_IsInvalid(value))
+    ASSERT(str)
+    
+    return generate_val(value, str);
+}

+ 4 - 0
ncd/NCDValueGenerator.h

@@ -33,8 +33,12 @@
 #include <misc/debug.h>
 #include <misc/expstring.h>
 #include <ncd/NCDValue.h>
+#include <ncd/NCDVal.h>
 
 char * NCDValueGenerator_Generate (NCDValue *value);
 int NCDValueGenerator_AppendGenerate (NCDValue *value, ExpString *str) WARN_UNUSED;
 
+char * NCDValGenerator_Generate (NCDValRef value);
+int NCDValGenerator_AppendGenerate (NCDValRef value, ExpString *str) WARN_UNUSED;
+
 #endif

+ 21 - 0
ncd/NCDValueParser.c

@@ -34,6 +34,7 @@
 #include <misc/debug.h>
 #include <base/BLog.h>
 #include <ncd/NCDConfigTokenizer.h>
+#include <ncd/NCDValCompat.h>
 
 #include "NCDValueParser.h"
 
@@ -294,3 +295,23 @@ out:
     NCDConfig_free_list(state.out.ast_list);
     return res;
 }
+
+int NCDValParser_Parse (const char *str, size_t str_len, NCDValMem *mem, NCDValRef *out_value)
+{
+    ASSERT(mem)
+    ASSERT(out_value)
+    
+    NCDValue value;
+    if (!NCDValueParser_Parse(str, str_len, &value)) {
+        return 0;
+    }
+    
+    if (!NCDValCompat_ValueToVal(&value, mem, out_value)) {
+        BLog(BLOG_ERROR, "NCDValCompat_ValueToVal failed");
+        NCDValue_Free(&value);
+        return 0;
+    }
+    
+    NCDValue_Free(&value);
+    return 1;
+}

+ 3 - 0
ncd/NCDValueParser.h

@@ -34,7 +34,10 @@
 
 #include <misc/debug.h>
 #include <ncd/NCDValue.h>
+#include <ncd/NCDVal.h>
 
 int NCDValueParser_Parse (const char *str, size_t str_len, NCDValue *out_value) WARN_UNUSED;
 
+int NCDValParser_Parse (const char *str, size_t str_len, NCDValMem *mem, NCDValRef *out_value) WARN_UNUSED;
+
 #endif

+ 4 - 4
ncd/modules/alias.c

@@ -78,16 +78,16 @@ static int split_string_inplace (char *str, char del)
 static void func_new (NCDModuleInst *i)
 {
     // read arguments
-    NCDValue *target_arg;
-    if (!NCDValue_ListRead(i->args, 1, &target_arg)) {
+    NCDValRef target_arg;
+    if (!NCDVal_ListRead(i->args, 1, &target_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(target_arg)) {
+    if (!NCDVal_IsStringNoNulls(target_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    const char *target = NCDValue_StringValue(target_arg);
+    const char *target = NCDVal_StringValue(target_arg);
     size_t target_len = strlen(target);
     
     // calculate size

+ 9 - 9
ncd/modules/arithmetic.c

@@ -184,20 +184,20 @@ static void new_templ (NCDModuleInst *i, compute_func cfunc)
     o->i = i;
     NCDModuleInst_Backend_SetUser(i, o);
     
-    NCDValue *n1_arg;
-    NCDValue *n2_arg;
-    if (!NCDValue_ListRead(i->args, 2, &n1_arg, &n2_arg)) {
+    NCDValRef n1_arg;
+    NCDValRef n2_arg;
+    if (!NCDVal_ListRead(i->args, 2, &n1_arg, &n2_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(n1_arg) || !NCDValue_IsStringNoNulls(n2_arg)) {
+    if (!NCDVal_IsStringNoNulls(n1_arg) || !NCDVal_IsStringNoNulls(n2_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
     uintmax_t n1;
     uintmax_t n2;
-    if (!parse_unsigned_integer(NCDValue_StringValue(n1_arg), &n1) || !parse_unsigned_integer(NCDValue_StringValue(n2_arg), &n2)) {
+    if (!parse_unsigned_integer(NCDVal_StringValue(n1_arg), &n1) || !parse_unsigned_integer(NCDVal_StringValue(n2_arg), &n2)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong value");
         goto fail1;
     }
@@ -227,14 +227,14 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out_value)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitString(out_value, o->value)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, o->value);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         return 1;
     }

+ 4 - 4
ncd/modules/blocker.c

@@ -116,7 +116,7 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    if (!NCDValue_ListRead(o->i->args, 0)) {
+    if (!NCDVal_ListRead(o->i->args, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
@@ -185,7 +185,7 @@ static void updown_func_new_templ (NCDModuleInst *i, int up, int first_down)
     ASSERT(!first_down || up)
     
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -252,7 +252,7 @@ static void rdownup_func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
@@ -322,7 +322,7 @@ static void use_func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    if (!NCDValue_ListRead(o->i->args, 0)) {
+    if (!NCDVal_ListRead(o->i->args, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }

+ 17 - 9
ncd/modules/call.c

@@ -88,6 +88,7 @@ struct callrefhere_instance {
 
 struct instance {
     NCDModuleInst *i;
+    NCDValMem args_mem;
     NCDModuleProcess process;
     int state;
     struct callrefhere_instance *crh;
@@ -206,17 +207,17 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    NCDValue *template_name_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(o->i->args, 2, &template_name_arg, &args_arg)) {
+    NCDValRef template_name_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(i->args, 2, &template_name_arg, &args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(template_name_arg) || NCDValue_Type(args_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsStringNoNulls(template_name_arg) || !NCDVal_IsList(args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    char *template_name = NCDValue_StringValue(template_name_arg);
+    const char *template_name = NCDVal_StringValue(template_name_arg);
     
     // calling none?
     if (!strcmp(template_name, "<none>")) {
@@ -226,17 +227,21 @@ static void func_new (NCDModuleInst *i)
         // set state none
         o->state = STATE_NONE;
     } else {
+        // init args mem
+        NCDValMem_Init(&o->args_mem);
+        
         // copy arguments
-        NCDValue args;
-        if (!NCDValue_InitCopy(&args, args_arg)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
+        NCDValRef args = NCDVal_NewCopy(&o->args_mem, args_arg);
+        if (NCDVal_IsInvalid(args)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
+            NCDValMem_Free(&o->args_mem);
             goto fail1;
         }
         
         // create process
         if (!NCDModuleProcess_Init(&o->process, o->i, template_name, args, o, (NCDModuleProcess_handler_event)process_handler_event)) {
             ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
-            NCDValue_Free(&args);
+            NCDValMem_Free(&o->args_mem);
             goto fail1;
         }
         
@@ -274,6 +279,9 @@ void instance_free (struct instance *o)
             LinkedList0_Remove(&o->crh->calls_list, &o->calls_list_node);
         }
         
+        // free args mem
+        NCDValMem_Free(&o->args_mem);
+        
         // free process
         NCDModuleProcess_Free(&o->process);
     }

+ 60 - 73
ncd/modules/call2.c

@@ -64,7 +64,7 @@ struct instance {
 static void process_handler_event (struct instance *o, int event);
 static int process_func_getspecialobj (struct instance *o, const char *name, NCDObject *out_object);
 static int caller_obj_func_getobj (struct instance *o, const char *name, NCDObject *out_object);
-static void func_new_templ (NCDModuleInst *i, const char *template_name, NCDValue *args, int embed);
+static void func_new_templ (NCDModuleInst *i, const char *template_name, NCDValRef args, int embed);
 static void instance_free (struct instance *o);
 
 static void process_handler_event (struct instance *o, int event)
@@ -121,9 +121,9 @@ static int caller_obj_func_getobj (struct instance *o, const char *name, NCDObje
     return NCDModuleInst_Backend_GetObj(o->i, name, out_object);
 }
 
-static void func_new_templ (NCDModuleInst *i, const char *template_name, NCDValue *args, int embed)
+static void func_new_templ (NCDModuleInst *i, const char *template_name, NCDValRef args, int embed)
 {
-    ASSERT(!args || NCDValue_IsList(args))
+    ASSERT(NCDVal_IsInvalid(args) || NCDVal_IsList(args))
     ASSERT(embed == !!embed)
     
     // allocate instance
@@ -145,29 +145,12 @@ static void func_new_templ (NCDModuleInst *i, const char *template_name, NCDValu
         // set state none
         o->state = STATE_NONE;
     } else {
-        // copy arguments
-        NCDValue args_copy;
-        if (!args) {
-            NCDValue_InitList(&args_copy);
-        } else {
-            if (!NCDValue_InitCopy(&args_copy, args)) {
-                ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-                goto fail1;
-            }
-        }
-        
         // create process
-        if (!NCDModuleProcess_Init(&o->process, o->i, template_name, args_copy, o, (NCDModuleProcess_handler_event)process_handler_event)) {
+        if (!NCDModuleProcess_Init(&o->process, o->i, template_name, args, o, (NCDModuleProcess_handler_event)process_handler_event)) {
             ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
-            NCDValue_Free(&args_copy);
             goto fail1;
         }
         
-        // if this is an embed call, make the process ignore arguments
-        if (embed) {
-            NCDModuleProcess_SetNoArgs(&o->process);
-        }
-        
         // set special functions
         NCDModuleProcess_SetSpecialFuncs(&o->process, (NCDModuleProcess_func_getspecialobj)process_func_getspecialobj);
         
@@ -201,18 +184,18 @@ static void instance_free (struct instance *o)
 
 static void func_new_call (NCDModuleInst *i)
 {
-    NCDValue *template_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(i->args, 2, &template_arg, &args_arg)) {
+    NCDValRef template_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(i->args, 2, &template_arg, &args_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(template_arg) || !NCDValue_IsList(args_arg)) {
+    if (!NCDVal_IsStringNoNulls(template_arg) || !NCDVal_IsList(args_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
-    func_new_templ(i, NCDValue_StringValue(template_arg), args_arg, 0);
+    func_new_templ(i, NCDVal_StringValue(template_arg), args_arg, 0);
     return;
     
 fail0:
@@ -222,17 +205,17 @@ fail0:
 
 static void func_new_embcall (NCDModuleInst *i)
 {
-    NCDValue *template_arg;
-    if (!NCDValue_ListRead(i->args, 1, &template_arg)) {
+    NCDValRef template_arg;
+    if (!NCDVal_ListRead(i->args, 1, &template_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(template_arg)) {
+    if (!NCDVal_IsStringNoNulls(template_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
-    func_new_templ(i, NCDValue_StringValue(template_arg), NULL, 1);
+    func_new_templ(i, NCDVal_StringValue(template_arg), NCDVal_NewInvalid(), 1);
     return;
     
 fail0:
@@ -242,22 +225,22 @@ fail0:
 
 static void func_new_call_if (NCDModuleInst *i)
 {
-    NCDValue *cond_arg;
-    NCDValue *template_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(i->args, 3, &cond_arg, &template_arg, &args_arg)) {
+    NCDValRef cond_arg;
+    NCDValRef template_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(i->args, 3, &cond_arg, &template_arg, &args_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsString(cond_arg) || !NCDValue_IsStringNoNulls(template_arg) || !NCDValue_IsList(args_arg)) {
+    if (!NCDVal_IsString(cond_arg) || !NCDVal_IsStringNoNulls(template_arg) || !NCDVal_IsList(args_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     const char *template_name = NULL;
     
-    if (NCDValue_StringEquals(cond_arg, "true")) {
-        template_name = NCDValue_StringValue(template_arg);
+    if (NCDVal_StringEquals(cond_arg, "true")) {
+        template_name = NCDVal_StringValue(template_arg);
     }
     
     func_new_templ(i, template_name, args_arg, 0);
@@ -270,24 +253,24 @@ fail0:
 
 static void func_new_embcall_if (NCDModuleInst *i)
 {
-    NCDValue *cond_arg;
-    NCDValue *template_arg;
-    if (!NCDValue_ListRead(i->args, 2, &cond_arg, &template_arg)) {
+    NCDValRef cond_arg;
+    NCDValRef template_arg;
+    if (!NCDVal_ListRead(i->args, 2, &cond_arg, &template_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsString(cond_arg) || !NCDValue_IsStringNoNulls(template_arg)) {
+    if (!NCDVal_IsString(cond_arg) || !NCDVal_IsStringNoNulls(template_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     const char *template_name = NULL;
     
-    if (NCDValue_StringEquals(cond_arg, "true")) {
-        template_name = NCDValue_StringValue(template_arg);
+    if (NCDVal_StringEquals(cond_arg, "true")) {
+        template_name = NCDVal_StringValue(template_arg);
     }
     
-    func_new_templ(i, template_name, NULL, 1);
+    func_new_templ(i, template_name, NCDVal_NewInvalid(), 1);
     return;
     
 fail0:
@@ -297,25 +280,25 @@ fail0:
 
 static void func_new_call_ifelse (NCDModuleInst *i)
 {
-    NCDValue *cond_arg;
-    NCDValue *template_arg;
-    NCDValue *else_template_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(i->args, 4, &cond_arg, &template_arg, &else_template_arg, &args_arg)) {
+    NCDValRef cond_arg;
+    NCDValRef template_arg;
+    NCDValRef else_template_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(i->args, 4, &cond_arg, &template_arg, &else_template_arg, &args_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsString(cond_arg) || !NCDValue_IsStringNoNulls(template_arg) || !NCDValue_IsStringNoNulls(else_template_arg) || !NCDValue_IsList(args_arg)) {
+    if (!NCDVal_IsString(cond_arg) || !NCDVal_IsStringNoNulls(template_arg) || !NCDVal_IsStringNoNulls(else_template_arg) || !NCDVal_IsList(args_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     const char *template_name;
     
-    if (NCDValue_StringEquals(cond_arg, "true")) {
-        template_name = NCDValue_StringValue(template_arg);
+    if (NCDVal_StringEquals(cond_arg, "true")) {
+        template_name = NCDVal_StringValue(template_arg);
     } else {
-        template_name = NCDValue_StringValue(else_template_arg);
+        template_name = NCDVal_StringValue(else_template_arg);
     }
     
     func_new_templ(i, template_name, args_arg, 0);
@@ -328,27 +311,27 @@ fail0:
 
 static void func_new_embcall_ifelse (NCDModuleInst *i)
 {
-    NCDValue *cond_arg;
-    NCDValue *template_arg;
-    NCDValue *else_template_arg;
-    if (!NCDValue_ListRead(i->args, 3, &cond_arg, &template_arg, &else_template_arg)) {
+    NCDValRef cond_arg;
+    NCDValRef template_arg;
+    NCDValRef else_template_arg;
+    if (!NCDVal_ListRead(i->args, 3, &cond_arg, &template_arg, &else_template_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsString(cond_arg) || !NCDValue_IsStringNoNulls(template_arg) || !NCDValue_IsStringNoNulls(else_template_arg)) {
+    if (!NCDVal_IsString(cond_arg) || !NCDVal_IsStringNoNulls(template_arg) || !NCDVal_IsStringNoNulls(else_template_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     const char *template_name;
     
-    if (NCDValue_StringEquals(cond_arg, "true")) {
-        template_name = NCDValue_StringValue(template_arg);
+    if (NCDVal_StringEquals(cond_arg, "true")) {
+        template_name = NCDVal_StringValue(template_arg);
     } else {
-        template_name = NCDValue_StringValue(else_template_arg);
+        template_name = NCDVal_StringValue(else_template_arg);
     }
     
-    func_new_templ(i, template_name, NULL, 1);
+    func_new_templ(i, template_name, NCDVal_NewInvalid(), 1);
     return;
     
 fail0:
@@ -360,34 +343,38 @@ static void func_new_embcall_multif (NCDModuleInst *i)
 {
     const char *template_name = NULL;
     
-    NCDValue *arg = NCDValue_ListFirst(i->args);
+    size_t count = NCDVal_ListCount(i->args);
+    size_t j = 0;
     
-    while (arg) {
-        NCDValue *arg2 = NCDValue_ListNext(i->args, arg);
-        if (!arg2) {
-            if (!NCDValue_IsStringNoNulls(arg)) {
+    while (j < count) {
+        NCDValRef arg = NCDVal_ListGet(i->args, j);
+        
+        if (j == count - 1) {
+            if (!NCDVal_IsStringNoNulls(arg)) {
                 ModuleLog(i, BLOG_ERROR, "bad arguments");
                 goto fail0;
             }
             
-            template_name = NCDValue_StringValue(arg);
+            template_name = NCDVal_StringValue(arg);
             break;
         }
         
-        if (!NCDValue_IsString(arg) || !NCDValue_IsStringNoNulls(arg2)) {
+        NCDValRef arg2 = NCDVal_ListGet(i->args, j + 1);
+        
+        if (!NCDVal_IsString(arg) || !NCDVal_IsStringNoNulls(arg2)) {
             ModuleLog(i, BLOG_ERROR, "bad arguments");
             goto fail0;
         }
         
-        if (NCDValue_StringEquals(arg, "true")) {
-            template_name = NCDValue_StringValue(arg2);
+        if (NCDVal_StringEquals(arg, "true")) {
+            template_name = NCDVal_StringValue(arg2);
             break;
         }
         
-        arg = NCDValue_ListNext(i->args, arg2);
+        j += 2;
     }
     
-    func_new_templ(i, template_name, NULL, 1);
+    func_new_templ(i, template_name, NCDVal_NewInvalid(), 1);
     return;
     
 fail0:

+ 22 - 21
ncd/modules/choose.c

@@ -51,7 +51,7 @@
 
 struct instance {
     NCDModuleInst *i;
-    NCDValue *result;
+    NCDValRef result;
 };
 
 static void func_new (NCDModuleInst *i)
@@ -68,48 +68,50 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *arg_choices;
-    NCDValue *arg_default_result;
-    if (!NCDValue_ListRead(i->args, 2, &arg_choices, &arg_default_result)) {
+    NCDValRef arg_choices;
+    NCDValRef arg_default_result;
+    if (!NCDVal_ListRead(i->args, 2, &arg_choices, &arg_default_result)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (NCDValue_Type(arg_choices) != NCDVALUE_LIST) {
+    if (!NCDVal_IsList(arg_choices)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
-    // set no result
-    o->result = NULL;
-    
     // iterate choices
-    for (NCDValue *c = NCDValue_ListFirst(arg_choices); c; c = NCDValue_ListNext(arg_choices, c)) {
+    int have_result = 0;
+    size_t count = NCDVal_ListCount(arg_choices);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef c = NCDVal_ListGet(arg_choices, j);
+        
         // check choice type
-        if (NCDValue_Type(c) != NCDVALUE_LIST) {
+        if (!NCDVal_IsList(c)) {
             ModuleLog(i, BLOG_ERROR, "wrong choice type");
             goto fail1;
         }
         
         // read choice
-        NCDValue *c_cond;
-        NCDValue *c_result;
-        if (!NCDValue_ListRead(c, 2, &c_cond, &c_result)) {
+        NCDValRef c_cond;
+        NCDValRef c_result;
+        if (!NCDVal_ListRead(c, 2, &c_cond, &c_result)) {
             ModuleLog(i, BLOG_ERROR, "wrong choice contents arity");
             goto fail1;
         }
-        if (NCDValue_Type(c_cond) != NCDVALUE_STRING) {
+        if (!NCDVal_IsString(c_cond)) {
             ModuleLog(i, BLOG_ERROR, "wrong choice condition type");
             goto fail1;
         }
         
         // update result
-        if (!o->result && NCDValue_StringEquals(c_cond, "true")) {
+        if (!have_result && NCDVal_StringEquals(c_cond, "true")) {
             o->result = c_result;
+            have_result = 1;
         }
     }
     
     // default?
-    if (!o->result) {
+    if (!have_result) {
         o->result = arg_default_result;
     }
     
@@ -135,16 +137,15 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitCopy(out, o->result)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-            return 0;
+        *out = NCDVal_NewCopy(mem, o->result);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     

+ 10 - 11
ncd/modules/concat.c

@@ -71,19 +71,19 @@ static void func_new (NCDModuleInst *i)
     }
     
     // append arguments
-    NCDValue *arg = NCDValue_ListFirst(o->i->args);
-    while (arg) {
-        if (NCDValue_Type(arg) != NCDVALUE_STRING) {
+    size_t count = NCDVal_ListCount(i->args);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef arg = NCDVal_ListGet(i->args, j);
+        
+        if (!NCDVal_IsString(arg)) {
             ModuleLog(i, BLOG_ERROR, "wrong type");
             goto fail2;
         }
         
-        if (!ExpString_AppendBinary(&s, (const uint8_t *)NCDValue_StringValue(arg), NCDValue_StringLength(arg))) {
+        if (!ExpString_AppendBinary(&s, (const uint8_t *)NCDVal_StringValue(arg), NCDVal_StringLength(arg))) {
             ModuleLog(i, BLOG_ERROR, "ExpString_Append failed");
             goto fail2;
         }
-        
-        arg = NCDValue_ListNext(o->i->args, arg);
     }
     
     // set string
@@ -118,16 +118,15 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitStringBin(out, o->string, o->len)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitStringBin failed");
-            return 0;
+        *out = NCDVal_NewStringBin(mem, o->string, o->len);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewStringBin failed");
         }
-        
         return 1;
     }
     

+ 13 - 14
ncd/modules/concatv.c

@@ -64,12 +64,12 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *strings_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &strings_arg)) {
+    NCDValRef strings_arg;
+    if (!NCDVal_ListRead(o->i->args, 1, &strings_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (NCDValue_Type(strings_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsList(strings_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
@@ -82,19 +82,19 @@ static void func_new (NCDModuleInst *i)
     }
     
     // append arguments
-    NCDValue *arg = NCDValue_ListFirst(strings_arg);
-    while (arg) {
-        if (NCDValue_Type(arg) != NCDVALUE_STRING) {
+    size_t count = NCDVal_ListCount(strings_arg);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef arg = NCDVal_ListGet(strings_arg, j);
+        
+        if (!NCDVal_IsString(arg)) {
             ModuleLog(i, BLOG_ERROR, "wrong type");
             goto fail2;
         }
         
-        if (!ExpString_AppendBinary(&s, (const uint8_t *)NCDValue_StringValue(arg), NCDValue_StringLength(arg))) {
+        if (!ExpString_AppendBinary(&s, (const uint8_t *)NCDVal_StringValue(arg), NCDVal_StringLength(arg))) {
             ModuleLog(i, BLOG_ERROR, "ExpString_Append failed");
             goto fail2;
         }
-        
-        arg = NCDValue_ListNext(strings_arg, arg);
     }
     
     // set string
@@ -129,16 +129,15 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitStringBin(out, o->string, o->len)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitStringBin failed");
-            return 0;
+        *out = NCDVal_NewStringBin(mem, o->string, o->len);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     

+ 18 - 13
ncd/modules/daemon.c

@@ -61,36 +61,40 @@
 
 struct instance {
     NCDModuleInst *i;
-    NCDValue *cmd_arg;
+    NCDValRef cmd_arg;
     BTimer timer;
     BProcess process;
     int state;
 };
 
-static int build_cmdline (NCDModuleInst *i, NCDValue *cmd_arg, char **exec, CmdLine *cl);
+static int build_cmdline (NCDModuleInst *i, NCDValRef cmd_arg, char **exec, CmdLine *cl);
 static void start_process (struct instance *o);
 static void timer_handler (struct instance *o);
 static void process_handler (struct instance *o, int normally, uint8_t normally_exit_status);
 static void instance_free (struct instance *o);
 
-static int build_cmdline (NCDModuleInst *i, NCDValue *cmd_arg, char **exec, CmdLine *cl)
+static int build_cmdline (NCDModuleInst *i, NCDValRef cmd_arg, char **exec, CmdLine *cl)
 {
-    if (NCDValue_Type(cmd_arg) != NCDVALUE_LIST) {
+    ASSERT(!NCDVal_IsInvalid(cmd_arg))
+    
+    if (!NCDVal_IsList(cmd_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
+    size_t count = NCDVal_ListCount(cmd_arg);
+    
     // read exec
-    NCDValue *exec_arg = NCDValue_ListFirst(cmd_arg);
-    if (!exec_arg) {
+    if (count == 0) {
         ModuleLog(i, BLOG_ERROR, "missing executable name");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(exec_arg)) {
+    NCDValRef exec_arg = NCDVal_ListGet(cmd_arg, 0);
+    if (!NCDVal_IsStringNoNulls(exec_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    if (!(*exec = strdup(NCDValue_StringValue(exec_arg)))) {
+    if (!(*exec = strdup(NCDVal_StringValue(exec_arg)))) {
         ModuleLog(i, BLOG_ERROR, "strdup failed");
         goto fail0;
     }
@@ -108,14 +112,15 @@ static int build_cmdline (NCDModuleInst *i, NCDValue *cmd_arg, char **exec, CmdL
     }
     
     // add additional arguments
-    NCDValue *arg = exec_arg;
-    while (arg = NCDValue_ListNext(cmd_arg, arg)) {
-        if (!NCDValue_IsStringNoNulls(arg)) {
+    for (size_t j = 1; j < count; j++) {
+        NCDValRef arg = NCDVal_ListGet(cmd_arg, j);
+        
+        if (!NCDVal_IsStringNoNulls(arg)) {
             ModuleLog(i, BLOG_ERROR, "wrong type");
             goto fail2;
         }
         
-        if (!CmdLine_Append(cl, NCDValue_StringValue(arg))) {
+        if (!CmdLine_Append(cl, NCDVal_StringValue(arg))) {
             ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
             goto fail2;
         }
@@ -213,7 +218,7 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    if (!NCDValue_ListRead(i->args, 1, &o->cmd_arg)) {
+    if (!NCDVal_ListRead(i->args, 1, &o->cmd_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }

+ 12 - 12
ncd/modules/depend.c

@@ -69,7 +69,7 @@
 
 struct provide {
     NCDModuleInst *i;
-    char *name;
+    const char *name;
     int is_queued;
     union {
         struct {
@@ -86,7 +86,7 @@ struct provide {
 
 struct depend {
     NCDModuleInst *i;
-    char *name;
+    const char *name;
     struct provide *p;
     LinkedList2Node node;
 };
@@ -179,16 +179,16 @@ static void provide_func_new_templ (NCDModuleInst *i, int event)
     o->i = i;
     
     // read arguments
-    NCDValue *name_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &name_arg)) {
-        ModuleLog(i, BLOG_ERROR, "wrong arity");
+    NCDValRef name_arg;
+    if (!NCDVal_ListRead(i->args, 1, &name_arg)) {
+        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsStringNoNulls(name_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->name = NCDValue_StringValue(name_arg);
+    o->name = NCDVal_StringValue(name_arg);
     
     // signal up.
     // This comes above provide_promote(), so that effects on related depend statements are
@@ -312,16 +312,16 @@ static void depend_func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *name_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &name_arg)) {
-        ModuleLog(i, BLOG_ERROR, "wrong arity");
+    NCDValRef name_arg;
+    if (!NCDVal_ListRead(i->args, 1, &name_arg)) {
+        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsStringNoNulls(name_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->name = NCDValue_StringValue(name_arg);
+    o->name = NCDVal_StringValue(name_arg);
     
     // find a provide with our name
     struct provide *p = find_provide(o->name);

+ 12 - 12
ncd/modules/dynamic_depend.c

@@ -62,7 +62,7 @@ struct name {
 struct provide {
     NCDModuleInst *i;
     struct name *n;
-    NCDValue *order_value;
+    NCDValRef order_value;
     BAVLNode provides_tree_node;
     int dying;
 };
@@ -91,9 +91,9 @@ static int stringptr_comparator (void *user, char **v1, char **v2)
     return 0;
 }
 
-static int valueptr_comparator (void *user, NCDValue **v1, NCDValue **v2)
+static int val_comparator (void *user, NCDValRef *v1, NCDValRef *v2)
 {
-    return NCDValue_Compare(*v1, *v2);
+    return NCDVal_Compare(*v1, *v2);
 }
 
 static struct name * find_name (const char *name)
@@ -130,7 +130,7 @@ static struct name * name_init (NCDModuleInst *i, const char *name)
     ASSERT_EXECUTE(BAVL_Insert(&names_tree, &o->names_tree_node, NULL))
     
     // init provides tree
-    BAVL_Init(&o->provides_tree, OFFSET_DIFF(struct provide, order_value, provides_tree_node), (BAVL_comparator)valueptr_comparator, NULL);
+    BAVL_Init(&o->provides_tree, OFFSET_DIFF(struct provide, order_value, provides_tree_node), (BAVL_comparator)val_comparator, NULL);
     
     // init waiting depends list
     LinkedList0_Init(&o->waiting_depends_list);
@@ -287,16 +287,16 @@ static void provide_func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *name_arg;
-    if (!NCDValue_ListRead(i->args, 2, &name_arg, &o->order_value)) {
+    NCDValRef name_arg;
+    if (!NCDVal_ListRead(i->args, 2, &name_arg, &o->order_value)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsStringNoNulls(name_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    char *name_str = NCDValue_StringValue(name_arg);
+    const char *name_str = NCDVal_StringValue(name_arg);
     
     // find name, create new if needed
     struct name *n = find_name(name_str);
@@ -397,16 +397,16 @@ static void depend_func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *name_arg;
-    if (!NCDValue_ListRead(i->args, 1, &name_arg)) {
+    NCDValRef name_arg;
+    if (!NCDVal_ListRead(i->args, 1, &name_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsStringNoNulls(name_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    char *name_str = NCDValue_StringValue(name_arg);
+    const char *name_str = NCDVal_StringValue(name_arg);
     
     // find name, create new if needed
     struct name *n = find_name(name_str);

+ 4 - 5
ncd/modules/event_template.c

@@ -118,7 +118,7 @@ void event_template_die (event_template *o)
     return;
 }
 
-int event_template_getvar (event_template *o, const char *name, NCDValue *out)
+int event_template_getvar (event_template *o, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     ASSERT(o->enabled)
     ASSERT(name)
@@ -128,11 +128,10 @@ int event_template_getvar (event_template *o, const char *name, NCDValue *out)
         return 0;
     }
     
-    if (!NCDValue_InitString(out, val)) {
-        TemplateLog(o, BLOG_ERROR, "NCDValue_InitString failed");
-        return 0;
+    *out = NCDVal_NewString(mem, val);
+    if (NCDVal_IsInvalid(*out)) {
+        TemplateLog(o, BLOG_ERROR, "NCDVal_NewString failed");
     }
-    
     return 1;
 }
 

+ 1 - 1
ncd/modules/event_template.h

@@ -56,7 +56,7 @@ struct event_template_event {
 void event_template_new (event_template *o, NCDModuleInst *i, int blog_channel, int maxevents, void *user,
                          event_template_func_free func_free);
 void event_template_die (event_template *o);
-int event_template_getvar (event_template *o, const char *name, NCDValue *out);
+int event_template_getvar (event_template *o, const char *name, NCDValMem *mem, NCDValRef *out);
 void event_template_queue (event_template *o, BStringMap map, int *out_was_empty);
 void event_template_dequeue (event_template *o, int *out_is_empty);
 int event_template_is_enabled (event_template *o);

+ 4 - 4
ncd/modules/exit.c

@@ -49,19 +49,19 @@
 static void func_new (NCDModuleInst *i)
 {
     // check arguments
-    NCDValue *exit_code_arg;
-    if (!NCDValue_ListRead(i->args, 1, &exit_code_arg)) {
+    NCDValRef exit_code_arg;
+    if (!NCDVal_ListRead(i->args, 1, &exit_code_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(exit_code_arg)) {
+    if (!NCDVal_IsStringNoNulls(exit_code_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     // parse exit code
     uintmax_t exit_code;
-    if (!parse_unsigned_integer(NCDValue_StringValue(exit_code_arg), &exit_code) || exit_code >= INT_MAX) {
+    if (!parse_unsigned_integer(NCDVal_StringValue(exit_code_arg), &exit_code) || exit_code >= INT_MAX) {
         ModuleLog(i, BLOG_ERROR, "wrong exit code value");
         goto fail0;
     }

+ 13 - 13
ncd/modules/file.c

@@ -90,18 +90,18 @@ static void read_func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // read arguments
-    NCDValue *filename_arg;
-    if (!NCDValue_ListRead(i->args, 1, &filename_arg)) {
+    NCDValRef filename_arg;
+    if (!NCDVal_ListRead(i->args, 1, &filename_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(filename_arg)) {
+    if (!NCDVal_IsStringNoNulls(filename_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
     // read file
-    if (!read_file(NCDValue_StringValue(filename_arg), &o->file_data, &o->file_len)) {
+    if (!read_file(NCDVal_StringValue(filename_arg), &o->file_data, &o->file_len)) {
         ModuleLog(i, BLOG_ERROR, "failed to read file");
         goto fail1;
     }
@@ -131,14 +131,14 @@ static void read_func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int read_func_getvar (void *vo, const char *name, NCDValue *out_value)
+static int read_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct read_instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitStringBin(out_value, o->file_data, o->file_len)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitStringBin failed");
-            return 0;
+        *out = NCDVal_NewStringBin(mem, o->file_data, o->file_len);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewStringBin failed");
         }
         return 1;
     }
@@ -149,19 +149,19 @@ static int read_func_getvar (void *vo, const char *name, NCDValue *out_value)
 static void write_func_new (NCDModuleInst *i)
 {
     // read arguments
-    NCDValue *filename_arg;
-    NCDValue *contents_arg;
-    if (!NCDValue_ListRead(i->args, 2, &filename_arg, &contents_arg)) {
+    NCDValRef filename_arg;
+    NCDValRef contents_arg;
+    if (!NCDVal_ListRead(i->args, 2, &filename_arg, &contents_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(filename_arg) || !NCDValue_IsString(contents_arg)) {
+    if (!NCDVal_IsStringNoNulls(filename_arg) || !NCDVal_IsString(contents_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     // write file
-    if (!write_file(NCDValue_StringValue(filename_arg), (const uint8_t *)NCDValue_StringValue(contents_arg), NCDValue_StringLength(contents_arg))) {
+    if (!write_file(NCDVal_StringValue(filename_arg), (const uint8_t *)NCDVal_StringValue(contents_arg), NCDVal_StringLength(contents_arg))) {
         ModuleLog(i, BLOG_ERROR, "failed to write file");
         goto fail0;
     }

+ 26 - 39
ncd/modules/foreach.c

@@ -74,8 +74,8 @@ struct element;
 
 struct instance {
     NCDModuleInst *i;
-    char *template_name;
-    NCDValue *args;
+    const char *template_name;
+    NCDValRef args;
     BTimer timer;
     size_t num_elems;
     struct element *elems;
@@ -87,7 +87,7 @@ struct instance {
 struct element {
     struct instance *inst;
     size_t i;
-    NCDValue *value;
+    NCDValRef value;
     NCDModuleProcess process;
     int state;
 };
@@ -99,8 +99,8 @@ static void timer_handler (struct instance *o);
 static void element_process_handler_event (struct element *e, int event);
 static int element_process_func_getspecialobj (struct element *e, const char *name, NCDObject *out_object);
 static int element_caller_object_func_getobj (struct element *e, const char *name, NCDObject *out_object);
-static int element_index_object_func_getvar (struct element *e, const char *name, NCDValue *out_value);
-static int element_elem_object_func_getvar (struct element *e, const char *name, NCDValue *out_value);
+static int element_index_object_func_getvar (struct element *e, const char *name, NCDValMem *mem, NCDValRef *out);
+static int element_elem_object_func_getvar (struct element *e, const char *name, NCDValMem *mem, NCDValRef *out);
 static void instance_free (struct instance *o);
 
 static void assert_state (struct instance *o)
@@ -228,17 +228,9 @@ static void advance (struct instance *o)
     // get next element
     struct element *e = &o->elems[o->gp];
     
-    // copy arguments
-    NCDValue args;
-    if (!NCDValue_InitCopy(&args, o->args)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail;
-    }
-    
     // init process
-    if (!NCDModuleProcess_Init(&e->process, o->i, o->template_name, args, e, (NCDModuleProcess_handler_event)element_process_handler_event)) {
+    if (!NCDModuleProcess_Init(&e->process, o->i, o->template_name, o->args, e, (NCDModuleProcess_handler_event)element_process_handler_event)) {
         ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
-        NCDValue_Free(&args);
         goto fail;
     }
     
@@ -352,7 +344,7 @@ static int element_caller_object_func_getobj (struct element *e, const char *nam
     return NCDModuleInst_Backend_GetObj(o->i, name, out_object);
 }
 
-static int element_index_object_func_getvar (struct element *e, const char *name, NCDValue *out_value)
+static int element_index_object_func_getvar (struct element *e, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = e->inst;
     ASSERT(e->state != ESTATE_FORGOTTEN)
@@ -364,15 +356,14 @@ static int element_index_object_func_getvar (struct element *e, const char *name
     char str[64];
     snprintf(str, sizeof(str), "%zu", e->i);
     
-    if (!NCDValue_InitString(out_value, str)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-        return 0;
+    *out = NCDVal_NewString(mem, str);
+    if (NCDVal_IsInvalid(*out)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
     }
-    
     return 1;
 }
 
-static int element_elem_object_func_getvar (struct element *e, const char *name, NCDValue *out_value)
+static int element_elem_object_func_getvar (struct element *e, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = e->inst;
     ASSERT(e->state != ESTATE_FORGOTTEN)
@@ -381,11 +372,10 @@ static int element_elem_object_func_getvar (struct element *e, const char *name,
         return 0;
     }
     
-    if (!NCDValue_InitCopy(out_value, e->value)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        return 0;
+    *out = NCDVal_NewCopy(mem, e->value);
+    if (NCDVal_IsInvalid(*out)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
     }
-    
     return 1;
 }
 
@@ -403,20 +393,20 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *arg_list;
-    NCDValue *arg_template;
-    NCDValue *arg_args;
-    if (!NCDValue_ListRead(i->args, 3, &arg_list, &arg_template, &arg_args)) {
+    NCDValRef arg_list;
+    NCDValRef arg_template;
+    NCDValRef arg_args;
+    if (!NCDVal_ListRead(i->args, 3, &arg_list, &arg_template, &arg_args)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (NCDValue_Type(arg_list) != NCDVALUE_LIST || !NCDValue_IsStringNoNulls(arg_template) ||
-        NCDValue_Type(arg_args) != NCDVALUE_LIST
+    if (!NCDVal_IsList(arg_list) || !NCDVal_IsStringNoNulls(arg_template) ||
+        !NCDVal_IsList(arg_args)
     ) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->template_name = NCDValue_StringValue(arg_template);
+    o->template_name = NCDVal_StringValue(arg_template);
     o->args = arg_args;
     
     // init timer
@@ -424,7 +414,7 @@ static void func_new (NCDModuleInst *i)
     BTimer_Init(&o->timer, retry_time, (BTimer_handler)timer_handler, o);
     
     // count elements
-    o->num_elems = NCDValue_ListCount(arg_list);
+    o->num_elems = NCDVal_ListCount(arg_list);
     
     // allocate elements
     if (!(o->elems = BAllocArray(o->num_elems, sizeof(o->elems[0])))) {
@@ -432,24 +422,21 @@ static void func_new (NCDModuleInst *i)
         goto fail1;
     }
     
-    NCDValue *ev = NCDValue_ListFirst(arg_list);
-    
-    for (size_t i = 0; i < o->num_elems; i++) {
-        struct element *e = &o->elems[i];
+    for (size_t j = 0; j < o->num_elems; j++) {
+        struct element *e = &o->elems[j];
+        NCDValRef ev = NCDVal_ListGet(arg_list, j);
         
         // set instance
         e->inst = o;
         
         // set index
-        e->i = i;
+        e->i = j;
         
         // set value
         e->value = ev;
         
         // set state forgotten
         e->state = ESTATE_FORGOTTEN;
-        
-        ev = NCDValue_ListNext(arg_list, ev);
     }
     
     // set GP and IP zero

+ 19 - 13
ncd/modules/from_string.c

@@ -46,7 +46,8 @@
 
 struct instance {
     NCDModuleInst *i;
-    NCDValue v;
+    NCDValMem mem;
+    NCDValRef val;
 };
 
 static void func_new (NCDModuleInst *i)
@@ -61,27 +62,32 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // read arguments
-    NCDValue *str_arg;
-    if (!NCDValue_ListRead(i->args, 1, &str_arg)) {
+    NCDValRef str_arg;
+    if (!NCDVal_ListRead(i->args, 1, &str_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(str_arg)) {
+    if (!NCDVal_IsStringNoNulls(str_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    char *str = NCDValue_StringValue(str_arg);
+    const char *str = NCDVal_StringValue(str_arg);
+    
+    // init mem
+    NCDValMem_Init(&o->mem);
     
     // parse value string
-    if (!NCDValueParser_Parse(str, strlen(str), &o->v)) {
+    if (!NCDValParser_Parse(str, strlen(str), &o->mem, &o->val)) {
         ModuleLog(i, BLOG_ERROR, "failed to parse");
-        goto fail1;
+        goto fail2;
     }
     
     // signal up
     NCDModuleInst_Backend_Up(i);
     return;
     
+fail2:
+    NCDValMem_Free(&o->mem);
 fail1:
     free(o);
 fail0:
@@ -94,8 +100,8 @@ static void func_die (void *vo)
     struct instance *o = vo;
     NCDModuleInst *i = o->i;
     
-    // free value
-    NCDValue_Free(&o->v);
+    // free mem
+    NCDValMem_Free(&o->mem);
     
     // free structure
     free(o);
@@ -103,14 +109,14 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitCopy(out, &o->v)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopu failed");
-            return 0;
+        *out = NCDVal_NewCopy(mem, o->val);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
         }
         return 1;
     }

+ 3 - 3
ncd/modules/getargs.c

@@ -48,7 +48,7 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, i);
     
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -62,12 +62,12 @@ fail0:
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out_value)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     NCDModuleInst *i = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDModuleInst_Backend_InterpGetArgs(i, out_value)) {
+        if (!NCDModuleInst_Backend_InterpGetArgs(i, mem, out)) {
             ModuleLog(i, BLOG_ERROR, "NCDModuleInst_Backend_InterpGetArgs failed");
             return 0;
         }

+ 6 - 6
ncd/modules/if.c

@@ -48,24 +48,24 @@
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
 
-static void new_templ (NCDModuleInst *i, int not)
+static void new_templ (NCDModuleInst *i, int is_not)
 {
     // check arguments
-    NCDValue *arg;
-    if (!NCDValue_ListRead(i->args, 1, &arg)) {
+    NCDValRef arg;
+    if (!NCDVal_ListRead(i->args, 1, &arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (NCDValue_Type(arg) != NCDVALUE_STRING) {
+    if (!NCDVal_IsString(arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     // compute logical value of argument
-    int c = NCDValue_StringEquals(arg, "true");
+    int c = NCDVal_StringEquals(arg, "true");
     
     // signal up if needed
-    if ((not && !c) || (!not && c)) {
+    if ((is_not && !c) || (!is_not && c)) {
         NCDModuleInst_Backend_Up(i);
     }
     

+ 18 - 27
ncd/modules/imperative.c

@@ -68,15 +68,15 @@
 
 struct instance {
     NCDModuleInst *i;
-    char *deinit_template;
-    NCDValue *deinit_args;
+    const char *deinit_template;
+    NCDValRef deinit_args;
     BTimer deinit_timer;
     NCDModuleProcess process;
     int state;
     int dying;
 };
 
-static int start_process (struct instance *o, const char *templ, NCDValue *args, NCDModuleProcess_handler_event handler);
+static int start_process (struct instance *o, const char *templ, NCDValRef args, NCDModuleProcess_handler_event handler);
 static void go_deinit (struct instance *o);
 static void init_process_handler_event (struct instance *o, int event);
 static void deinit_process_handler_event (struct instance *o, int event);
@@ -85,28 +85,19 @@ static int process_caller_object_func_getobj (struct instance *o, const char *na
 static void deinit_timer_handler (struct instance *o);
 static void instance_free (struct instance *o);
 
-static int start_process (struct instance *o, const char *templ, NCDValue *args, NCDModuleProcess_handler_event handler)
+static int start_process (struct instance *o, const char *templ, NCDValRef args, NCDModuleProcess_handler_event handler)
 {
-    // copy arguments
-    NCDValue args_copy;
-    if (!NCDValue_InitCopy(&args_copy, args)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail;
-    }
+    ASSERT(NCDVal_IsList(args))
     
     // create process
-    if (!NCDModuleProcess_Init(&o->process, o->i, templ, args_copy, o, handler)) {
+    if (!NCDModuleProcess_Init(&o->process, o->i, templ, args, o, handler)) {
         ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
-        NCDValue_Free(&args_copy);
-        goto fail;
+        return 0;
     }
     
     // set special functions
     NCDModuleProcess_SetSpecialFuncs(&o->process, (NCDModuleProcess_func_getspecialobj)process_func_getspecialobj);
     return 1;
-    
-fail:
-    return 0;
 }
 
 static void go_deinit (struct instance *o)
@@ -247,26 +238,26 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    NCDValue *init_template_arg;
-    NCDValue *init_args;
-    NCDValue *deinit_template_arg;
-    NCDValue *deinit_timeout_arg;
-    if (!NCDValue_ListRead(i->args, 5, &init_template_arg, &init_args, &deinit_template_arg, &o->deinit_args, &deinit_timeout_arg)) {
+    NCDValRef init_template_arg;
+    NCDValRef init_args;
+    NCDValRef deinit_template_arg;
+    NCDValRef deinit_timeout_arg;
+    if (!NCDVal_ListRead(i->args, 5, &init_template_arg, &init_args, &deinit_template_arg, &o->deinit_args, &deinit_timeout_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(init_template_arg) || NCDValue_Type(init_args) != NCDVALUE_LIST ||
-        !NCDValue_IsStringNoNulls(deinit_template_arg) || NCDValue_Type(o->deinit_args) != NCDVALUE_LIST ||
-        !NCDValue_IsStringNoNulls(deinit_timeout_arg)) {
+    if (!NCDVal_IsStringNoNulls(init_template_arg) || !NCDVal_IsList(init_args)  ||
+        !NCDVal_IsStringNoNulls(deinit_template_arg) || !NCDVal_IsList(o->deinit_args) ||
+        !NCDVal_IsStringNoNulls(deinit_timeout_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    char *init_template = NCDValue_StringValue(init_template_arg);
-    o->deinit_template = NCDValue_StringValue(deinit_template_arg);
+    const char *init_template = NCDVal_StringValue(init_template_arg);
+    o->deinit_template = NCDVal_StringValue(deinit_template_arg);
     
     // read timeout
     uintmax_t timeout;
-    if (!parse_unsigned_integer(NCDValue_StringValue(deinit_timeout_arg), &timeout) || timeout > UINT64_MAX) {
+    if (!parse_unsigned_integer(NCDVal_StringValue(deinit_timeout_arg), &timeout) || timeout > UINT64_MAX) {
         ModuleLog(i, BLOG_ERROR, "wrong timeout");
         goto fail1;
     }

+ 16 - 14
ncd/modules/implode.c

@@ -64,13 +64,13 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // read arguments
-    NCDValue *glue_arg;
-    NCDValue *pieces_arg;
-    if (!NCDValue_ListRead(i->args, 2, &glue_arg, &pieces_arg)) {
+    NCDValRef glue_arg;
+    NCDValRef pieces_arg;
+    if (!NCDVal_ListRead(i->args, 2, &glue_arg, &pieces_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsString(glue_arg) || !NCDValue_IsList(pieces_arg)) {
+    if (!NCDVal_IsString(glue_arg) || !NCDVal_IsList(pieces_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
@@ -82,23 +82,26 @@ static void func_new (NCDModuleInst *i)
         goto fail1;
     }
     
-    for (NCDValue *piece = NCDValue_ListFirst(pieces_arg); piece; piece = NCDValue_ListNext(pieces_arg, piece)) {
+    size_t count = NCDVal_ListCount(pieces_arg);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef piece = NCDVal_ListGet(pieces_arg, j);
+        
         // check piece type
-        if (!NCDValue_IsString(piece)) {
+        if (!NCDVal_IsString(piece)) {
             ModuleLog(i, BLOG_ERROR, "wrong piece type");
             goto fail2;
         }
         
         // append glue
-        if (piece != NCDValue_ListFirst(pieces_arg)) {
-            if (!ExpString_AppendBinary(&str, (const uint8_t *)NCDValue_StringValue(glue_arg), NCDValue_StringLength(glue_arg))) {
+        if (j > 0) {
+            if (!ExpString_AppendBinary(&str, (const uint8_t *)NCDVal_StringValue(glue_arg), NCDVal_StringLength(glue_arg))) {
                 ModuleLog(i, BLOG_ERROR, "ExpString_AppendBinary failed");
                 goto fail2;
             }
         }
         
         // append piece
-        if (!ExpString_AppendBinary(&str, (const uint8_t *)NCDValue_StringValue(piece), NCDValue_StringLength(piece))) {
+        if (!ExpString_AppendBinary(&str, (const uint8_t *)NCDVal_StringValue(piece), NCDVal_StringLength(piece))) {
             ModuleLog(i, BLOG_ERROR, "ExpString_AppendBinary failed");
             goto fail2;
         }
@@ -135,16 +138,15 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out_value)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitStringBin(out_value, (uint8_t *)o->result, o->result_len)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitStringBin failed");
-            return 0;
+        *out = NCDVal_NewStringBin(mem, (uint8_t *)o->result, o->result_len);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewStringBin failed");
         }
-        
         return 1;
     }
     

+ 8 - 9
ncd/modules/index.c

@@ -86,19 +86,19 @@ fail0:
 static void func_new_from_value (NCDModuleInst *i)
 {
     // read arguments
-    NCDValue *arg_value;
-    if (!NCDValue_ListRead(i->args, 1, &arg_value)) {
+    NCDValRef arg_value;
+    if (!NCDVal_ListRead(i->args, 1, &arg_value)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(arg_value)) {
+    if (!NCDVal_IsStringNoNulls(arg_value)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     // parse value
     uintmax_t value;
-    if (!parse_unsigned_integer(NCDValue_StringValue(arg_value), &value)) {
+    if (!parse_unsigned_integer(NCDVal_StringValue(arg_value), &value)) {
         ModuleLog(i, BLOG_ERROR, "wrong value");
         goto fail0;
     }
@@ -146,7 +146,7 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
@@ -154,11 +154,10 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
         char str[64];
         snprintf(str, sizeof(str), "%zu", o->value);
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     

+ 12 - 13
ncd/modules/ip_in_network.c

@@ -65,14 +65,14 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *arg_addr1;
-    NCDValue *arg_addr2;
-    NCDValue *arg_netprefix;
-    if (!NCDValue_ListRead(o->i->args, 3, &arg_addr1, &arg_addr2, &arg_netprefix)) {
+    NCDValRef arg_addr1;
+    NCDValRef arg_addr2;
+    NCDValRef arg_netprefix;
+    if (!NCDVal_ListRead(o->i->args, 3, &arg_addr1, &arg_addr2, &arg_netprefix)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(arg_addr1) || !NCDValue_IsStringNoNulls(arg_addr2) || !NCDValue_IsStringNoNulls(arg_netprefix)) {
+    if (!NCDVal_IsStringNoNulls(arg_addr1) || !NCDVal_IsStringNoNulls(arg_addr2) || !NCDVal_IsStringNoNulls(arg_netprefix)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
@@ -81,15 +81,15 @@ static void func_new (NCDModuleInst *i)
     uint32_t addr1;
     uint32_t addr2;
     int netprefix;
-    if (!ipaddr_parse_ipv4_addr(NCDValue_StringValue(arg_addr1), &addr1)) {
+    if (!ipaddr_parse_ipv4_addr((char *)NCDVal_StringValue(arg_addr1), &addr1)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong addr1");
         goto fail1;
     }
-    if (!ipaddr_parse_ipv4_addr(NCDValue_StringValue(arg_addr2), &addr2)) {
+    if (!ipaddr_parse_ipv4_addr((char *)NCDVal_StringValue(arg_addr2), &addr2)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong addr2");
         goto fail1;
     }
-    if (!ipaddr_parse_ipv4_prefix(NCDValue_StringValue(arg_netprefix), &netprefix)) {
+    if (!ipaddr_parse_ipv4_prefix((char *)NCDVal_StringValue(arg_netprefix), &netprefix)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong netprefix");
         goto fail1;
     }
@@ -120,18 +120,17 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
         const char *v = (o->value ? "true" : "false");
         
-        if (!NCDValue_InitString(out, v)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, v);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     

+ 284 - 179
ncd/modules/list.c

@@ -93,25 +93,34 @@
 #include <inttypes.h>
 
 #include <misc/parse_number.h>
+#include <misc/offset.h>
+#include <structure/IndexedList.h>
 #include <ncd/NCDModule.h>
 
 #include <generated/blog_channel_ncd_list.h>
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
 
+struct elem {
+    IndexedListNode il_node;
+    NCDValMem mem;
+    NCDValRef val;
+};
+
 struct instance {
     NCDModuleInst *i;
-    NCDValue list;
+    IndexedList il;
 };
 
 struct length_instance {
     NCDModuleInst *i;
-    size_t length;
+    uint64_t length;
 };
 
 struct get_instance {
     NCDModuleInst *i;
-    NCDValue value;
+    NCDValMem mem;
+    NCDValRef val;
 };
 
 struct contains_instance {
@@ -122,69 +131,207 @@ struct contains_instance {
 struct find_instance {
     NCDModuleInst *i;
     int is_found;
-    size_t found_pos;
+    uint64_t found_pos;
 };
 
-static int append_list_args (NCDModuleInst *i, NCDValue *list, NCDValue *args)
+static uint64_t list_count (struct instance *o)
+{
+    return IndexedList_Count(&o->il);
+}
+
+static struct elem * insert_value (NCDModuleInst *i, struct instance *o, NCDValRef val, uint64_t idx)
 {
-    ASSERT(NCDValue_Type(list) == NCDVALUE_LIST)
-    ASSERT(NCDValue_Type(args) == NCDVALUE_LIST)
+    ASSERT(idx <= list_count(o))
+    ASSERT(!NCDVal_IsInvalid(val))
     
-    // append contents of list arguments
-    for (NCDValue *arg = NCDValue_ListFirst(args); arg; arg = NCDValue_ListNext(args, arg)) {
-        // check type
-        if (NCDValue_Type(arg) != NCDVALUE_LIST) {
-            ModuleLog(i, BLOG_ERROR, "wrong type");
-            return 0;
+    struct elem *e = malloc(sizeof(*e));
+    if (!e) {
+        ModuleLog(i, BLOG_ERROR, "malloc failed");
+        return NULL;
+    }
+    
+    NCDValMem_Init(&e->mem);
+    
+    e->val = NCDVal_NewCopy(&e->mem, val);
+    if (NCDVal_IsInvalid(e->val)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_NewCopy failed");
+        goto fail1;
+    }
+    
+    IndexedList_InsertAt(&o->il, &e->il_node, idx);
+    
+    return e;
+    
+fail1:
+    NCDValMem_Free(&e->mem);
+    free(e);
+fail0:
+    return NULL;
+}
+
+static void remove_elem (struct instance *o, struct elem *e)
+{
+    IndexedList_Remove(&o->il, &e->il_node);
+    NCDValMem_Free(&e->mem);
+    free(e);
+}
+
+static struct elem * get_elem_at (struct instance *o, uint64_t idx)
+{
+    ASSERT(idx < list_count(o))
+    
+    IndexedListNode *iln = IndexedList_GetAt(&o->il, idx);
+    struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
+    
+    return e;
+}
+
+static struct elem * get_first_elem (struct instance *o)
+{
+    ASSERT(list_count(o) > 0)
+    
+    IndexedListNode *iln = IndexedList_GetFirst(&o->il);
+    struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
+    
+    return e;
+}
+
+static struct elem * get_last_elem (struct instance *o)
+{
+    ASSERT(list_count(o) > 0)
+    
+    IndexedListNode *iln = IndexedList_GetLast(&o->il);
+    struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
+    
+    return e;
+}
+
+static void cut_list_front (struct instance *o, uint64_t count)
+{
+    while (list_count(o) > count) {
+        remove_elem(o, get_first_elem(o));
+    }
+}
+
+static void cut_list_back (struct instance *o, uint64_t count)
+{
+    while (list_count(o) > count) {
+        remove_elem(o, get_last_elem(o));
+    }
+}
+
+static int append_list_contents (NCDModuleInst *i, struct instance *o, NCDValRef args)
+{
+    ASSERT(NCDVal_IsList(args))
+    
+    uint64_t orig_count = list_count(o);
+    
+    size_t append_count = NCDVal_ListCount(args);
+    
+    for (size_t j = 0; j < append_count; j++) {
+        NCDValRef elem = NCDVal_ListGet(args, j);
+        if (!insert_value(i, o, elem, list_count(o))) {
+            goto fail;
         }
+    }
+    
+    return 1;
+    
+fail:
+    cut_list_back(o, orig_count);
+    return 0;
+}
+
+static int append_list_contents_contents (NCDModuleInst *i, struct instance *o, NCDValRef args)
+{
+    ASSERT(NCDVal_IsList(args))
+    
+    uint64_t orig_count = list_count(o);
+    
+    size_t append_count = NCDVal_ListCount(args);
+    
+    for (size_t j = 0; j < append_count; j++) {
+        NCDValRef elem = NCDVal_ListGet(args, j);
         
-        // copy list
-        NCDValue copy;
-        if (!NCDValue_InitCopy(&copy, arg)) {
-            ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
-            return 0;
+        if (!NCDVal_IsList(elem)) {
+            ModuleLog(i, BLOG_ERROR, "wrong type");
+            goto fail;
         }
         
-        // append
-        if (!NCDValue_ListAppendList(list, copy)) {
-            ModuleLog(i, BLOG_ERROR, "NCDValue_ListAppendList failed");
-            NCDValue_Free(&copy);
-            return 0;
+        if (!append_list_contents(i, o, elem)) {
+            goto fail;
         }
     }
     
     return 1;
+    
+fail:
+    cut_list_back(o, orig_count);
+    return 0;
 }
 
-static NCDValue * find_in_list (NCDValue *list, NCDValue *val)
+static struct elem * find_elem (struct instance *o, NCDValRef val, uint64_t start_idx, uint64_t *out_idx)
 {
-    ASSERT(NCDValue_Type(list) == NCDVALUE_LIST)
+    if (start_idx >= list_count(o)) {
+        return NULL;
+    }
     
-    for (NCDValue *e = NCDValue_ListFirst(list); e; e = NCDValue_ListNext(list, e)) {
-        if (NCDValue_Compare(e, val) == 0) {
+    for (IndexedListNode *iln = IndexedList_GetAt(&o->il, start_idx); iln; iln = IndexedList_GetNext(&o->il, iln)) {
+        struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
+        if (NCDVal_Compare(e->val, val) == 0) {
+            if (out_idx) {
+                *out_idx = start_idx;
+            }
             return e;
         }
+        start_idx++;
     }
     
     return NULL;
 }
 
+static int list_to_value (NCDModuleInst *i, struct instance *o, NCDValMem *mem, NCDValRef *out_val)
+{
+    *out_val = NCDVal_NewList(mem, IndexedList_Count(&o->il));
+    if (NCDVal_IsInvalid(*out_val)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_NewList failed");
+        goto fail;
+    }
+    
+    for (IndexedListNode *iln = IndexedList_GetFirst(&o->il); iln; iln = IndexedList_GetNext(&o->il, iln)) {
+        struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
+        
+        NCDValRef copy = NCDVal_NewCopy(mem, e->val);
+        if (NCDVal_IsInvalid(copy)) {
+            ModuleLog(i, BLOG_ERROR, "NCDVal_NewCopy failed");
+            goto fail;
+        }
+        
+        NCDVal_ListAppend(*out_val, copy);
+    }
+    
+    return 1;
+    
+fail:
+    return 0;
+}
+
 static void func_new_list (NCDModuleInst *i)
 {
     // allocate instance
     struct instance *o = malloc(sizeof(*o));
     if (!o) {
-        ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
+        ModuleLog(i, BLOG_ERROR, "malloc failed");
         goto fail0;
     }
+    o->i = i;
     NCDModuleInst_Backend_SetUser(i, o);
     
-    // init arguments
-    o->i = i;
+    // init list
+    IndexedList_Init(&o->il);
     
-    // copy list
-    if (!NCDValue_InitCopy(&o->list, i->args)) {
-        ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
+    // append contents
+    if (!append_list_contents(i, o, i->args)) {
         goto fail1;
     }
     
@@ -193,6 +340,7 @@ static void func_new_list (NCDModuleInst *i)
     return;
     
 fail1:
+    cut_list_front(o, 0);
     free(o);
 fail0:
     NCDModuleInst_Backend_SetError(i);
@@ -204,29 +352,26 @@ static void func_new_listfrom (NCDModuleInst *i)
     // allocate instance
     struct instance *o = malloc(sizeof(*o));
     if (!o) {
-        ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
+        ModuleLog(i, BLOG_ERROR, "malloc failed");
         goto fail0;
     }
-    NCDModuleInst_Backend_SetUser(i, o);
-    
-    // init arguments
     o->i = i;
+    NCDModuleInst_Backend_SetUser(i, o);
     
     // init list
-    NCDValue_InitList(&o->list);
+    IndexedList_Init(&o->il);
     
-    // append contents of list arguments
-    if (!append_list_args(i, &o->list, i->args)) {
-        goto fail2;
+    // append contents contents
+    if (!append_list_contents_contents(i, o, i->args)) {
+        goto fail1;
     }
     
     // signal up
     NCDModuleInst_Backend_Up(o->i);
     return;
     
-fail2:
-    NCDValue_Free(&o->list);
 fail1:
+    cut_list_front(o, 0);
     free(o);
 fail0:
     NCDModuleInst_Backend_SetError(i);
@@ -238,8 +383,8 @@ static void func_die (void *vo)
     struct instance *o = vo;
     NCDModuleInst *i = o->i;
     
-    // free list
-    NCDValue_Free(&o->list);
+    // free list elements
+    cut_list_front(o, 0);
     
     // free instance
     free(o);
@@ -247,13 +392,12 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitCopy(out, &o->list)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
+        if (!list_to_value(o->i, o, mem, out)) {
             return 0;
         }
         
@@ -262,13 +406,12 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
     
     if (!strcmp(name, "length")) {
         char str[64];
-        snprintf(str, sizeof(str), "%zu", NCDValue_ListCount(&o->list));
+        snprintf(str, sizeof(str), "%"PRIu64, list_count(o));
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -278,8 +421,8 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
 static void append_func_new (NCDModuleInst *i)
 {
     // check arguments
-    NCDValue *arg;
-    if (!NCDValue_ListRead(i->args, 1, &arg)) {
+    NCDValRef arg;
+    if (!NCDVal_ListRead(i->args, 1, &arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -288,14 +431,7 @@ static void append_func_new (NCDModuleInst *i)
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
     // append
-    NCDValue v;
-    if (!NCDValue_InitCopy(&v, arg)) {
-        ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail0;
-    }
-    if (!NCDValue_ListAppend(&mo->list, v)) {
-        NCDValue_Free(&v);
-        ModuleLog(i, BLOG_ERROR, "NCDValue_ListAppend failed");
+    if (!insert_value(i, mo, arg, list_count(mo))) {
         goto fail0;
     }
     
@@ -311,12 +447,12 @@ fail0:
 static void appendv_func_new (NCDModuleInst *i)
 {
     // check arguments
-    NCDValue *arg;
-    if (!NCDValue_ListRead(i->args, 1, &arg)) {
+    NCDValRef arg;
+    if (!NCDVal_ListRead(i->args, 1, &arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (NCDValue_Type(arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsList(arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
@@ -325,14 +461,7 @@ static void appendv_func_new (NCDModuleInst *i)
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
     // append
-    NCDValue l;
-    if (!NCDValue_InitCopy(&l, arg)) {
-        ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail0;
-    }
-    if (!NCDValue_ListAppendList(&mo->list, l)) {
-        ModuleLog(i, BLOG_ERROR, "NCDValue_ListAppendList failed");
-        NCDValue_Free(&l);
+    if (!append_list_contents(i, mo, arg)) {
         goto fail0;
     }
     
@@ -359,7 +488,7 @@ static void length_func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    if (!NCDValue_ListRead(o->i->args, 0)) {
+    if (!NCDVal_ListRead(o->i->args, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
@@ -368,7 +497,7 @@ static void length_func_new (NCDModuleInst *i)
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
     // remember length
-    o->length = NCDValue_ListCount(&mo->list);
+    o->length = list_count(mo);
     
     // signal up
     NCDModuleInst_Backend_Up(o->i);
@@ -393,19 +522,18 @@ static void length_func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int length_func_getvar (void *vo, const char *name, NCDValue *out)
+static int length_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct length_instance *o = vo;
     
     if (!strcmp(name, "")) {
         char str[64];
-        snprintf(str, sizeof(str), "%zu", o->length);
+        snprintf(str, sizeof(str), "%"PRIu64, o->length);
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -426,17 +554,17 @@ static void get_func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    NCDValue *index_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &index_arg)) {
+    NCDValRef index_arg;
+    if (!NCDVal_ListRead(o->i->args, 1, &index_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(index_arg)) {
+    if (!NCDVal_IsStringNoNulls(index_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     uintmax_t index;
-    if (!parse_unsigned_integer(NCDValue_StringValue(index_arg), &index)) {
+    if (!parse_unsigned_integer(NCDVal_StringValue(index_arg), &index)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong value");
         goto fail1;
     }
@@ -445,22 +573,30 @@ static void get_func_new (NCDModuleInst *i)
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
     // check index
-    if (index >= NCDValue_ListCount(&mo->list)) {
+    if (index >= list_count(mo)) {
         ModuleLog(o->i, BLOG_ERROR, "no element at index %"PRIuMAX, index);
         goto fail1;
     }
     
+    // get element
+    struct elem *e = get_elem_at(mo, index);
+    
+    // init mem
+    NCDValMem_Init(&o->mem);
+    
     // copy value
-    if (!NCDValue_InitCopy(&o->value, NCDValue_ListGet(&mo->list, index))) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail1;
+    o->val = NCDVal_NewCopy(&o->mem, e->val);
+    if (NCDVal_IsInvalid(o->val)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
+        goto fail2;
     }
     
     // signal up
     NCDModuleInst_Backend_Up(o->i);
-    
     return;
     
+fail2:
+    NCDValMem_Free(&o->mem);
 fail1:
     free(o);
 fail0:
@@ -473,8 +609,8 @@ static void get_func_die (void *vo)
     struct get_instance *o = vo;
     NCDModuleInst *i = o->i;
     
-    // free value
-    NCDValue_Free(&o->value);
+    // free mem
+    NCDValMem_Free(&o->mem);
     
     // free instance
     free(o);
@@ -482,16 +618,15 @@ static void get_func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int get_func_getvar (void *vo, const char *name, NCDValue *out)
+static int get_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct get_instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitCopy(out, &o->value)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-            return 0;
+        *out = NCDVal_NewCopy(mem, o->val);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
         }
-        
         return 1;
     }
     
@@ -501,7 +636,7 @@ static int get_func_getvar (void *vo, const char *name, NCDValue *out)
 static void shift_func_new (NCDModuleInst *i)
 {
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -509,13 +644,14 @@ static void shift_func_new (NCDModuleInst *i)
     // get method object
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
-    // shift
-    if (!NCDValue_ListFirst(&mo->list)) {
+    // check first
+    if (list_count(mo) == 0) {
         ModuleLog(i, BLOG_ERROR, "list has no elements");
         goto fail0;
     }
-    NCDValue v = NCDValue_ListShift(&mo->list);
-    NCDValue_Free(&v);
+    
+    // remove first
+    remove_elem(mo, get_first_elem(mo));
     
     // signal up
     NCDModuleInst_Backend_Up(i);
@@ -540,8 +676,8 @@ static void contains_func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *value_arg;
-    if (!NCDValue_ListRead(i->args, 1, &value_arg)) {
+    NCDValRef value_arg;
+    if (!NCDVal_ListRead(i->args, 1, &value_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
@@ -550,13 +686,7 @@ static void contains_func_new (NCDModuleInst *i)
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
     // search
-    o->contains = 0;
-    for (NCDValue *v = NCDValue_ListFirst(&mo->list); v; v = NCDValue_ListNext(&mo->list, v)) {
-        if (NCDValue_Compare(v, value_arg) == 0) {
-            o->contains = 1;
-            break;
-        }
-    }
+    o->contains = !!find_elem(mo, value_arg, 0, NULL);
     
     // signal up
     NCDModuleInst_Backend_Up(o->i);
@@ -580,18 +710,17 @@ static void contains_func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int contains_func_getvar (void *vo, const char *name, NCDValue *out)
+static int contains_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct contains_instance *o = vo;
     
     if (!strcmp(name, "")) {
         const char *value = (o->contains ? "true" : "false");
         
-        if (!NCDValue_InitString(out, value)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, value);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -612,20 +741,20 @@ static void find_func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *start_pos_arg;
-    NCDValue *value_arg;
-    if (!NCDValue_ListRead(i->args, 2, &start_pos_arg, &value_arg)) {
+    NCDValRef start_pos_arg;
+    NCDValRef value_arg;
+    if (!NCDVal_ListRead(i->args, 2, &start_pos_arg, &value_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(start_pos_arg)) {
+    if (!NCDVal_IsStringNoNulls(start_pos_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
     // read start position
     uintmax_t start_pos;
-    if (!parse_unsigned_integer(NCDValue_StringValue(start_pos_arg), &start_pos)) {
+    if (!parse_unsigned_integer(NCDVal_StringValue(start_pos_arg), &start_pos) || start_pos > UINT64_MAX) {
         ModuleLog(o->i, BLOG_ERROR, "wrong start pos");
         goto fail1;
     }
@@ -633,17 +762,8 @@ static void find_func_new (NCDModuleInst *i)
     // get method object
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
-    // search
-    o->is_found = 0;
-    size_t pos = 0;
-    for (NCDValue *v = NCDValue_ListFirst(&mo->list); v; v = NCDValue_ListNext(&mo->list, v)) {
-        if (pos >= start_pos && NCDValue_Compare(v, value_arg) == 0) {
-            o->is_found = 1;
-            o->found_pos = pos;
-            break;
-        }
-        pos++;
-    }
+    // find
+    o->is_found = !!find_elem(mo, value_arg, start_pos, &o->found_pos);
     
     // signal up
     NCDModuleInst_Backend_Up(o->i);
@@ -667,7 +787,7 @@ static void find_func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int find_func_getvar (void *vo, const char *name, NCDValue *out)
+static int find_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct find_instance *o = vo;
     
@@ -675,27 +795,25 @@ static int find_func_getvar (void *vo, const char *name, NCDValue *out)
         char value[64];
         
         if (o->is_found) {
-            snprintf(value, sizeof(value), "%zu", o->found_pos);
+            snprintf(value, sizeof(value), "%"PRIu64, o->found_pos);
         } else {
             snprintf(value, sizeof(value), "none");
         }
         
-        if (!NCDValue_InitString(out, value)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, value);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
     if (!strcmp(name, "found")) {
         const char *value = (o->is_found ? "true" : "false");
         
-        if (!NCDValue_InitString(out, value)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, value);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -705,19 +823,19 @@ static int find_func_getvar (void *vo, const char *name, NCDValue *out)
 static void removeat_func_new (NCDModuleInst *i)
 {
     // read arguments
-    NCDValue *remove_pos_arg;
-    if (!NCDValue_ListRead(i->args, 1, &remove_pos_arg)) {
+    NCDValRef remove_pos_arg;
+    if (!NCDVal_ListRead(i->args, 1, &remove_pos_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(remove_pos_arg)) {
+    if (!NCDVal_IsStringNoNulls(remove_pos_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     // read position
     uintmax_t remove_pos;
-    if (!parse_unsigned_integer(NCDValue_StringValue(remove_pos_arg), &remove_pos)) {
+    if (!parse_unsigned_integer(NCDVal_StringValue(remove_pos_arg), &remove_pos)) {
         ModuleLog(i, BLOG_ERROR, "wrong pos");
         goto fail0;
     }
@@ -726,21 +844,13 @@ static void removeat_func_new (NCDModuleInst *i)
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
     // check position
-    if (remove_pos >= NCDValue_ListCount(&mo->list)) {
+    if (remove_pos >= list_count(mo)) {
         ModuleLog(i, BLOG_ERROR, "pos out of range");
         goto fail0;
     }
     
-    // find and remove
-    size_t pos = 0;
-    for (NCDValue *v = NCDValue_ListFirst(&mo->list); v; v = NCDValue_ListNext(&mo->list, v)) {
-        if (pos == remove_pos) {
-            NCDValue removed_v = NCDValue_ListRemove(&mo->list, v);
-            NCDValue_Free(&removed_v);
-            break;
-        }
-        pos++;
-    }
+    // remove
+    remove_elem(mo, get_elem_at(mo, remove_pos));
     
     // signal up
     NCDModuleInst_Backend_Up(i);
@@ -754,8 +864,8 @@ fail0:
 static void remove_func_new (NCDModuleInst *i)
 {
     // read arguments
-    NCDValue *value_arg;
-    if (!NCDValue_ListRead(i->args, 1, &value_arg)) {
+    NCDValRef value_arg;
+    if (!NCDVal_ListRead(i->args, 1, &value_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -763,16 +873,15 @@ static void remove_func_new (NCDModuleInst *i)
     // get method object
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
-    // find value
-    NCDValue *e = find_in_list(&mo->list, value_arg);
+    // find element
+    struct elem *e = find_elem(mo, value_arg, 0, NULL);
     if (!e) {
         ModuleLog(i, BLOG_ERROR, "value does not exist");
         goto fail0;
     }
     
-    // remove it
-    NCDValue removed_v = NCDValue_ListRemove(&mo->list, e);
-    NCDValue_Free(&removed_v);
+    // remove element
+    remove_elem(mo, e);
     
     // signal up
     NCDModuleInst_Backend_Up(i);
@@ -785,28 +894,24 @@ fail0:
 
 static void set_func_new (NCDModuleInst *i)
 {
-    // init list
-    NCDValue list;
-    NCDValue_InitList(&list);
-    
-    // append to list
-    if (!append_list_args(i, &list, i->args)) {
-        goto fail1;
-    }
-    
     // get method object
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
-    // replace list
-    NCDValue_Free(&mo->list);
-    mo->list = list;
+    // remember old count
+    uint64_t old_count = list_count(mo);
+    
+    // append contents of our lists
+    if (!append_list_contents_contents(i, mo, i->args)) {
+        goto fail0;
+    }
+    
+    // remove old elements
+    cut_list_front(mo, list_count(mo) - old_count);
     
     // signal up
     NCDModuleInst_Backend_Up(i);
     return;
     
-fail1:
-    NCDValue_Free(&list);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);

+ 19 - 19
ncd/modules/logical.c

@@ -57,7 +57,7 @@ struct instance {
     int value;
 };
 
-static void func_new (NCDModuleInst *i, int not, int or)
+static void func_new (NCDModuleInst *i, int is_not, int is_or)
 {
     // allocate instance
     struct instance *o = malloc(sizeof(*o));
@@ -71,36 +71,37 @@ static void func_new (NCDModuleInst *i, int not, int or)
     o->i = i;
     
     // compute value from arguments
-    if (not) {
-        NCDValue *arg;
-        if (!NCDValue_ListRead(o->i->args, 1, &arg)) {
+    if (is_not) {
+        NCDValRef arg;
+        if (!NCDVal_ListRead(i->args, 1, &arg)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong arity");
             goto fail1;
         }
-        if (NCDValue_Type(arg) != NCDVALUE_STRING) {
+        if (!NCDVal_IsString(arg)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong type");
             goto fail1;
         }
         
-        o->value = !NCDValue_StringEquals(arg, "true");
+        o->value = !NCDVal_StringEquals(arg, "true");
     } else {
-        o->value = (or ? 0 : 1);
+        o->value = (is_or ? 0 : 1);
         
-        NCDValue *arg = NCDValue_ListFirst(o->i->args);
-        while (arg) {
-            if (NCDValue_Type(arg) != NCDVALUE_STRING) {
+        size_t count = NCDVal_ListCount(i->args);
+        
+        for (size_t j = 0; j < count; j++) {
+            NCDValRef arg = NCDVal_ListGet(i->args, j);
+            
+            if (!NCDVal_IsString(arg)) {
                 ModuleLog(o->i, BLOG_ERROR, "wrong type");
                 goto fail1;
             }
             
-            int this_value = NCDValue_StringEquals(arg, "true");
-            if (or) {
+            int this_value = NCDVal_StringEquals(arg, "true");
+            if (is_or) {
                 o->value = o->value || this_value;
             } else {
                 o->value = o->value && this_value;
             }
-            
-            arg = NCDValue_ListNext(o->i->args, arg);
         }
     }
     
@@ -142,18 +143,17 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
         const char *v = (o->value ? "true" : "false");
         
-        if (!NCDValue_InitString(out, v)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, v);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     

+ 18 - 17
ncd/modules/multidepend.c

@@ -58,7 +58,7 @@
 
 struct provide {
     NCDModuleInst *i;
-    char *name;
+    const char *name;
     LinkedList2Node provides_node;
     LinkedList2 depends;
     int dying;
@@ -66,7 +66,7 @@ struct provide {
 
 struct depend {
     NCDModuleInst *i;
-    NCDValue *names;
+    NCDValRef names;
     LinkedList2Node depends_node;
     struct provide *provide;
     LinkedList2Node provide_node;
@@ -94,13 +94,14 @@ static struct provide * find_provide (const char *name)
 
 static struct provide * depend_find_best_provide (struct depend *o)
 {
-    NCDValue *e = NCDValue_ListFirst(o->names);
-    while (e) {
-        struct provide *p = find_provide(NCDValue_StringValue(e));
+    size_t count = NCDVal_ListCount(o->names);
+    
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef e = NCDVal_ListGet(o->names, j);
+        struct provide *p = find_provide(NCDVal_StringValue(e));
         if (p && !p->dying) {
             return p;
         }
-        e = NCDValue_ListNext(o->names, e);
     }
     
     return NULL;
@@ -168,16 +169,16 @@ static void provide_func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *name_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &name_arg)) {
+    NCDValRef name_arg;
+    if (!NCDVal_ListRead(o->i->args, 1, &name_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsStringNoNulls(name_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->name = NCDValue_StringValue(name_arg);
+    o->name = NCDVal_StringValue(name_arg);
     
     // check for existing provide with this name
     if (find_provide(o->name)) {
@@ -272,25 +273,25 @@ static void depend_func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *names_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &names_arg)) {
+    NCDValRef names_arg;
+    if (!NCDVal_ListRead(o->i->args, 1, &names_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (NCDValue_Type(names_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsList(names_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     o->names = names_arg;
     
     // check names list
-    NCDValue *e = NCDValue_ListFirst(o->names);
-    while (e) {
-        if (!NCDValue_IsStringNoNulls(e)) {
+    size_t count = NCDVal_ListCount(o->names);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef e = NCDVal_ListGet(o->names, j);
+        if (!NCDVal_IsStringNoNulls(e)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong type");
             goto fail1;
         }
-        e = NCDValue_ListNext(o->names, e);
     }
     
     // insert to depends list

+ 22 - 23
ncd/modules/net_backend_badvpn.c

@@ -48,10 +48,10 @@
 
 struct instance {
     NCDModuleInst *i;
-    char *ifname;
-    char *user;
-    char *exec;
-    NCDValue *args;
+    const char *ifname;
+    const char *user;
+    const char *exec;
+    NCDValRef args;
     int dying;
     int started;
     BTimer timer;
@@ -81,13 +81,12 @@ void try_process (struct instance *o)
     }
     
     // append arguments
-    NCDValue *arg = NCDValue_ListFirst(o->args);
-    while (arg) {
-        // append argument
-        if (!CmdLine_Append(&c, NCDValue_StringValue(arg))) {
+    size_t count = NCDVal_ListCount(o->args);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef arg = NCDVal_ListGet(o->args, j);
+        if (!CmdLine_Append(&c, NCDVal_StringValue(arg))) {
             goto fail1;
         }
-        arg = NCDValue_ListNext(o->args, arg);
     }
     
     // terminate cmdline
@@ -161,32 +160,32 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *ifname_arg;
-    NCDValue *user_arg;
-    NCDValue *exec_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(o->i->args, 4, &ifname_arg, &user_arg, &exec_arg, &args_arg)) {
+    NCDValRef ifname_arg;
+    NCDValRef user_arg;
+    NCDValRef exec_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(o->i->args, 4, &ifname_arg, &user_arg, &exec_arg, &args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(ifname_arg) || !NCDValue_IsStringNoNulls(user_arg) ||
-        !NCDValue_IsStringNoNulls(exec_arg) || NCDValue_Type(args_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsStringNoNulls(ifname_arg) || !NCDVal_IsStringNoNulls(user_arg) ||
+        !NCDVal_IsStringNoNulls(exec_arg) || !NCDVal_IsList(args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->ifname = NCDValue_StringValue(ifname_arg);
-    o->user = NCDValue_StringValue(user_arg);
-    o->exec = NCDValue_StringValue(exec_arg);
+    o->ifname = NCDVal_StringValue(ifname_arg);
+    o->user = NCDVal_StringValue(user_arg);
+    o->exec = NCDVal_StringValue(exec_arg);
     o->args = args_arg;
     
     // check arguments
-    NCDValue *arg = NCDValue_ListFirst(o->args);
-    while (arg) {
-        if (!NCDValue_IsStringNoNulls(arg)) {
+    size_t count = NCDVal_ListCount(o->args);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef arg = NCDVal_ListGet(o->args, j);
+        if (!NCDVal_IsStringNoNulls(arg)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong type");
             goto fail1;
         }
-        arg = NCDValue_ListNext(o->args, arg);
     }
     
     // create TAP device

+ 6 - 6
ncd/modules/net_backend_rfkill.c

@@ -144,18 +144,18 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    NCDValue *type_arg;
-    NCDValue *name_arg;
-    if (!NCDValue_ListRead(i->args, 2, &type_arg, &name_arg)) {
+    NCDValRef type_arg;
+    NCDValRef name_arg;
+    if (!NCDVal_ListRead(i->args, 2, &type_arg, &name_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(type_arg) || !NCDValue_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsStringNoNulls(type_arg) || !NCDVal_IsStringNoNulls(name_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    char *type = NCDValue_StringValue(type_arg);
-    char *name = NCDValue_StringValue(name_arg);
+    const char *type = NCDVal_StringValue(type_arg);
+    const char *name = NCDVal_StringValue(name_arg);
     
     if (!strcmp(type, "index")) {
         if (sscanf(name, "%"SCNu32, &o->index) != 1) {

+ 4 - 4
ncd/modules/net_backend_waitdevice.c

@@ -129,16 +129,16 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    NCDValue *arg;
-    if (!NCDValue_ListRead(i->args, 1, &arg)) {
+    NCDValRef arg;
+    if (!NCDVal_ListRead(i->args, 1, &arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(arg)) {
+    if (!NCDVal_IsStringNoNulls(arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->ifname = NCDValue_StringValue(arg);
+    o->ifname = NCDVal_StringValue(arg);
     
     // init client
     NCDUdevClient_Init(&o->client, o->i->iparams->umanager, o, (NCDUdevClient_handler)client_handler);

+ 4 - 4
ncd/modules/net_backend_waitlink.c

@@ -88,16 +88,16 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // check arguments
-    NCDValue *arg;
-    if (!NCDValue_ListRead(i->args, 1, &arg)) {
+    NCDValRef arg;
+    if (!NCDVal_ListRead(i->args, 1, &arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(arg)) {
+    if (!NCDVal_IsStringNoNulls(arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    char *ifname = NCDValue_StringValue(arg);
+    const char *ifname = NCDVal_StringValue(arg);
     
     // get interface index
     int ifindex;

+ 27 - 29
ncd/modules/net_backend_wpa_supplicant.c

@@ -68,10 +68,10 @@
 
 struct instance {
     NCDModuleInst *i;
-    char *ifname;
-    char *conf;
-    char *exec;
-    NCDValue *args;
+    const char *ifname;
+    const char *conf;
+    const char *exec;
+    NCDValRef args;
     int dying;
     int up;
     BInputProcess process;
@@ -216,19 +216,19 @@ int build_cmdline (struct instance *o, CmdLine *c)
     }
     
     // append user arguments
-    NCDValue *arg = NCDValue_ListFirst(o->args);
-    while (arg) {
-        if (!NCDValue_IsStringNoNulls(arg)) {
+    size_t count = NCDVal_ListCount(o->args);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef arg = NCDVal_ListGet(o->args, j);
+        
+        if (!NCDVal_IsStringNoNulls(arg)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong type");
             goto fail1;
         }
         
         // append argument
-        if (!CmdLine_Append(c, NCDValue_StringValue(arg))) {
+        if (!CmdLine_Append(c, NCDVal_StringValue(arg))) {
             goto fail1;
         }
-        
-        arg = NCDValue_ListNext(o->args, arg);
     }
     
     // append interface name
@@ -411,22 +411,22 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *ifname_arg;
-    NCDValue *conf_arg;
-    NCDValue *exec_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(o->i->args, 4, &ifname_arg, &conf_arg, &exec_arg, &args_arg)) {
+    NCDValRef ifname_arg;
+    NCDValRef conf_arg;
+    NCDValRef exec_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(o->i->args, 4, &ifname_arg, &conf_arg, &exec_arg, &args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(ifname_arg) || !NCDValue_IsStringNoNulls(conf_arg)  ||
-        !NCDValue_IsStringNoNulls(exec_arg) || NCDValue_Type(args_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsStringNoNulls(ifname_arg) || !NCDVal_IsStringNoNulls(conf_arg)  ||
+        !NCDVal_IsStringNoNulls(exec_arg) || !NCDVal_IsList(args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->ifname = NCDValue_StringValue(ifname_arg);
-    o->conf = NCDValue_StringValue(conf_arg);
-    o->exec = NCDValue_StringValue(exec_arg);
+    o->ifname = NCDVal_StringValue(ifname_arg);
+    o->conf = NCDVal_StringValue(conf_arg);
+    o->exec = NCDVal_StringValue(exec_arg);
     o->args = args_arg;
     
     // set not dying
@@ -528,7 +528,7 @@ static void func_die (void *vo)
     o->dying = 1;
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     ASSERT(o->up)
@@ -544,20 +544,18 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
             sprintf(str, "%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8, id[0], id[1], id[2], id[3], id[4], id[5]);
         }
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
     if (!strcmp(name, "ssid")) {
-        if (!NCDValue_InitString(out, o->info_ssid)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, o->info_ssid);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     

+ 11 - 11
ncd/modules/net_dns.c

@@ -220,29 +220,31 @@ static void func_new (NCDModuleInst *i)
     LinkedList2_Init(&o->ipv4_dns_servers);
     
     // get arguments
-    NCDValue *servers_arg;
-    NCDValue *priority_arg;
-    if (!NCDValue_ListRead(o->i->args, 2, &servers_arg, &priority_arg)) {
+    NCDValRef servers_arg;
+    NCDValRef priority_arg;
+    if (!NCDVal_ListRead(o->i->args, 2, &servers_arg, &priority_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (NCDValue_Type(servers_arg) != NCDVALUE_LIST || !NCDValue_IsStringNoNulls(priority_arg)) {
+    if (!NCDVal_IsList(servers_arg) || !NCDVal_IsStringNoNulls(priority_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
-    int priority = atoi(NCDValue_StringValue(priority_arg));
+    int priority = atoi(NCDVal_StringValue(priority_arg));
     
     // read servers
-    NCDValue *server_arg = NCDValue_ListFirst(servers_arg);
-    while (server_arg) {
-        if (NCDValue_Type(server_arg) != NCDVALUE_STRING) {
+    size_t count = NCDVal_ListCount(servers_arg);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef server_arg = NCDVal_ListGet(servers_arg, j);
+        
+        if (!NCDVal_IsStringNoNulls(server_arg)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong type");
             goto fail1;
         }
         
         uint32_t addr;
-        if (!ipaddr_parse_ipv4_addr(NCDValue_StringValue(server_arg), &addr)) {
+        if (!ipaddr_parse_ipv4_addr((char *)NCDVal_StringValue(server_arg), &addr)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong addr");
             goto fail1;
         }
@@ -251,8 +253,6 @@ static void func_new (NCDModuleInst *i)
             ModuleLog(o->i, BLOG_ERROR, "failed to add dns entry");
             goto fail1;
         }
-        
-        server_arg = NCDValue_ListNext(servers_arg, server_arg);
     }
     
     // add to instances

+ 29 - 29
ncd/modules/net_iptables.c

@@ -139,18 +139,18 @@ static void unlock_free (struct unlock_instance *o);
 static int build_append_cmdline (NCDModuleInst *i, const char *prog, int remove, char **exec, CmdLine *cl)
 {
     // read arguments
-    NCDValue *table_arg;
-    NCDValue *chain_arg;
-    if (!NCDValue_ListReadHead(i->args, 2, &table_arg, &chain_arg)) {
+    NCDValRef table_arg;
+    NCDValRef chain_arg;
+    if (!NCDVal_ListReadHead(i->args, 2, &table_arg, &chain_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(table_arg) || !NCDValue_IsStringNoNulls(chain_arg)) {
+    if (!NCDVal_IsStringNoNulls(table_arg) || !NCDVal_IsStringNoNulls(chain_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    char *table = NCDValue_StringValue(table_arg);
-    char *chain = NCDValue_StringValue(chain_arg);
+    const char *table = NCDVal_StringValue(table_arg);
+    const char *chain = NCDVal_StringValue(chain_arg);
     
     // find program
     if (!(*exec = badvpn_find_program(prog))) {
@@ -171,19 +171,19 @@ static int build_append_cmdline (NCDModuleInst *i, const char *prog, int remove,
     }
     
     // add additional arguments
-    NCDValue *arg = NCDValue_ListNext(i->args, chain_arg);
-    while (arg) {
-        if (!NCDValue_IsStringNoNulls(arg)) {
+    size_t count = NCDVal_ListCount(i->args);
+    for (size_t j = 2; j < count; j++) {
+        NCDValRef arg = NCDVal_ListGet(i->args, j);
+        
+        if (!NCDVal_IsStringNoNulls(arg)) {
             ModuleLog(i, BLOG_ERROR, "wrong type");
             goto fail2;
         }
         
-        if (!CmdLine_Append(cl, NCDValue_StringValue(arg))) {
+        if (!CmdLine_Append(cl, NCDVal_StringValue(arg))) {
             ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
             goto fail2;
         }
-        
-        arg = NCDValue_ListNext(i->args, arg);
     }
     
     // finish
@@ -205,24 +205,24 @@ fail0:
 static int build_policy_cmdline (NCDModuleInst *i, const char *prog, int remove, char **exec, CmdLine *cl)
 {
     // read arguments
-    NCDValue *table_arg;
-    NCDValue *chain_arg;
-    NCDValue *target_arg;
-    NCDValue *revert_target_arg;
-    if (!NCDValue_ListRead(i->args, 4, &table_arg, &chain_arg, &target_arg, &revert_target_arg)) {
+    NCDValRef table_arg;
+    NCDValRef chain_arg;
+    NCDValRef target_arg;
+    NCDValRef revert_target_arg;
+    if (!NCDVal_ListRead(i->args, 4, &table_arg, &chain_arg, &target_arg, &revert_target_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(table_arg) || !NCDValue_IsStringNoNulls(chain_arg) ||
-        !NCDValue_IsStringNoNulls(target_arg) || !NCDValue_IsStringNoNulls(revert_target_arg)
+    if (!NCDVal_IsStringNoNulls(table_arg) || !NCDVal_IsStringNoNulls(chain_arg) ||
+        !NCDVal_IsStringNoNulls(target_arg) || !NCDVal_IsStringNoNulls(revert_target_arg)
     ) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    char *table = NCDValue_StringValue(table_arg);
-    char *chain = NCDValue_StringValue(chain_arg);
-    char *target = NCDValue_StringValue(target_arg);
-    char *revert_target = NCDValue_StringValue(revert_target_arg);
+    const char *table = NCDVal_StringValue(table_arg);
+    const char *chain = NCDVal_StringValue(chain_arg);
+    const char *target = NCDVal_StringValue(target_arg);
+    const char *revert_target = NCDVal_StringValue(revert_target_arg);
     
     // find program
     if (!(*exec = badvpn_find_program(prog))) {
@@ -262,18 +262,18 @@ fail0:
 static int build_newchain_cmdline (NCDModuleInst *i, const char *prog, int remove, char **exec, CmdLine *cl)
 {
     // read arguments
-    NCDValue *table_arg = NULL;
-    NCDValue *chain_arg;
-    if (!NCDValue_ListRead(i->args, 1, &chain_arg) && !NCDValue_ListRead(i->args, 2, &table_arg, &chain_arg)) {
+    NCDValRef table_arg = NCDVal_NewInvalid();
+    NCDValRef chain_arg;
+    if (!NCDVal_ListRead(i->args, 1, &chain_arg) && !NCDVal_ListRead(i->args, 2, &table_arg, &chain_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if ((table_arg && !NCDValue_IsStringNoNulls(table_arg)) || !NCDValue_IsStringNoNulls(chain_arg)) {
+    if ((!NCDVal_IsInvalid(table_arg) && !NCDVal_IsStringNoNulls(table_arg)) || !NCDVal_IsStringNoNulls(chain_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    char *table = (!table_arg ? "filter" : NCDValue_StringValue(table_arg));
-    char *chain = NCDValue_StringValue(chain_arg);
+    const char *table = (NCDVal_IsInvalid(table_arg) ? "filter" : NCDVal_StringValue(table_arg));
+    const char *chain = NCDVal_StringValue(chain_arg);
     
     // find program
     if (!(*exec = badvpn_find_program(prog))) {

+ 8 - 8
ncd/modules/net_ipv4_addr.c

@@ -63,23 +63,23 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *ifname_arg;
-    NCDValue *addr_arg;
-    NCDValue *prefix_arg;
-    if (!NCDValue_ListRead(o->i->args, 3, &ifname_arg, &addr_arg, &prefix_arg)) {
+    NCDValRef ifname_arg;
+    NCDValRef addr_arg;
+    NCDValRef prefix_arg;
+    if (!NCDVal_ListRead(o->i->args, 3, &ifname_arg, &addr_arg, &prefix_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(ifname_arg) || !NCDValue_IsStringNoNulls(addr_arg) || !NCDValue_IsStringNoNulls(prefix_arg)) {
+    if (!NCDVal_IsStringNoNulls(ifname_arg) || !NCDVal_IsStringNoNulls(addr_arg) || !NCDVal_IsStringNoNulls(prefix_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->ifname = NCDValue_StringValue(ifname_arg);
-    if (!ipaddr_parse_ipv4_addr(NCDValue_StringValue(addr_arg), &o->ifaddr.addr)) {
+    o->ifname = NCDVal_StringValue(ifname_arg);
+    if (!ipaddr_parse_ipv4_addr((char *)NCDVal_StringValue(addr_arg), &o->ifaddr.addr)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong address");
         goto fail1;
     }
-    if (!ipaddr_parse_ipv4_prefix(NCDValue_StringValue(prefix_arg), &o->ifaddr.prefix)) {
+    if (!ipaddr_parse_ipv4_prefix((char *)NCDVal_StringValue(prefix_arg), &o->ifaddr.prefix)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong prefix");
         goto fail1;
     }

+ 11 - 12
ncd/modules/net_ipv4_arp_probe.c

@@ -132,22 +132,22 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *arg_ifname;
-    NCDValue *arg_addr;
-    if (!NCDValue_ListRead(i->args, 2, &arg_ifname, &arg_addr)) {
+    NCDValRef arg_ifname;
+    NCDValRef arg_addr;
+    if (!NCDVal_ListRead(i->args, 2, &arg_ifname, &arg_addr)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(arg_ifname) || !NCDValue_IsStringNoNulls(arg_addr)) {
+    if (!NCDVal_IsStringNoNulls(arg_ifname) || !NCDVal_IsStringNoNulls(arg_addr)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    char *ifname = NCDValue_StringValue(arg_ifname);
-    char *addr_str = NCDValue_StringValue(arg_addr);
+    const char *ifname = NCDVal_StringValue(arg_ifname);
+    const char *addr_str = NCDVal_StringValue(arg_addr);
     
     // parse address
     uint32_t addr;
-    if (!ipaddr_parse_ipv4_addr(addr_str, &addr)) {
+    if (!ipaddr_parse_ipv4_addr((char *)addr_str, &addr)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong address");
         goto fail1;
     }
@@ -189,7 +189,7 @@ static void func_die (void *vo)
     instance_free(o);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     ASSERT(o->state == STATE_EXIST || o->state == STATE_NOEXIST)
@@ -197,11 +197,10 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
     if (!strcmp(name, "exists")) {
         const char *str = (o->state == STATE_EXIST ? "true" : "false");
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     

+ 43 - 46
ncd/modules/net_ipv4_dhcp.c

@@ -109,41 +109,44 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    NCDValue *ifname_arg;
-    NCDValue *opts_arg = NULL;
-    if (!NCDValue_ListRead(i->args, 1, &ifname_arg) && !NCDValue_ListRead(i->args, 2, &ifname_arg, &opts_arg)) {
+    NCDValRef ifname_arg;
+    NCDValRef opts_arg = NCDVal_NewInvalid();
+    if (!NCDVal_ListRead(i->args, 1, &ifname_arg) && !NCDVal_ListRead(i->args, 2, &ifname_arg, &opts_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(ifname_arg) || (opts_arg && NCDValue_Type(opts_arg) != NCDVALUE_LIST)) {
+    if (!NCDVal_IsStringNoNulls(ifname_arg) || (!NCDVal_IsInvalid(opts_arg) && !NCDVal_IsList(opts_arg))) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    char *ifname = NCDValue_StringValue(ifname_arg);
+    const char *ifname = NCDVal_StringValue(ifname_arg);
     
     struct BDHCPClient_opts opts = {};
     
     // read options
-    for (NCDValue *opt = (opts_arg ? NCDValue_ListFirst(opts_arg) : NULL); opt; opt = NCDValue_ListNext(opts_arg, opt)) {
+    size_t count = NCDVal_IsInvalid(opts_arg) ? 0 : NCDVal_ListCount(opts_arg);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef opt = NCDVal_ListGet(opts_arg, j);
+        
         // read name
-        if (!NCDValue_IsStringNoNulls(opt)) {
+        if (!NCDVal_IsStringNoNulls(opt)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong option name type");
             goto fail1;
         }
-        char *optname = NCDValue_StringValue(opt);
+        const char *optname = NCDVal_StringValue(opt);
         
         if (!strcmp(optname, "hostname") || !strcmp(optname, "vendorclassid")) {
             // read value
-            NCDValue *val = NCDValue_ListNext(opts_arg, opt);
-            if (!val) {
+            if (j == count) {
                 ModuleLog(o->i, BLOG_ERROR, "option value missing");
                 goto fail1;
             }
-            if (!NCDValue_IsStringNoNulls(val)) {
+            NCDValRef val = NCDVal_ListGet(opts_arg, j + 1);
+            if (!NCDVal_IsStringNoNulls(val)) {
                 ModuleLog(o->i, BLOG_ERROR, "wrong option value type");
                 goto fail1;
             }
-            char *optval = NCDValue_StringValue(val);
+            const char *optval = NCDVal_StringValue(val);
             
             if (!strcmp(optname, "hostname")) {
                 opts.hostname = optval;
@@ -151,7 +154,7 @@ static void func_new (NCDModuleInst *i)
                 opts.vendorclassid = optval;
             }
             
-            opt = val;
+            j++;
         }
         else if (!strcmp(optname, "auto_clientid")) {
             opts.auto_clientid = 1;
@@ -200,7 +203,7 @@ static void func_die (void *vo)
     instance_free(o);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     ASSERT(o->up)
@@ -213,11 +216,10 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
         char str[50];
         sprintf(str, "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, b[0], b[1], b[2], b[3]);
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -236,11 +238,10 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
         char str[10];
         sprintf(str, "%d", ifaddr.prefix);
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -255,11 +256,10 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
             sprintf(str, "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, b[0], b[1], b[2], b[3]);
         }
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -267,33 +267,27 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
         uint32_t servers[BDHCPCLIENT_MAX_DOMAIN_NAME_SERVERS];
         int num_servers = BDHCPClient_GetDNS(&o->dhcp, servers, BDHCPCLIENT_MAX_DOMAIN_NAME_SERVERS);
         
-        NCDValue list;
-        NCDValue_InitList(&list);
+        *out = NCDVal_NewList(mem, num_servers);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewList failed");
+            goto fail;
+        }
         
         for (int i = 0; i < num_servers; i++) {
             uint8_t *b = (uint8_t *)&servers[i];
             char str[50];
             sprintf(str, "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, b[0], b[1], b[2], b[3]);
             
-            NCDValue server;
-            if (!NCDValue_InitString(&server, str)) {
-                ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-                goto fail1;
+            NCDValRef server = NCDVal_NewString(mem, str);
+            if (NCDVal_IsInvalid(server)) {
+                ModuleLog(o->i, BLOG_ERROR, "NCDVal_IsInvalid failed");
+                goto fail;
             }
             
-            if (!NCDValue_ListAppend(&list, server)) {
-                ModuleLog(o->i, BLOG_ERROR, "NCDValue_ListAppend failed");
-                NCDValue_Free(&server);
-                goto fail1;
-            }
+            NCDVal_ListAppend(*out, server);
         }
         
-        *out = list;
         return 1;
-        
-    fail1:
-        NCDValue_Free(&list);
-        return 0;
     }
     
     if (!strcmp(name, "server_mac")) {
@@ -304,15 +298,18 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
         sprintf(str, "%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8":%02"PRIX8,
                 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
     return 0;
+    
+fail:
+    *out = NCDVal_NewInvalid();
+    return 1;
 }
 
 static const struct NCDModule modules[] = {

+ 14 - 14
ncd/modules/net_ipv4_route.c

@@ -76,40 +76,40 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *dest_arg;
-    NCDValue *dest_prefix_arg;
-    NCDValue *gateway_arg;
-    NCDValue *metric_arg;
-    NCDValue *ifname_arg;
-    if (!NCDValue_ListRead(o->i->args, 5, &dest_arg, &dest_prefix_arg, &gateway_arg, &metric_arg, &ifname_arg)) {
+    NCDValRef dest_arg;
+    NCDValRef dest_prefix_arg;
+    NCDValRef gateway_arg;
+    NCDValRef metric_arg;
+    NCDValRef ifname_arg;
+    if (!NCDVal_ListRead(o->i->args, 5, &dest_arg, &dest_prefix_arg, &gateway_arg, &metric_arg, &ifname_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(dest_arg) || !NCDValue_IsStringNoNulls(dest_prefix_arg) || !NCDValue_IsStringNoNulls(gateway_arg) ||
-        !NCDValue_IsStringNoNulls(metric_arg) || !NCDValue_IsStringNoNulls(ifname_arg)) {
+    if (!NCDVal_IsStringNoNulls(dest_arg) || !NCDVal_IsStringNoNulls(dest_prefix_arg) || !NCDVal_IsStringNoNulls(gateway_arg) ||
+        !NCDVal_IsStringNoNulls(metric_arg) || !NCDVal_IsStringNoNulls(ifname_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
     // read dest
-    if (!ipaddr_parse_ipv4_addr(NCDValue_StringValue(dest_arg), &o->dest.addr)) {
+    if (!ipaddr_parse_ipv4_addr((char *)NCDVal_StringValue(dest_arg), &o->dest.addr)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong dest addr");
         goto fail1;
     }
-    if (!ipaddr_parse_ipv4_prefix(NCDValue_StringValue(dest_prefix_arg), &o->dest.prefix)) {
+    if (!ipaddr_parse_ipv4_prefix((char *)NCDVal_StringValue(dest_prefix_arg), &o->dest.prefix)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong dest prefix");
         goto fail1;
     }
     
     // read gateway and choose type
-    char *gateway_str = NCDValue_StringValue(gateway_arg);
+    const char *gateway_str = NCDVal_StringValue(gateway_arg);
     if (!strcmp(gateway_str, "none")) {
         o->type = TYPE_IFONLY;
     }
     else if (!strcmp(gateway_str, "blackhole")) {
         o->type = TYPE_BLACKHOLE;
     } else {
-        if (!ipaddr_parse_ipv4_addr(gateway_str, &o->gateway)) {
+        if (!ipaddr_parse_ipv4_addr((char *)gateway_str, &o->gateway)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong gateway");
             goto fail1;
         }
@@ -117,10 +117,10 @@ static void func_new (NCDModuleInst *i)
     }
     
     // read metric
-    o->metric = atoi(NCDValue_StringValue(metric_arg));
+    o->metric = atoi(NCDVal_StringValue(metric_arg));
     
     // read ifname
-    o->ifname = NCDValue_StringValue(ifname_arg);
+    o->ifname = NCDVal_StringValue(ifname_arg);
     
     // add route
     int res;

+ 11 - 11
ncd/modules/net_ipv6_wait_dynamic_addr.c

@@ -104,16 +104,16 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // read arguments
-    NCDValue *ifname_arg;
-    if (!NCDValue_ListRead(i->args, 1, &ifname_arg)) {
+    NCDValRef ifname_arg;
+    if (!NCDVal_ListRead(i->args, 1, &ifname_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(ifname_arg)) {
+    if (!NCDVal_IsStringNoNulls(ifname_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    const char *ifname = NCDValue_StringValue(ifname_arg);
+    const char *ifname = NCDVal_StringValue(ifname_arg);
     
     // get interface index
     int ifindex;
@@ -158,7 +158,7 @@ static void func_die (void *vo)
     instance_free(o);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     ASSERT(o->up)
@@ -169,9 +169,9 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
             ModuleLog(o->i, BLOG_ERROR, "ipaddr6_print_addr failed");
             return 0;
         }
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         return 1;
     }
@@ -179,9 +179,9 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
     if (!strcmp(name, "prefix")) {
         char str[10];
         sprintf(str, "%d", o->ifaddr.prefix);
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         return 1;
     }

+ 4 - 4
ncd/modules/net_up.c

@@ -63,16 +63,16 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *ifname_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &ifname_arg)) {
+    NCDValRef ifname_arg;
+    if (!NCDVal_ListRead(o->i->args, 1, &ifname_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(ifname_arg)) {
+    if (!NCDVal_IsStringNoNulls(ifname_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->ifname = NCDValue_StringValue(ifname_arg);
+    o->ifname = NCDVal_StringValue(ifname_arg);
     
     // set interface up
     if (!NCDIfConfig_set_up(o->ifname)) {

+ 4 - 4
ncd/modules/net_watch_interfaces.c

@@ -358,7 +358,7 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    if (!NCDValue_ListRead(o->i->args, 0)) {
+    if (!NCDVal_ListRead(o->i->args, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
@@ -430,16 +430,16 @@ static void func_die (void *vo)
     event_template_die(&o->templ);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
-    return event_template_getvar(&o->templ, name, out);
+    return event_template_getvar(&o->templ, name, mem, out);
 }
 
 static void nextevent_func_new (NCDModuleInst *i)
 {
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }

+ 22 - 24
ncd/modules/netmask.c

@@ -98,19 +98,19 @@ fail0:
 static void prefix_to_mask_func_init (NCDModuleInst *i)
 {
     // read arguments
-    NCDValue *prefix_arg;
-    if (!NCDValue_ListRead(i->args, 1, &prefix_arg)) {
+    NCDValRef prefix_arg;
+    if (!NCDVal_ListRead(i->args, 1, &prefix_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(prefix_arg)) {
+    if (!NCDVal_IsStringNoNulls(prefix_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     // parse prefix
     int prefix;
-    if (!ipaddr_parse_ipv4_prefix(NCDValue_StringValue(prefix_arg), &prefix)) {
+    if (!ipaddr_parse_ipv4_prefix((char *)NCDVal_StringValue(prefix_arg), &prefix)) {
         ModuleLog(i, BLOG_ERROR, "bad prefix");
         goto fail0;
     }
@@ -129,27 +129,27 @@ fail0:
 static void ipv4_net_from_addr_and_prefix_func_init (NCDModuleInst *i)
 {
     // read arguments
-    NCDValue *addr_arg;
-    NCDValue *prefix_arg;
-    if (!NCDValue_ListRead(i->args, 2, &addr_arg, &prefix_arg)) {
+    NCDValRef addr_arg;
+    NCDValRef prefix_arg;
+    if (!NCDVal_ListRead(i->args, 2, &addr_arg, &prefix_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(addr_arg) || !NCDValue_IsStringNoNulls(prefix_arg)) {
+    if (!NCDVal_IsStringNoNulls(addr_arg) || !NCDVal_IsStringNoNulls(prefix_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     // parse addr
     uint32_t addr;
-    if (!ipaddr_parse_ipv4_addr(NCDValue_StringValue(addr_arg), &addr)) {
+    if (!ipaddr_parse_ipv4_addr((char *)NCDVal_StringValue(addr_arg), &addr)) {
         ModuleLog(i, BLOG_ERROR, "bad addr");
         goto fail0;
     }
     
     // parse prefix
     int prefix;
-    if (!ipaddr_parse_ipv4_prefix(NCDValue_StringValue(prefix_arg), &prefix)) {
+    if (!ipaddr_parse_ipv4_prefix((char *)NCDVal_StringValue(prefix_arg), &prefix)) {
         ModuleLog(i, BLOG_ERROR, "bad prefix");
         goto fail0;
     }
@@ -176,7 +176,7 @@ static void addr_func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int addr_func_getvar (void *vo, const char *name, NCDValue *out_value)
+static int addr_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct addr_instance *o = vo;
     
@@ -185,11 +185,10 @@ static int addr_func_getvar (void *vo, const char *name, NCDValue *out_value)
         char buf[20];
         sprintf(buf, "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, x[0], x[1], x[2], x[3]);
         
-        if (!NCDValue_InitString(out_value, buf)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, buf);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -208,19 +207,19 @@ static void mask_to_prefix_func_init (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // read arguments
-    NCDValue *mask_arg;
-    if (!NCDValue_ListRead(i->args, 1, &mask_arg)) {
+    NCDValRef mask_arg;
+    if (!NCDVal_ListRead(i->args, 1, &mask_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(mask_arg)) {
+    if (!NCDVal_IsStringNoNulls(mask_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
     // parse mask
     uint32_t mask;
-    if (!ipaddr_parse_ipv4_addr(NCDValue_StringValue(mask_arg), &mask)) {
+    if (!ipaddr_parse_ipv4_addr((char *)NCDVal_StringValue(mask_arg), &mask)) {
         ModuleLog(i, BLOG_ERROR, "bad mask");
         goto fail1;
     }
@@ -253,7 +252,7 @@ static void prefix_func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int prefix_func_getvar (void *vo, const char *name, NCDValue *out_value)
+static int prefix_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct prefix_instance *o = vo;
     
@@ -261,11 +260,10 @@ static int prefix_func_getvar (void *vo, const char *name, NCDValue *out_value)
         char buf[6];
         sprintf(buf, "%d", o->prefix);
         
-        if (!NCDValue_InitString(out_value, buf)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, buf);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     

+ 9 - 17
ncd/modules/ondemand.c

@@ -66,8 +66,8 @@
 
 struct ondemand {
     NCDModuleInst *i;
-    char *template_name;
-    NCDValue *args;
+    const char *template_name;
+    NCDValRef args;
     LinkedList1 demands_list;
     int dying;
     int have_process;
@@ -93,17 +93,9 @@ static int ondemand_start_process (struct ondemand *o)
     ASSERT(!o->dying)
     ASSERT(!o->have_process)
     
-    // copy arguments
-    NCDValue args;
-    if (!NCDValue_InitCopy(&args, o->args)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail0;
-    }
-    
     // start process
-    if (!NCDModuleProcess_Init(&o->process, o->i, o->template_name, args, o, (NCDModuleProcess_handler_event)ondemand_process_handler)) {
+    if (!NCDModuleProcess_Init(&o->process, o->i, o->template_name, o->args, o, (NCDModuleProcess_handler_event)ondemand_process_handler)) {
         ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
-        NCDValue_Free(&args);
         goto fail0;
     }
     
@@ -230,17 +222,17 @@ static void ondemand_func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *arg_template_name;
-    NCDValue *arg_args;
-    if (!NCDValue_ListRead(i->args, 2, &arg_template_name, &arg_args)) {
+    NCDValRef arg_template_name;
+    NCDValRef arg_args;
+    if (!NCDVal_ListRead(i->args, 2, &arg_template_name, &arg_args)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(arg_template_name) || NCDValue_Type(arg_args) != NCDVALUE_LIST) {
+    if (!NCDVal_IsStringNoNulls(arg_template_name) || !NCDVal_IsList(arg_args)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->template_name = NCDValue_StringValue(arg_template_name);
+    o->template_name = NCDVal_StringValue(arg_template_name);
     o->args = arg_args;
     
     // init demands list
@@ -315,7 +307,7 @@ static void demand_func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }

+ 31 - 27
ncd/modules/parse.c

@@ -54,13 +54,14 @@
 
 struct instance {
     NCDModuleInst *i;
-    NCDValue value;
+    NCDValMem mem;
+    NCDValRef value;
     int succeeded;
 };
 
-typedef int (*parse_func) (NCDModuleInst *i, const char *str, NCDValue *out_value);
+typedef int (*parse_func) (NCDModuleInst *i, const char *str, NCDValMem *mem, NCDValRef *out);
 
-static int parse_number (NCDModuleInst *i, const char *str, NCDValue *out_value)
+static int parse_number (NCDModuleInst *i, const char *str, NCDValMem *mem, NCDValRef *out)
 {
     uintmax_t n;
     if (!parse_unsigned_integer(str, &n)) {
@@ -69,19 +70,20 @@ static int parse_number (NCDModuleInst *i, const char *str, NCDValue *out_value)
     }
     
     char buf[25];
-    sprintf(buf, "%"PRIuMAX, n);
+    snprintf(buf, sizeof(buf), "%"PRIuMAX, n);
     
-    if (!NCDValue_InitString(out_value, buf)) {
-        ModuleLog(i, BLOG_ERROR, "NCDValue_InitString failed");
+    *out = NCDVal_NewString(mem, buf);
+    if (NCDVal_IsInvalid(*out)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_NewString failed");
         return 0;
     }
     
     return 1;
 }
 
-static int parse_value (NCDModuleInst *i, const char *str, NCDValue *out_value)
+static int parse_value (NCDModuleInst *i, const char *str, NCDValMem *mem, NCDValRef *out)
 {
-    if (!NCDValueParser_Parse(str, strlen(str), out_value)) {
+    if (!NCDValParser_Parse(str, strlen(str), mem, out)) {
         ModuleLog(i, BLOG_ERROR, "failed to parse value");
         return 0;
     }
@@ -89,7 +91,7 @@ static int parse_value (NCDModuleInst *i, const char *str, NCDValue *out_value)
     return 1;
 }
 
-static int parse_ipv4_addr (NCDModuleInst *i, const char *str, NCDValue *out_value)
+static int parse_ipv4_addr (NCDModuleInst *i, const char *str, NCDValMem *mem, NCDValRef *out)
 {
     uint32_t addr;
     if (!ipaddr_parse_ipv4_addr((char *)str, &addr)) {
@@ -102,8 +104,9 @@ static int parse_ipv4_addr (NCDModuleInst *i, const char *str, NCDValue *out_val
     char buf[20];
     sprintf(buf, "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, x[0], x[1], x[2], x[3]);
     
-    if (!NCDValue_InitString(out_value, buf)) {
-        ModuleLog(i, BLOG_ERROR, "NCDValue_InitString failed");
+    *out = NCDVal_NewString(mem, buf);
+    if (NCDVal_IsInvalid(*out)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_NewString failed");
         return 0;
     }
     
@@ -122,22 +125,25 @@ static void new_templ (NCDModuleInst *i, parse_func pfunc)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // read arguments
-    NCDValue *str_arg;
-    if (!NCDValue_ListRead(i->args, 1, &str_arg)) {
+    NCDValRef str_arg;
+    if (!NCDVal_ListRead(i->args, 1, &str_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (NCDValue_Type(str_arg) != NCDVALUE_STRING) {
+    if (!NCDVal_IsString(str_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
+    // init mem
+    NCDValMem_Init(&o->mem);
+    
     // parse
-    if (NCDValue_StringHasNulls(str_arg)) {
+    if (NCDVal_StringHasNulls(str_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "string has nulls");
         o->succeeded = 0;
     } else {
-        o->succeeded = pfunc(i, NCDValue_StringValue(str_arg), &o->value);
+        o->succeeded = pfunc(i, NCDVal_StringValue(str_arg), &o->mem, &o->value);
     }
     
     // signal up
@@ -156,10 +162,8 @@ static void func_die (void *vo)
     struct instance *o = vo;
     NCDModuleInst *i = o->i;
     
-    // free value
-    if (o->succeeded) {
-        NCDValue_Free(&o->value);
-    }
+    // free mem
+    NCDValMem_Free(&o->mem);
     
     // free instance
     free(o);
@@ -167,23 +171,23 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out_value)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "succeeded")) {
         const char *str = o->succeeded ? "true" : "false";
-        if (!NCDValue_InitString(out_value, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         return 1;
     }
     
     if (o->succeeded && !strcmp(name, "")) {
-        if (!NCDValue_InitCopy(out_value, &o->value)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-            return 0;
+        *out = NCDVal_NewCopy(mem, o->value);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
         }
         return 1;
     }

+ 11 - 6
ncd/modules/print.c

@@ -68,11 +68,14 @@ struct instance {
 
 static void do_print (NCDModuleInst *i, int ln)
 {
-    for (NCDValue *arg = NCDValue_ListFirst(i->args); arg; arg = NCDValue_ListNext(i->args, arg)) {
-        ASSERT(NCDValue_Type(arg) == NCDVALUE_STRING)
+    size_t num_args = NCDVal_ListCount(i->args);
+    
+    for (size_t j = 0; j < num_args; j++) {
+        NCDValRef arg = NCDVal_ListGet(i->args, j);
+        ASSERT(NCDVal_IsString(arg))
         
-        const char *str = NCDValue_StringValue(arg);
-        size_t len = NCDValue_StringLength(arg);
+        const char *str = NCDVal_StringValue(arg);
+        size_t len = NCDVal_StringLength(arg);
         size_t pos = 0;
         
         while (pos < len) {
@@ -107,8 +110,10 @@ static void func_new_temp (NCDModuleInst *i, int ln, int rev)
     o->rev = rev;
     
     // check arguments
-    for (NCDValue *arg = NCDValue_ListFirst(i->args); arg; arg = NCDValue_ListNext(i->args, arg)) {
-        if (NCDValue_Type(arg) != NCDVALUE_STRING) {
+    size_t num_args = NCDVal_ListCount(i->args);
+    for (size_t j = 0; j < num_args; j++) {
+        NCDValRef arg = NCDVal_ListGet(i->args, j);
+        if (!NCDVal_IsString(arg)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong type");
             goto fail1;
         }

+ 57 - 38
ncd/modules/process_manager.c

@@ -77,23 +77,26 @@ struct process {
     LinkedList2Node processes_list_node;
     int have_params;
     char *params_template_name;
-    NCDValue params_args;
+    NCDValMem params_mem;
+    NCDValRef params_args;
     int have_module_process;
+    NCDValMem process_mem;
+    NCDValRef process_args;
     NCDModuleProcess module_process;
     int state;
 };
 
 static struct process * find_process (struct instance *o, const char *name);
-static int process_new (struct instance *o, const char *name, const char *template_name, NCDValue *args);
+static int process_new (struct instance *o, const char *name, const char *template_name, NCDValRef args);
 static void process_free (struct process *p);
 static void process_retry_timer_handler (struct process *p);
 static void process_module_process_handler_event (struct process *p, int event);
 static int process_module_process_func_getspecialobj (struct process *p, const char *name, NCDObject *out_object);
 static int process_module_process_caller_obj_func_getobj (struct process *p, const char *name, NCDObject *out_object);
 static void process_stop (struct process *p);
-static int process_restart (struct process *p, const char *template_name, NCDValue *args);
+static int process_restart (struct process *p, const char *template_name, NCDValRef args);
 static void process_try (struct process *p);
-static int process_set_params (struct process *p, const char *template_name, NCDValue args);
+static int process_set_params (struct process *p, const char *template_name, NCDValMem mem, NCDValSafeRef args);
 static void instance_free (struct instance *o);
 
 struct process * find_process (struct instance *o, const char *name)
@@ -110,11 +113,11 @@ struct process * find_process (struct instance *o, const char *name)
     return NULL;
 }
 
-int process_new (struct instance *o, const char *name, const char *template_name, NCDValue *args)
+int process_new (struct instance *o, const char *name, const char *template_name, NCDValRef args)
 {
     ASSERT(!o->dying)
     ASSERT(!find_process(o, name))
-    ASSERT(NCDValue_Type(args) == NCDVALUE_LIST)
+    ASSERT(NCDVal_IsList(args))
     
     // allocate structure
     struct process *p = malloc(sizeof(*p));
@@ -145,15 +148,16 @@ int process_new (struct instance *o, const char *name, const char *template_name
     p->have_module_process = 0;
     
     // copy arguments
-    NCDValue args2;
-    if (!NCDValue_InitCopy(&args2, args)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
+    NCDValMem mem;
+    NCDValMem_Init(&mem);
+    NCDValRef args2 = NCDVal_NewCopy(&mem, args);
+    if (NCDVal_IsInvalid(args2)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
         goto fail2;
     }
     
     // set params
-    if (!process_set_params(p, template_name, args2)) {
-        NCDValue_Free(&args2);
+    if (!process_set_params(p, template_name, mem, NCDVal_ToSafe(args2))) {
         goto fail2;
     }
     
@@ -163,6 +167,7 @@ int process_new (struct instance *o, const char *name, const char *template_name
     return 1;
     
 fail2:
+    NCDValMem_Free(&mem);
     LinkedList2_Remove(&o->processes_list, &p->processes_list_node);
     free(p->name);
 fail1:
@@ -178,7 +183,7 @@ void process_free (struct process *p)
     
     // free params
     if (p->have_params) {
-        NCDValue_Free(&p->params_args);
+        NCDValMem_Free(&p->params_mem);
         free(p->params_template_name);
     }
     
@@ -224,6 +229,9 @@ void process_module_process_handler_event (struct process *p, int event)
     // free module process
     NCDModuleProcess_Free(&p->module_process);
     
+    // free arguments mem
+    NCDValMem_Free(&p->process_mem);
+    
     // set no module process
     p->have_module_process = 0;
     
@@ -297,7 +305,7 @@ void process_stop (struct process *p)
             ASSERT(p->have_params)
             
             // free params
-            NCDValue_Free(&p->params_args);
+            NCDValMem_Free(&p->params_mem);
             free(p->params_template_name);
             p->have_params = 0;
             
@@ -313,30 +321,36 @@ void process_stop (struct process *p)
     }
 }
 
-int process_restart (struct process *p, const char *template_name, NCDValue *args)
+int process_restart (struct process *p, const char *template_name, NCDValRef args)
 {
     struct instance *o = p->manager;
     ASSERT(!o->dying)
     ASSERT(p->state == PROCESS_STATE_STOPPING)
     ASSERT(!p->have_params)
+    ASSERT(NCDVal_IsList(args))
     
     // copy arguments
-    NCDValue args2;
-    if (!NCDValue_InitCopy(&args2, args)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        return 0;
+    NCDValMem mem;
+    NCDValMem_Init(&mem);
+    NCDValRef args2 = NCDVal_NewCopy(&mem, args);
+    if (NCDVal_IsInvalid(args2)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
+        goto fail1;
     }
     
     // set params
-    if (!process_set_params(p, template_name, args2)) {
-        NCDValue_Free(&args2);
-        return 0;
+    if (!process_set_params(p, template_name, mem, NCDVal_ToSafe(args2))) {
+        goto fail1;
     }
     
     // set state
     p->state = PROCESS_STATE_RESTARTING;
     
     return 1;
+    
+fail1:
+    NCDValMem_Free(&mem);
+    return 0;
 }
 
 void process_try (struct process *p)
@@ -348,8 +362,12 @@ void process_try (struct process *p)
     
     ModuleLog(o->i, BLOG_INFO, "trying process %s", p->name);
     
+    // move params
+    p->process_mem = p->params_mem;
+    p->process_args = NCDVal_Moved(&p->process_mem, p->params_args);
+    
     // init module process
-    if (!NCDModuleProcess_Init(&p->module_process, o->i, p->params_template_name, p->params_args, p, (NCDModuleProcess_handler_event)process_module_process_handler_event)) {
+    if (!NCDModuleProcess_Init(&p->module_process, o->i, p->params_template_name, p->process_args, p, (NCDModuleProcess_handler_event)process_module_process_handler_event)) {
         ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
         
         // set timer
@@ -357,7 +375,6 @@ void process_try (struct process *p)
         
         // set state
         p->state = PROCESS_STATE_RETRYING;
-        
         return;
     }
     
@@ -375,9 +392,10 @@ void process_try (struct process *p)
     p->state = PROCESS_STATE_RUNNING;
 }
 
-int process_set_params (struct process *p, const char *template_name, NCDValue args)
+int process_set_params (struct process *p, const char *template_name, NCDValMem mem, NCDValSafeRef args)
 {
     ASSERT(!p->have_params)
+    ASSERT(NCDVal_IsList(NCDVal_FromSafe(&mem, args)))
     
     // copy template name
     if (!(p->params_template_name = strdup(template_name))) {
@@ -386,7 +404,8 @@ int process_set_params (struct process *p, const char *template_name, NCDValue a
     }
     
     // eat arguments
-    p->params_args = args;
+    p->params_mem = mem;
+    p->params_args = NCDVal_FromSafe(&p->params_mem, args);
     
     // set have params
     p->have_params = 1;
@@ -408,7 +427,7 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    if (!NCDValue_ListRead(o->i->args, 0)) {
+    if (!NCDVal_ListRead(o->i->args, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
@@ -469,20 +488,20 @@ static void func_die (void *vo)
 static void start_func_new (NCDModuleInst *i)
 {
     // check arguments
-    NCDValue *name_arg;
-    NCDValue *template_name_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(i->args, 3, &name_arg, &template_name_arg, &args_arg)) {
+    NCDValRef name_arg;
+    NCDValRef template_name_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(i->args, 3, &name_arg, &template_name_arg, &args_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(name_arg) || !NCDValue_IsStringNoNulls(template_name_arg) ||
-        NCDValue_Type(args_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsStringNoNulls(name_arg) || !NCDVal_IsStringNoNulls(template_name_arg) ||
+        !NCDVal_IsList(args_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    char *name = NCDValue_StringValue(name_arg);
-    char *template_name = NCDValue_StringValue(template_name_arg);
+    const char *name = NCDVal_StringValue(name_arg);
+    const char *template_name = NCDVal_StringValue(template_name_arg);
     
     // signal up.
     // Do it before creating the process so that the process starts initializing before our own process continues.
@@ -522,16 +541,16 @@ fail0:
 static void stop_func_new (NCDModuleInst *i)
 {
     // check arguments
-    NCDValue *name_arg;
-    if (!NCDValue_ListRead(i->args, 1, &name_arg)) {
+    NCDValRef name_arg;
+    if (!NCDVal_ListRead(i->args, 1, &name_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(name_arg)) {
+    if (!NCDVal_IsStringNoNulls(name_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    char *name = NCDValue_StringValue(name_arg);
+    const char *name = NCDVal_StringValue(name_arg);
     
     // signal up.
     // Do it before stopping the process so that the process starts terminating before our own process continues.

+ 2 - 2
ncd/modules/ref.c

@@ -81,7 +81,7 @@ static void refhere_func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
@@ -145,7 +145,7 @@ static void ref_func_new_templ (NCDModuleInst *i, struct refhere_instance *rh)
     o->i = i;
     
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }

+ 35 - 38
ncd/modules/regex_match.c

@@ -79,7 +79,7 @@
 
 struct instance {
     NCDModuleInst *i;
-    char *input;
+    const char *input;
     size_t input_len;
     int succeeded;
     int num_matches;
@@ -184,19 +184,19 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read arguments
-    NCDValue *input_arg;
-    NCDValue *regex_arg;
-    if (!NCDValue_ListRead(o->i->args, 2, &input_arg, &regex_arg)) {
+    NCDValRef input_arg;
+    NCDValRef regex_arg;
+    if (!NCDVal_ListRead(o->i->args, 2, &input_arg, &regex_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (NCDValue_Type(input_arg) != NCDVALUE_STRING || !NCDValue_IsStringNoNulls(regex_arg)) {
+    if (!NCDVal_IsString(input_arg) || !NCDVal_IsStringNoNulls(regex_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->input = NCDValue_StringValue(input_arg);
-    o->input_len = NCDValue_StringLength(input_arg);
-    char *regex = NCDValue_StringValue(regex_arg);
+    o->input = NCDVal_StringValue(input_arg);
+    o->input_len = NCDVal_StringLength(input_arg);
+    const char *regex = NCDVal_StringValue(regex_arg);
     
     // make sure we don't overflow regoff_t
     if (o->input_len > INT_MAX) {
@@ -243,16 +243,16 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "succeeded")) {
-        if (!NCDValue_InitString(out, (o->succeeded ? "true" : "false"))) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-            return 0;
+        const char *str = o->succeeded ? "true" : "false";
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -268,11 +268,10 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
             
             size_t len = m->rm_eo - m->rm_so;
             
-            if (!NCDValue_InitStringBin(out, (uint8_t *)o->input + m->rm_so, len)) {
-                ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitStringBin failed");
-                return 0;
+            *out = NCDVal_NewStringBin(mem, (uint8_t *)o->input + m->rm_so, len);
+            if (NCDVal_IsInvalid(*out)) {
+                ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewStringBin failed");
             }
-            
             return 1;
         }
     }
@@ -292,35 +291,36 @@ static void replace_func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // read arguments
-    NCDValue *input_arg;
-    NCDValue *regex_arg;
-    NCDValue *replace_arg;
-    if (!NCDValue_ListRead(i->args, 3, &input_arg, &regex_arg, &replace_arg)) {
+    NCDValRef input_arg;
+    NCDValRef regex_arg;
+    NCDValRef replace_arg;
+    if (!NCDVal_ListRead(i->args, 3, &input_arg, &regex_arg, &replace_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsString(input_arg) || !NCDValue_IsList(regex_arg) || !NCDValue_IsList(replace_arg)) {
+    if (!NCDVal_IsString(input_arg) || !NCDVal_IsList(regex_arg) || !NCDVal_IsList(replace_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
     // check number of regex/replace
-    if (NCDValue_ListCount(regex_arg) != NCDValue_ListCount(replace_arg)) {
+    if (NCDVal_ListCount(regex_arg) != NCDVal_ListCount(replace_arg)) {
         ModuleLog(i, BLOG_ERROR, "number of regex's is not the same as number of replacements");
         goto fail1;
     }
     
     // start with input as current text
-    char *current = NCDValue_StringValue(input_arg);
-    size_t current_len = NCDValue_StringLength(input_arg);
+    char *current = (char *)NCDVal_StringValue(input_arg);
+    size_t current_len = NCDVal_StringLength(input_arg);
     int current_free = 0;
     
-    NCDValue *regex = NCDValue_ListFirst(regex_arg);
-    NCDValue *replace = NCDValue_ListFirst(replace_arg);
-    
-    while (regex) {
+    size_t count = NCDVal_ListCount(regex_arg);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef regex = NCDVal_ListGet(regex_arg, j);
+        NCDValRef replace = NCDVal_ListGet(replace_arg, j);
+        
         // check type of regex and replace
-        if (!NCDValue_IsStringNoNulls(regex) || !NCDValue_IsString(replace)) {
+        if (!NCDVal_IsStringNoNulls(regex) || !NCDVal_IsString(replace)) {
             ModuleLog(i, BLOG_ERROR, "regex/replace element has wrong type");
             goto fail2;
         }
@@ -328,7 +328,7 @@ static void replace_func_new (NCDModuleInst *i)
         // perform the replacing
         char *replaced;
         size_t replaced_len;
-        if (!regex_replace(current, current_len, NCDValue_StringValue(regex), NCDValue_StringValue(replace), NCDValue_StringLength(replace), &replaced, &replaced_len, i)) {
+        if (!regex_replace(current, current_len, NCDVal_StringValue(regex), NCDVal_StringValue(replace), NCDVal_StringLength(replace), &replaced, &replaced_len, i)) {
             goto fail2;
         }
         
@@ -339,9 +339,6 @@ static void replace_func_new (NCDModuleInst *i)
         current = replaced;
         current_len = replaced_len;
         current_free = 1;
-        
-        regex = NCDValue_ListNext(regex_arg, regex);
-        replace = NCDValue_ListNext(replace_arg, replace);
     }
     
     // set output
@@ -380,14 +377,14 @@ static void replace_func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int replace_func_getvar (void *vo, const char *name, NCDValue *out)
+static int replace_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct replace_instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitStringBin(out, (uint8_t *)o->output, o->output_len)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitStringBin failed");
-            return 0;
+        *out = NCDVal_NewStringBin(mem, (uint8_t *)o->output, o->output_len);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewStringBin failed");
         }
         return 1;
     }

+ 15 - 13
ncd/modules/run.c

@@ -60,32 +60,33 @@ struct instance {
 static int build_cmdline (NCDModuleInst *i, int remove, char **exec, CmdLine *cl)
 {
     // read arguments
-    NCDValue *do_cmd_arg;
-    NCDValue *undo_cmd_arg;
-    if (!NCDValue_ListRead(i->args, 2, &do_cmd_arg, &undo_cmd_arg)) {
+    NCDValRef do_cmd_arg;
+    NCDValRef undo_cmd_arg;
+    if (!NCDVal_ListRead(i->args, 2, &do_cmd_arg, &undo_cmd_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (NCDValue_Type(do_cmd_arg) != NCDVALUE_LIST || NCDValue_Type(undo_cmd_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsList(do_cmd_arg) || !NCDVal_IsList(undo_cmd_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
-    NCDValue *list = (remove ? undo_cmd_arg : do_cmd_arg);
+    NCDValRef list = (remove ? undo_cmd_arg : do_cmd_arg);
+    size_t count = NCDVal_ListCount(list);
     
     // check if there is no command
-    if (!NCDValue_ListFirst(list)) {
+    if (count == 0) {
         *exec = NULL;
         return 1;
     }
     
     // read exec
-    NCDValue *exec_arg = NCDValue_ListFirst(list);
-    if (!NCDValue_IsStringNoNulls(exec_arg)) {
+    NCDValRef exec_arg = NCDVal_ListGet(list, 0);
+    if (!NCDVal_IsStringNoNulls(exec_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    if (!(*exec = strdup(NCDValue_StringValue(exec_arg)))) {
+    if (!(*exec = strdup(NCDVal_StringValue(exec_arg)))) {
         ModuleLog(i, BLOG_ERROR, "strdup failed");
         goto fail0;
     }
@@ -103,14 +104,15 @@ static int build_cmdline (NCDModuleInst *i, int remove, char **exec, CmdLine *cl
     }
     
     // add additional arguments
-    NCDValue *arg = exec_arg;
-    while (arg = NCDValue_ListNext(list, arg)) {
-        if (!NCDValue_IsStringNoNulls(arg)) {
+    for (size_t j = 1; j < count; j++) {
+        NCDValRef arg = NCDVal_ListGet(list, j);
+        
+        if (!NCDVal_IsStringNoNulls(arg)) {
             ModuleLog(i, BLOG_ERROR, "wrong type");
             goto fail2;
         }
         
-        if (!CmdLine_Append(cl, NCDValue_StringValue(arg))) {
+        if (!CmdLine_Append(cl, NCDVal_StringValue(arg))) {
             ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
             goto fail2;
         }

+ 29 - 22
ncd/modules/runonce.c

@@ -72,24 +72,28 @@ struct instance {
 
 static void instance_free (struct instance *o);
 
-static int build_cmdline (NCDModuleInst *i, NCDValue *cmd_arg, char **exec, CmdLine *cl)
+static int build_cmdline (NCDModuleInst *i, NCDValRef cmd_arg, char **exec, CmdLine *cl)
 {
-    if (NCDValue_Type(cmd_arg) != NCDVALUE_LIST) {
+    ASSERT(!NCDVal_IsInvalid(cmd_arg))
+    
+    if (!NCDVal_IsList(cmd_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
+    size_t count = NCDVal_ListCount(cmd_arg);
+    
     // read exec
-    NCDValue *exec_arg = NCDValue_ListFirst(cmd_arg);
-    if (!exec_arg) {
+    if (count == 0) {
         ModuleLog(i, BLOG_ERROR, "missing executable name");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(exec_arg)) {
+    NCDValRef exec_arg = NCDVal_ListGet(cmd_arg, 0);
+    if (!NCDVal_IsStringNoNulls(exec_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
-    if (!(*exec = strdup(NCDValue_StringValue(exec_arg)))) {
+    if (!(*exec = strdup(NCDVal_StringValue(exec_arg)))) {
         ModuleLog(i, BLOG_ERROR, "strdup failed");
         goto fail0;
     }
@@ -107,14 +111,15 @@ static int build_cmdline (NCDModuleInst *i, NCDValue *cmd_arg, char **exec, CmdL
     }
     
     // add additional arguments
-    NCDValue *arg = exec_arg;
-    while (arg = NCDValue_ListNext(cmd_arg, arg)) {
-        if (!NCDValue_IsStringNoNulls(arg)) {
+    for (size_t j = 1; j < count; j++) {
+        NCDValRef arg = NCDVal_ListGet(cmd_arg, j);
+        
+        if (!NCDVal_IsStringNoNulls(arg)) {
             ModuleLog(i, BLOG_ERROR, "wrong type");
             goto fail2;
         }
         
-        if (!CmdLine_Append(cl, NCDValue_StringValue(arg))) {
+        if (!CmdLine_Append(cl, NCDVal_StringValue(arg))) {
             ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
             goto fail2;
         }
@@ -174,13 +179,13 @@ static void func_new (NCDModuleInst *i)
     o->term_on_deinit = 0;
     
     // read arguments
-    NCDValue *cmd_arg;
-    NCDValue *opts_arg = NULL;
-    if (!NCDValue_ListRead(i->args, 1, &cmd_arg) && !NCDValue_ListRead(i->args, 2, &cmd_arg, &opts_arg)) {
+    NCDValRef cmd_arg;
+    NCDValRef opts_arg = NCDVal_NewInvalid();
+    if (!NCDVal_ListRead(i->args, 1, &cmd_arg) && !NCDVal_ListRead(i->args, 2, &cmd_arg, &opts_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (opts_arg && NCDValue_Type(opts_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsInvalid(opts_arg) && !NCDVal_IsList(opts_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
@@ -190,13 +195,16 @@ static void func_new (NCDModuleInst *i)
     int do_setsid = 0;
     
     // read options
-    for (NCDValue *opt = (opts_arg ? NCDValue_ListFirst(opts_arg) : NULL); opt; opt = NCDValue_ListNext(opts_arg, opt)) {
+    size_t count = NCDVal_IsInvalid(opts_arg) ? 0 : NCDVal_ListCount(opts_arg);
+    for (size_t j = 0; j < count; j++) {
+        NCDValRef opt = NCDVal_ListGet(opts_arg, j);
+        
         // read name
-        if (!NCDValue_IsStringNoNulls(opt)) {
+        if (!NCDVal_IsStringNoNulls(opt)) {
             ModuleLog(o->i, BLOG_ERROR, "wrong option name type");
             goto fail1;
         }
-        char *optname = NCDValue_StringValue(opt);
+        const char *optname = NCDVal_StringValue(opt);
         
         if (!strcmp(optname, "term_on_deinit")) {
             o->term_on_deinit = 1;
@@ -295,7 +303,7 @@ static void func_die (void *vo)
     o->state = STATE_RUNNING_DIE;
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     ASSERT(o->state == STATE_FINISHED)
@@ -304,11 +312,10 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
         char str[30];
         snprintf(str, sizeof(str), "%d", o->exit_status);
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     

+ 6 - 6
ncd/modules/sleep.c

@@ -82,21 +82,21 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    NCDValue *ms_start_arg;
-    NCDValue *ms_stop_arg;
-    if (!NCDValue_ListRead(i->args, 2, &ms_start_arg, &ms_stop_arg)) {
+    NCDValRef ms_start_arg;
+    NCDValRef ms_stop_arg;
+    if (!NCDVal_ListRead(i->args, 2, &ms_start_arg, &ms_stop_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(ms_start_arg) || !NCDValue_IsStringNoNulls(ms_stop_arg)) {
+    if (!NCDVal_IsStringNoNulls(ms_start_arg) || !NCDVal_IsStringNoNulls(ms_stop_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    if (sscanf(NCDValue_StringValue(ms_start_arg), "%"SCNi64, &o->ms_start) != 1) {
+    if (sscanf(NCDVal_StringValue(ms_start_arg), "%"SCNi64, &o->ms_start) != 1) {
         ModuleLog(o->i, BLOG_ERROR, "wrong time");
         goto fail1;
     }
-    if (sscanf(NCDValue_StringValue(ms_stop_arg), "%"SCNi64, &o->ms_stop) != 1) {
+    if (sscanf(NCDVal_StringValue(ms_stop_arg), "%"SCNi64, &o->ms_stop) != 1) {
         ModuleLog(o->i, BLOG_ERROR, "wrong time");
         goto fail1;
     }

+ 6 - 16
ncd/modules/spawn.c

@@ -97,19 +97,17 @@ static void func_new (NCDModuleInst *i)
         ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
         goto fail0;
     }
-    NCDModuleInst_Backend_SetUser(i, o);
-    
-    // init arguments
     o->i = i;
+    NCDModuleInst_Backend_SetUser(i, o);
     
     // check arguments
-    NCDValue *template_name_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(o->i->args, 2, &template_name_arg, &args_arg)) {
+    NCDValRef template_name_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(o->i->args, 2, &template_name_arg, &args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(template_name_arg) || NCDValue_Type(args_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsStringNoNulls(template_name_arg) || !NCDVal_IsList(args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
@@ -118,17 +116,9 @@ static void func_new (NCDModuleInst *i)
     // Do it before creating the process so that the process starts initializing before our own process continues.
     NCDModuleInst_Backend_Up(o->i);
     
-    // copy arguments
-    NCDValue args;
-    if (!NCDValue_InitCopy(&args, args_arg)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail1;
-    }
-    
     // create process
-    if (!NCDModuleProcess_Init(&o->process, o->i, NCDValue_StringValue(template_name_arg), args, o, (NCDModuleProcess_handler_event)process_handler_event)) {
+    if (!NCDModuleProcess_Init(&o->process, o->i, NCDVal_StringValue(template_name_arg), args_arg, o, (NCDModuleProcess_handler_event)process_handler_event)) {
         ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
-        NCDValue_Free(&args);
         goto fail1;
     }
     

+ 22 - 46
ncd/modules/strcmp.c

@@ -44,70 +44,47 @@
 
 #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
 
-struct instance {
-    NCDModuleInst *i;
-    NCDValue *arg1;
-    NCDValue *arg2;
-};
-
 static void func_new (NCDModuleInst *i)
 {
-    // allocate instance
-    struct instance *o = malloc(sizeof(*o));
-    if (!o) {
-        ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
-        goto fail0;
-    }
-    NCDModuleInst_Backend_SetUser(i, o);
+    // set argument
+    NCDModuleInst_Backend_SetUser(i, i);
     
-    // init arguments
-    o->i = i;
-    
-    // read arguments
-    if (!NCDValue_ListRead(o->i->args, 2, &o->arg1, &o->arg2)) {
-        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
-        goto fail1;
+    // check arguments
+    NCDValRef str1_arg;
+    NCDValRef str2_arg;
+    if (!NCDVal_ListRead(i->args, 2, &str1_arg, &str2_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail0;
     }
-    if (NCDValue_Type(o->arg1) != NCDVALUE_STRING || NCDValue_Type(o->arg2) != NCDVALUE_STRING) {
-        ModuleLog(o->i, BLOG_ERROR, "wrong type");
-        goto fail1;
+    if (!NCDVal_IsString(str1_arg) || !NCDVal_IsString(str2_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong type");
+        goto fail0;
     }
     
     // signal up
-    NCDModuleInst_Backend_Up(o->i);
-    
+    NCDModuleInst_Backend_Up(i);
     return;
     
-fail1:
-    free(o);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);
 }
 
-static void func_die (void *vo)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
-    struct instance *o = vo;
-    NCDModuleInst *i = o->i;
-    
-    // free instance
-    free(o);
-    
-    NCDModuleInst_Backend_Dead(i);
-}
-
-static int func_getvar (void *vo, const char *name, NCDValue *out)
-{
-    struct instance *o = vo;
+    NCDModuleInst *i = vo;
     
     if (!strcmp(name, "")) {
-        const char *v = !NCDValue_Compare(o->arg1, o->arg2) ? "true" : "false";
+        NCDValRef str1_arg;
+        NCDValRef str2_arg;
+        NCDVal_ListRead(i->args, 2, &str1_arg, &str2_arg);
+        int result = NCDVal_Compare(str1_arg, str2_arg) == 0;
+        const char *v = result ? "true" : "false";
         
-        if (!NCDValue_InitString(out, v)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, v);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -118,7 +95,6 @@ static const struct NCDModule modules[] = {
     {
         .type = "strcmp",
         .func_new = func_new,
-        .func_die = func_die,
         .func_getvar = func_getvar
     }, {
         .type = NULL

+ 18 - 23
ncd/modules/sys_evdev.c

@@ -151,18 +151,18 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    NCDValue *device_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &device_arg)) {
+    NCDValRef device_arg;
+    if (!NCDVal_ListRead(o->i->args, 1, &device_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(device_arg)) {
+    if (!NCDVal_IsStringNoNulls(device_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
     
     // open device
-    if ((o->evdev_fd = open(NCDValue_StringValue(device_arg), O_RDONLY)) < 0) {
+    if ((o->evdev_fd = open(NCDVal_StringValue(device_arg), O_RDONLY)) < 0) {
         ModuleLog(o->i, BLOG_ERROR, "open failed");
         goto fail1;
     }
@@ -223,39 +223,36 @@ static void func_die (void *vo)
     instance_free(o, 0);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     ASSERT(o->processing)
     
     if (!strcmp(name, "type")) {
-        if (!NCDValue_InitString(out, evdev_type_to_str(o->event.type))) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, evdev_type_to_str(o->event.type));
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
     if (!strcmp(name, "value")) {
         char str[50];
         snprintf(str, sizeof(str), "%"PRIi32, o->event.value);
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
     if (!strcmp(name, "code_numeric")) {
         char str[50];
         snprintf(str, sizeof(str), "%"PRIu16, o->event.code);
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -297,14 +294,12 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
             #endif
         }
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
-
     
     return 0;
 }
@@ -312,7 +307,7 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
 static void nextevent_func_new (NCDModuleInst *i)
 {
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }

+ 82 - 72
ncd/modules/sys_request_client.c

@@ -92,6 +92,7 @@
 #include <system/BAddr.h>
 #include <ncd/NCDModule.h>
 #include <ncd/NCDRequestClient.h>
+#include <ncd/NCDValCompat.h>
 
 #include <generated/blog_channel_ncd_sys_request_client.h>
 
@@ -122,16 +123,17 @@ struct instance {
 
 struct request_instance {
     NCDModuleInst *i;
-    char *reply_handler;
-    char *finished_handler;
-    NCDValue *args;
+    const char *reply_handler;
+    const char *finished_handler;
+    NCDValRef args;
     struct instance *client;
     NCDRequestClientRequest request;
     LinkedList0Node requests_list_node;
     LinkedList1 replies_list;
     NCDModuleProcess process;
     int process_is_finished;
-    NCDValue process_reply_data;
+    NCDValMem process_reply_mem;
+    NCDValRef process_reply_data;
     int rstate;
     int pstate;
     int dstate;
@@ -139,7 +141,8 @@ struct request_instance {
 
 struct reply {
     LinkedList1Node replies_list_node;
-    NCDValue val;
+    NCDValMem mem;
+    NCDValRef val;
 };
 
 static void client_handler_error (struct instance *o);
@@ -150,14 +153,14 @@ static void request_handler_finished (struct request_instance *o, int is_error);
 static void request_process_handler_event (struct request_instance *o, int event);
 static int request_process_func_getspecialobj (struct request_instance *o, const char *name, NCDObject *out_object);
 static int request_process_caller_obj_func_getobj (struct request_instance *o, const char *name, NCDObject *out_object);
-static int request_process_reply_obj_func_getvar (struct request_instance *o, const char *name, NCDValue *out_value);
+static int request_process_reply_obj_func_getvar (struct request_instance *o, const char *name, NCDValMem *mem, NCDValRef *out);
 static void request_gone (struct request_instance *o, int is_bad);
 static void request_terminate_process (struct request_instance *o);
 static void request_die (struct request_instance *o, int is_error);
 static void request_free_reply (struct request_instance *o, struct reply *r, int have_value);
-static int request_init_reply_process (struct request_instance *o, NCDValue reply_data);
+static int request_init_reply_process (struct request_instance *o, NCDValMem reply_mem, NCDValSafeRef reply_data);
 static int request_init_finished_process (struct request_instance *o);
-static int get_connect_addr (struct instance *o, NCDValue *connect_addr_arg, struct NCDRequestClient_addr *out_addr);
+static int get_connect_addr (struct instance *o, NCDValRef connect_addr_arg, struct NCDRequestClient_addr *out_addr);
 static void instance_free (struct instance *o, int with_error);
 static void request_instance_free (struct request_instance *o, int with_error);
 
@@ -195,27 +198,39 @@ static void request_handler_reply (struct request_instance *o, NCDValue reply_da
 {
     ASSERT(o->rstate == RRSTATE_READY)
     
+    NCDValMem mem;
+    NCDValMem_Init(&mem);
+    
+    NCDValRef val;
+    int res = NCDValCompat_ValueToVal(&reply_data, &mem, &val);
+    NCDValue_Free(&reply_data);
+    if (!res) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDValCompat_ValueToVal failed");
+        goto fail1;
+    }
+    
     // queue reply if process is running
     if (o->pstate != RPSTATE_NONE) {
         struct reply *r = malloc(sizeof(*r));
         if (!r) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-            goto fail;
+            ModuleLog(o->i, BLOG_ERROR, "malloc failed");
+            goto fail1;
         }
-        r->val = reply_data;
+        r->mem = mem;
+        r->val = NCDVal_Moved(&r->mem, val);
         LinkedList1_Append(&o->replies_list, &r->replies_list_node);
         return;
     }
     
     // start reply process
-    if (!request_init_reply_process(o, reply_data)) {
-        goto fail;
+    if (!request_init_reply_process(o, mem, NCDVal_ToSafe(val))) {
+        goto fail1;
     }
     
     return;
     
-fail:
-    NCDValue_Free(&reply_data);
+fail1:
+    NCDValMem_Free(&mem);
     request_die(o, 1);
 }
 
@@ -270,7 +285,7 @@ static void request_process_handler_event (struct request_instance *o, int event
             
             // free reply data
             if (!o->process_is_finished) {
-                NCDValue_Free(&o->process_reply_data);
+                NCDValMem_Free(&o->process_reply_mem);
             }
             
             // set process state none
@@ -287,7 +302,7 @@ static void request_process_handler_event (struct request_instance *o, int event
                 struct reply *r = UPPER_OBJECT(LinkedList1_GetFirst(&o->replies_list), struct reply, replies_list_node);
                 
                 // start reply process
-                if (!request_init_reply_process(o, r->val)) {
+                if (!request_init_reply_process(o, r->mem, NCDVal_ToSafe(r->val))) {
                     goto fail;
                 }
                 
@@ -333,15 +348,15 @@ static int request_process_caller_obj_func_getobj (struct request_instance *o, c
     return NCDModuleInst_Backend_GetObj(o->i, name, out_object);
 }
 
-static int request_process_reply_obj_func_getvar (struct request_instance *o, const char *name, NCDValue *out_value)
+static int request_process_reply_obj_func_getvar (struct request_instance *o, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     ASSERT(o->pstate != RPSTATE_NONE)
     ASSERT(!o->process_is_finished)
     
     if (!strcmp(name, "data")) {
-        if (!NCDValue_InitCopy(out_value, &o->process_reply_data)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-            return 0;
+        *out = NCDVal_NewCopy(mem, o->process_reply_data);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
         }
         return 1;
     }
@@ -404,32 +419,25 @@ static void request_free_reply (struct request_instance *o, struct reply *r, int
     
     // free value
     if (have_value) {
-        NCDValue_Free(&r->val);
+        NCDValMem_Free(&r->mem);
     }
     
     // free structure
     free(r);
 }
 
-static int request_init_reply_process (struct request_instance *o, NCDValue reply_data)
+static int request_init_reply_process (struct request_instance *o, NCDValMem reply_mem, NCDValSafeRef reply_data)
 {
     ASSERT(o->pstate == RPSTATE_NONE)
     
     // set parameters
     o->process_is_finished = 0;
-    o->process_reply_data = reply_data;
-    
-    // copy arguments
-    NCDValue args;
-    if (!NCDValue_InitCopy(&args, o->args)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail0;
-    }
+    o->process_reply_mem = reply_mem;
+    o->process_reply_data = NCDVal_FromSafe(&o->process_reply_mem, reply_data);
     
     // init process
-    if (!NCDModuleProcess_Init(&o->process, o->i, o->reply_handler, args, o, (NCDModuleProcess_handler_event)request_process_handler_event)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        NCDValue_Free(&args);
+    if (!NCDModuleProcess_Init(&o->process, o->i, o->reply_handler, o->args, o, (NCDModuleProcess_handler_event)request_process_handler_event)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
         goto fail0;
     }
     
@@ -451,17 +459,9 @@ static int request_init_finished_process (struct request_instance *o)
     // set parameters
     o->process_is_finished = 1;
     
-    // copy arguments
-    NCDValue args;
-    if (!NCDValue_InitCopy(&args, o->args)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail0;
-    }
-    
     // init process
-    if (!NCDModuleProcess_Init(&o->process, o->i, o->finished_handler, args, o, (NCDModuleProcess_handler_event)request_process_handler_event)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        NCDValue_Free(&args);
+    if (!NCDModuleProcess_Init(&o->process, o->i, o->finished_handler, o->args, o, (NCDModuleProcess_handler_event)request_process_handler_event)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
         goto fail0;
     }
     
@@ -476,52 +476,52 @@ fail0:
     return 0;
 }
 
-static int get_connect_addr (struct instance *o, NCDValue *connect_addr_arg, struct NCDRequestClient_addr *out_addr)
+static int get_connect_addr (struct instance *o, NCDValRef connect_addr_arg, struct NCDRequestClient_addr *out_addr)
 {
-    if (NCDValue_Type(connect_addr_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsList(connect_addr_arg)) {
         goto bad;
     }
     
-    if (NCDValue_ListCount(connect_addr_arg) < 1) {
+    if (NCDVal_ListCount(connect_addr_arg) < 1) {
         goto bad;
     }
-    NCDValue *type_arg = NCDValue_ListFirst(connect_addr_arg);
+    NCDValRef type_arg = NCDVal_ListGet(connect_addr_arg, 0);
     
-    if (!NCDValue_IsStringNoNulls(type_arg)) {
+    if (!NCDVal_IsStringNoNulls(type_arg)) {
         goto bad;
     }
-    const char *type = NCDValue_StringValue(type_arg);
+    const char *type = NCDVal_StringValue(type_arg);
     
     if (!strcmp(type, "unix")) {
-        NCDValue *socket_path_arg;
-        if (!NCDValue_ListRead(connect_addr_arg, 2, &type_arg, &socket_path_arg)) {
+        NCDValRef socket_path_arg;
+        if (!NCDVal_ListRead(connect_addr_arg, 2, &type_arg, &socket_path_arg)) {
             goto bad;
         }
         
-        if (!NCDValue_IsStringNoNulls(socket_path_arg)) {
+        if (!NCDVal_IsStringNoNulls(socket_path_arg)) {
             goto bad;
         }
         
-        *out_addr = NCDREQUESTCLIENT_UNIX_ADDR(NCDValue_StringValue(socket_path_arg));
+        *out_addr = NCDREQUESTCLIENT_UNIX_ADDR(NCDVal_StringValue(socket_path_arg));
     }
     else if (!strcmp(type, "tcp")) {
-        NCDValue *ip_address_arg;
-        NCDValue *port_number_arg;
-        if (!NCDValue_ListRead(connect_addr_arg, 3, &type_arg, &ip_address_arg, &port_number_arg)) {
+        NCDValRef ip_address_arg;
+        NCDValRef port_number_arg;
+        if (!NCDVal_ListRead(connect_addr_arg, 3, &type_arg, &ip_address_arg, &port_number_arg)) {
             goto bad;
         }
         
-        if (!NCDValue_IsStringNoNulls(ip_address_arg) || !NCDValue_IsStringNoNulls(port_number_arg)) {
+        if (!NCDVal_IsStringNoNulls(ip_address_arg) || !NCDVal_IsStringNoNulls(port_number_arg)) {
             goto bad;
         }
         
         BIPAddr ipaddr;
-        if (!BIPAddr_Resolve(&ipaddr, NCDValue_StringValue(ip_address_arg), 1)) {
+        if (!BIPAddr_Resolve(&ipaddr, (char *)NCDVal_StringValue(ip_address_arg), 1)) {
             goto bad;
         }
         
         uintmax_t port;
-        if (!parse_unsigned_integer(NCDValue_StringValue(port_number_arg), &port) || port > UINT16_MAX) {
+        if (!parse_unsigned_integer(NCDVal_StringValue(port_number_arg), &port) || port > UINT16_MAX) {
             goto bad;
         }
         
@@ -553,8 +553,8 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // check arguments
-    NCDValue *connect_addr_arg;
-    if (!NCDValue_ListRead(i->args, 1, &connect_addr_arg)) {
+    NCDValRef connect_addr_arg;
+    if (!NCDVal_ListRead(i->args, 1, &connect_addr_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
@@ -629,22 +629,22 @@ static void request_func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // check arguments
-    NCDValue *request_data_arg;
-    NCDValue *reply_handler_arg;
-    NCDValue *finished_handler_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(i->args, 4, &request_data_arg, &reply_handler_arg, &finished_handler_arg, &args_arg)) {
+    NCDValRef request_data_arg;
+    NCDValRef reply_handler_arg;
+    NCDValRef finished_handler_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(i->args, 4, &request_data_arg, &reply_handler_arg, &finished_handler_arg, &args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(reply_handler_arg) || !NCDValue_IsStringNoNulls(finished_handler_arg) ||
-        NCDValue_Type(args_arg) != NCDVALUE_LIST
+    if (!NCDVal_IsStringNoNulls(reply_handler_arg) || !NCDVal_IsStringNoNulls(finished_handler_arg) ||
+        !NCDVal_IsList(args_arg)
     ) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->reply_handler = NCDValue_StringValue(reply_handler_arg);
-    o->finished_handler = NCDValue_StringValue(finished_handler_arg);
+    o->reply_handler = NCDVal_StringValue(reply_handler_arg);
+    o->finished_handler = NCDVal_StringValue(finished_handler_arg);
     o->args = args_arg;
     
     // get client
@@ -657,15 +657,25 @@ static void request_func_new (NCDModuleInst *i)
         goto fail1;
     }
     
+    // convert argument to old format
+    NCDValue request_data_compat;
+    if (!NCDValCompat_ValToValue(request_data_arg, &request_data_compat)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDValCompat_ValToValue failed");
+        goto fail1;
+    }
+    
     // init request
-    if (!NCDRequestClientRequest_Init(&o->request, &client->client, request_data_arg, o,
+    if (!NCDRequestClientRequest_Init(&o->request, &client->client, &request_data_compat, o,
         (NCDRequestClientRequest_handler_sent)request_handler_sent,
         (NCDRequestClientRequest_handler_reply)request_handler_reply,
         (NCDRequestClientRequest_handler_finished)request_handler_finished)) {
         ModuleLog(o->i, BLOG_ERROR, "NCDRequestClientRequest_Init failed");
+        NCDValue_Free(&request_data_compat);
         goto fail1;
     }
     
+    NCDValue_Free(&request_data_compat);
+    
     // add to requests list
     LinkedList0_Prepend(&client->requests_list, &o->requests_list_node);
     

+ 59 - 61
ncd/modules/sys_request_server.c

@@ -103,9 +103,9 @@
 
 struct instance {
     NCDModuleInst *i;
-    char *unix_socket_path;
-    char *request_handler_template;
-    NCDValue *args;
+    const char *unix_socket_path;
+    const char *request_handler_template;
+    NCDValRef args;
     BListener listener;
     LinkedList0 connections_list;
     int dying;
@@ -134,7 +134,8 @@ struct request {
     struct connection *con;
     uint32_t request_id;
     LinkedList0Node requests_list_node;
-    NCDValue request_data;
+    NCDValMem request_data_mem;
+    NCDValRef request_data;
     struct reply *end_reply;
     NCDModuleProcess process;
     int terminating;
@@ -161,13 +162,13 @@ static void request_free (struct request *r);
 static struct request * find_request (struct connection *c, uint32_t request_id);
 static void request_process_handler_event (struct request *r, int event);
 static int request_process_func_getspecialobj (struct request *r, const char *name, NCDObject *out_object);
-static int request_process_request_obj_func_getvar (struct request *r, const char *name, NCDValue *out_value);
+static int request_process_request_obj_func_getvar (struct request *r, const char *name, NCDValMem *mem, NCDValRef *out_value);
 static void request_terminate (struct request *r);
-static struct reply * reply_init (struct connection *c, uint32_t request_id, NCDValue *reply_data);
+static struct reply * reply_init (struct connection *c, uint32_t request_id, NCDValRef reply_data);
 static void reply_start (struct reply *r, uint32_t type);
 static void reply_free (struct reply *r);
 static void reply_send_qflow_if_handler_done (struct reply *r);
-static int init_listen (struct instance *o, NCDValue *listen_addr_arg);
+static int init_listen (struct instance *o, NCDValRef listen_addr_arg);
 static void instance_free (struct instance *o);
 
 static void listener_handler (struct instance *o)
@@ -377,24 +378,19 @@ static int request_init (struct connection *c, uint32_t request_id, const uint8_
     
     LinkedList0_Prepend(&c->requests_list, &r->requests_list_node);
     
-    if (!NCDValueParser_Parse((const char *)data, data_len, &r->request_data)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValueParser_Parse failed");
-        goto fail1;
-    }
+    NCDValMem_Init(&r->request_data_mem);
     
-    if (!(r->end_reply = reply_init(c, request_id, NULL))) {
-        goto fail2;
+    if (!NCDValParser_Parse((const char *)data, data_len, &r->request_data_mem, &r->request_data)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDValParser_Parse failed");
+        goto fail1;
     }
     
-    NCDValue args;
-    if (!NCDValue_InitCopy(&args, o->args)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail3;
+    if (!(r->end_reply = reply_init(c, request_id, NCDVal_NewInvalid()))) {
+        goto fail1;
     }
     
-    if (!NCDModuleProcess_Init(&r->process, o->i, o->request_handler_template, args, r, (NCDModuleProcess_handler_event)request_process_handler_event)) {
+    if (!NCDModuleProcess_Init(&r->process, o->i, o->request_handler_template, o->args, r, (NCDModuleProcess_handler_event)request_process_handler_event)) {
         ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
-        NCDValue_Free(&args);
         goto fail3;
     }
     
@@ -408,9 +404,8 @@ static int request_init (struct connection *c, uint32_t request_id, const uint8_
     
 fail3:
     reply_free(r->end_reply);
-fail2:
-    NCDValue_Free(&r->request_data);
 fail1:
+    NCDValMem_Free(&r->request_data_mem);
     LinkedList0_Remove(&c->requests_list, &r->requests_list_node);
     free(r);
 fail0:
@@ -428,7 +423,7 @@ static void request_free (struct request *r)
     }
     
     NCDModuleProcess_Free(&r->process);
-    NCDValue_Free(&r->request_data);
+    NCDValMem_Free(&r->request_data_mem);
     LinkedList0_Remove(&c->requests_list, &r->requests_list_node);
     free(r);
 }
@@ -490,14 +485,14 @@ static int request_process_func_getspecialobj (struct request *r, const char *na
     return 0;
 }
 
-static int request_process_request_obj_func_getvar (struct request *r, const char *name, NCDValue *out_value)
+static int request_process_request_obj_func_getvar (struct request *r, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = r->con->inst;
     
     if (!strcmp(name, "data")) {
-        if (!NCDValue_InitCopy(out_value, &r->request_data)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-            return 0;
+        *out = NCDVal_NewCopy(mem, r->request_data);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
         }
         return 1;
     }
@@ -513,9 +508,9 @@ static int request_process_request_obj_func_getvar (struct request *r, const cha
                 break;
         }
         
-        if (!NCDValue_InitString(out_value, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         return 1;
     }
@@ -532,9 +527,9 @@ static int request_process_request_obj_func_getvar (struct request *r, const cha
             } break;
         }
         
-        if (!NCDValue_InitString(out_value, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         return 1;
     }
@@ -551,10 +546,11 @@ static void request_terminate (struct request *r)
     r->terminating = 1;
 }
 
-static struct reply * reply_init (struct connection *c, uint32_t request_id, NCDValue *reply_data)
+static struct reply * reply_init (struct connection *c, uint32_t request_id, NCDValRef reply_data)
 {
     struct instance *o = c->inst;
     ASSERT(c->state == CONNECTION_STATE_RUNNING)
+    NCDVal_Assert(reply_data);
     
     struct reply *r = malloc(sizeof(*r));
     if (!r) {
@@ -587,8 +583,8 @@ static struct reply * reply_init (struct connection *c, uint32_t request_id, NCD
         goto fail2;
     }
     
-    if (reply_data && !NCDValueGenerator_AppendGenerate(reply_data, &str)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValueGenerator_AppendGenerate failed");
+    if (!NCDVal_IsInvalid(reply_data) && !NCDValGenerator_AppendGenerate(reply_data, &str)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDValGenerator_AppendGenerate failed");
         goto fail2;
     }
     
@@ -646,36 +642,38 @@ static void reply_send_qflow_if_handler_done (struct reply *r)
     reply_free(r);
 }
 
-static int init_listen (struct instance *o, NCDValue *listen_addr_arg)
+static int init_listen (struct instance *o, NCDValRef listen_addr_arg)
 {
-    if (NCDValue_Type(listen_addr_arg) != NCDVALUE_LIST) {
+    ASSERT(!NCDVal_IsInvalid(listen_addr_arg))
+    
+    if (!NCDVal_IsList(listen_addr_arg)) {
         goto bad;
     }
     
-    if (NCDValue_ListCount(listen_addr_arg) < 1) {
+    if (NCDVal_ListCount(listen_addr_arg) < 1) {
         goto bad;
     }
-    NCDValue *type_arg = NCDValue_ListFirst(listen_addr_arg);
+    NCDValRef type_arg = NCDVal_ListGet(listen_addr_arg, 0);
     
-    if (!NCDValue_IsStringNoNulls(type_arg)) {
+    if (!NCDVal_IsStringNoNulls(type_arg)) {
         goto bad;
     }
-    const char *type = NCDValue_StringValue(type_arg);
+    const char *type = NCDVal_StringValue(type_arg);
     
     o->unix_socket_path = NULL;
     
     if (!strcmp(type, "unix")) {
-        NCDValue *socket_path_arg;
-        if (!NCDValue_ListRead(listen_addr_arg, 2, &type_arg, &socket_path_arg)) {
+        NCDValRef socket_path_arg;
+        if (!NCDVal_ListRead(listen_addr_arg, 2, &type_arg, &socket_path_arg)) {
             goto bad;
         }
         
-        if (!NCDValue_IsStringNoNulls(socket_path_arg)) {
+        if (!NCDVal_IsStringNoNulls(socket_path_arg)) {
             goto bad;
         }
         
         // remember socket path
-        o->unix_socket_path = NCDValue_StringValue(socket_path_arg);
+        o->unix_socket_path = NCDVal_StringValue(socket_path_arg);
         
         // make sure socket file doesn't exist
         if (unlink(o->unix_socket_path) < 0 && errno != ENOENT) {
@@ -690,23 +688,23 @@ static int init_listen (struct instance *o, NCDValue *listen_addr_arg)
         }
     }
     else if (!strcmp(type, "tcp")) {
-        NCDValue *ip_address_arg;
-        NCDValue *port_number_arg;
-        if (!NCDValue_ListRead(listen_addr_arg, 3, &type_arg, &ip_address_arg, &port_number_arg)) {
+        NCDValRef ip_address_arg;
+        NCDValRef port_number_arg;
+        if (!NCDVal_ListRead(listen_addr_arg, 3, &type_arg, &ip_address_arg, &port_number_arg)) {
             goto bad;
         }
         
-        if (!NCDValue_IsStringNoNulls(ip_address_arg) || !NCDValue_IsStringNoNulls(port_number_arg)) {
+        if (!NCDVal_IsStringNoNulls(ip_address_arg) || !NCDVal_IsStringNoNulls(port_number_arg)) {
             goto bad;
         }
         
         BIPAddr ipaddr;
-        if (!BIPAddr_Resolve(&ipaddr, NCDValue_StringValue(ip_address_arg), 1)) {
+        if (!BIPAddr_Resolve(&ipaddr, (char *)NCDVal_StringValue(ip_address_arg), 1)) {
             goto bad;
         }
         
         uintmax_t port;
-        if (!parse_unsigned_integer(NCDValue_StringValue(port_number_arg), &port) || port > UINT16_MAX) {
+        if (!parse_unsigned_integer(NCDVal_StringValue(port_number_arg), &port) || port > UINT16_MAX) {
             goto bad;
         }
         
@@ -715,7 +713,7 @@ static int init_listen (struct instance *o, NCDValue *listen_addr_arg)
         
         // init listener
         if (!BListener_Init(&o->listener, addr, o->i->iparams->reactor, o, (BListener_handler)listener_handler)) {
-            ModuleLog(o->i, BLOG_ERROR, "BListener_InitUnix failed");
+            ModuleLog(o->i, BLOG_ERROR, "BListener_Init failed");
             return 0;
         }
     }
@@ -742,18 +740,18 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // check arguments
-    NCDValue *listen_addr_arg;
-    NCDValue *request_handler_template_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(i->args, 3, &listen_addr_arg, &request_handler_template_arg, &args_arg)) {
+    NCDValRef listen_addr_arg;
+    NCDValRef request_handler_template_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(i->args, 3, &listen_addr_arg, &request_handler_template_arg, &args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(request_handler_template_arg) || NCDValue_Type(args_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsStringNoNulls(request_handler_template_arg) || !NCDVal_IsList(args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->request_handler_template = NCDValue_StringValue(request_handler_template_arg);
+    o->request_handler_template = NCDVal_StringValue(request_handler_template_arg);
     o->args = args_arg;
     
     // init listener
@@ -829,8 +827,8 @@ static void func_die (void *vo)
 
 static void reply_func_new (NCDModuleInst *i)
 {
-    NCDValue *reply_data;
-    if (!NCDValue_ListRead(i->args, 1, &reply_data)) {
+    NCDValRef reply_data;
+    if (!NCDVal_ListRead(i->args, 1, &reply_data)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail;
     }
@@ -861,7 +859,7 @@ fail:
 
 static void finish_func_new (NCDModuleInst *i)
 {
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail;
     }

+ 21 - 21
ncd/modules/sys_watch_directory.c

@@ -64,7 +64,7 @@
 
 struct instance {
     NCDModuleInst *i;
-    char *dir;
+    const char *dir;
     DIR *dir_handle;
     int inotify_fd;
     BFileDescriptor bfd;
@@ -244,16 +244,16 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    NCDValue *dir_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &dir_arg)) {
+    NCDValRef dir_arg;
+    if (!NCDVal_ListRead(o->i->args, 1, &dir_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(dir_arg)) {
+    if (!NCDVal_IsStringNoNulls(dir_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->dir = NCDValue_StringValue(dir_arg);
+    o->dir = NCDVal_StringValue(dir_arg);
     
     // open inotify
     if ((o->inotify_fd = inotify_init()) < 0) {
@@ -337,26 +337,24 @@ static void func_die (void *vo)
     instance_free(o, 0);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     ASSERT(o->processing)
     
     if (!strcmp(name, "event_type")) {
-        if (!NCDValue_InitString(out, o->processing_type)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, o->processing_type);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
     if (!strcmp(name, "filename")) {
-        if (!NCDValue_InitString(out, o->processing_file)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, o->processing_file);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
-        
         return 1;
     }
     
@@ -364,27 +362,29 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
         char *str = concat_strings(3, o->dir, "/", o->processing_file);
         if (!str) {
             ModuleLog(o->i, BLOG_ERROR, "concat_strings failed");
-            return 0;
+            goto fail;
         }
         
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            free(str);
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         
         free(str);
-        
         return 1;
     }
     
     return 0;
+    
+fail:
+    *out = NCDVal_NewInvalid();
+    return 1;
 }
 
 static void nextevent_func_new (NCDModuleInst *i)
 {
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }

+ 8 - 8
ncd/modules/sys_watch_input.c

@@ -70,7 +70,7 @@ struct device {
 
 struct instance {
     NCDModuleInst *i;
-    char *devnode_type;
+    const char *devnode_type;
     NCDUdevClient client;
     LinkedList1 devices_list;
     event_template templ;
@@ -356,16 +356,16 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    NCDValue *devnode_type_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &devnode_type_arg)) {
+    NCDValRef devnode_type_arg;
+    if (!NCDVal_ListRead(o->i->args, 1, &devnode_type_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(devnode_type_arg)) {
+    if (!NCDVal_IsStringNoNulls(devnode_type_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    o->devnode_type = NCDValue_StringValue(devnode_type_arg);
+    o->devnode_type = NCDVal_StringValue(devnode_type_arg);
     
     // init client
     NCDUdevClient_Init(&o->client, o->i->iparams->umanager, o, (NCDUdevClient_handler)client_handler);
@@ -409,16 +409,16 @@ static void func_die (void *vo)
     event_template_die(&o->templ);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
-    return event_template_getvar(&o->templ, name, out);
+    return event_template_getvar(&o->templ, name, mem, out);
 }
 
 static void nextevent_func_new (NCDModuleInst *i)
 {
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }

+ 4 - 4
ncd/modules/sys_watch_usb.c

@@ -331,7 +331,7 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
@@ -377,16 +377,16 @@ static void func_die (void *vo)
     event_template_die(&o->templ);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
-    return event_template_getvar(&o->templ, name, out);
+    return event_template_getvar(&o->templ, name, mem, out);
 }
 
 static void nextevent_func_new (NCDModuleInst *i)
 {
     // check arguments
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }

+ 8 - 8
ncd/modules/to_string.c

@@ -61,15 +61,15 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // read arguments
-    NCDValue *value_arg;
-    if (!NCDValue_ListRead(i->args, 1, &value_arg)) {
+    NCDValRef value_arg;
+    if (!NCDVal_ListRead(i->args, 1, &value_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
     
     // convert to string
-    if (!(o->str = NCDValueGenerator_Generate(value_arg))) {
-        ModuleLog(i, BLOG_ERROR, "NCDValueGenerator_Generate failed");
+    if (!(o->str = NCDValGenerator_Generate(value_arg))) {
+        ModuleLog(i, BLOG_ERROR, "NCDValGenerator_Generate failed");
         goto fail1;
     }
     
@@ -98,14 +98,14 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitString(out, o->str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, o->str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         return 1;
     }

+ 15 - 22
ncd/modules/try.c

@@ -168,29 +168,21 @@ static void func_new (NCDModuleInst *i)
     NCDModuleInst_Backend_SetUser(i, o);
     
     // check arguments
-    NCDValue *template_name_arg;
-    NCDValue *args_arg;
-    if (!NCDValue_ListRead(i->args, 2, &template_name_arg, &args_arg)) {
+    NCDValRef template_name_arg;
+    NCDValRef args_arg;
+    if (!NCDVal_ListRead(i->args, 2, &template_name_arg, &args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (!NCDValue_IsStringNoNulls(template_name_arg) || NCDValue_Type(args_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsStringNoNulls(template_name_arg) || !NCDVal_IsList(args_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
-    char *template_name = NCDValue_StringValue(template_name_arg);
-    
-    // copy arguments
-    NCDValue args;
-    if (!NCDValue_InitCopy(&args, args_arg)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail1;
-    }
+    const char *template_name = NCDVal_StringValue(template_name_arg);
     
     // start process
-    if (!NCDModuleProcess_Init(&o->process, i, template_name, args, o, (NCDModuleProcess_handler_event)process_handler_event)) {
+    if (!NCDModuleProcess_Init(&o->process, i, template_name, args_arg, o, (NCDModuleProcess_handler_event)process_handler_event)) {
         ModuleLog(o->i, BLOG_ERROR, "NCDModuleProcess_Init failed");
-        NCDValue_Free(&args);
         goto fail1;
     }
     
@@ -240,7 +232,7 @@ static void func_die (void *vo)
     }
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     ASSERT(o->state == STATE_FINISHED)
@@ -248,9 +240,10 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
     
     if (!strcmp(name, "succeeded")) {
         const char *str = (o->succeeded ? "true" : "false");
-        if (!NCDValue_InitString(out, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         return 1;
     }
@@ -261,12 +254,12 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
 static void assert_func_new (NCDModuleInst *i)
 {
     // check arguments
-    NCDValue *cond_arg;
-    if (!NCDValue_ListRead(i->args, 1, &cond_arg)) {
+    NCDValRef cond_arg;
+    if (!NCDVal_ListRead(i->args, 1, &cond_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
-    if (NCDValue_Type(cond_arg) != NCDVALUE_STRING) {
+    if (!NCDVal_IsString(cond_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail1;
     }
@@ -278,7 +271,7 @@ static void assert_func_new (NCDModuleInst *i)
     // signal up
     NCDModuleInst_Backend_Up(i);
     
-    if (!NCDValue_StringEquals(cond_arg, "true")) {
+    if (!NCDVal_StringEquals(cond_arg, "true")) {
         // mark not succeeded
         mo->succeeded = 0;
         

+ 216 - 206
ncd/modules/value.c

@@ -154,7 +154,8 @@ struct value {
             IndexedListNode list_contents_il_node;
         } list_parent;
         struct {
-            NCDValue key;
+            NCDValMem key_mem;
+            NCDValRef key;
             BCountAVLNode map_contents_tree_node;
         } map_parent;
     };
@@ -174,7 +175,7 @@ struct value {
     };
 };
 
-static int ncdvalue_comparator (void *unused, void *vv1, void *vv2);
+static int ncdval_comparator (void *unused, void *vv1, void *vv2);
 static const char * get_type_str (int type);
 static void value_cleanup (struct value *v);
 static void value_delete (struct value *v);
@@ -188,35 +189,35 @@ static void value_list_remove (struct value *list, struct value *v);
 static struct value * value_init_map (NCDModuleInst *i);
 static size_t value_map_len (struct value *map);
 static struct value * value_map_at (struct value *map, size_t index);
-static struct value * value_map_find (struct value *map, NCDValue *key);
-static int value_map_insert (struct value *map, struct value *v, NCDValue key, NCDModuleInst *i);
+static struct value * value_map_find (struct value *map, NCDValRef key);
+static int value_map_insert (struct value *map, struct value *v, NCDValMem mem, NCDValSafeRef key, NCDModuleInst *i);
 static void value_map_remove (struct value *map, struct value *v);
-static void value_map_remove2 (struct value *map, struct value *v, NCDValue *out_key);
-static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValue *value);
-static int value_to_value (NCDModuleInst *i, struct value *v, NCDValue *out_value);
-static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValue *where, int no_error);
-static struct value * value_get_path (NCDModuleInst *i, struct value *v, NCDValue *path);
-static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValue *where, NCDValue *what, struct value **out_oldv);
-static int value_remove (NCDModuleInst *i, struct value *v, NCDValue *where);
+static void value_map_remove2 (struct value *map, struct value *v, NCDValMem *out_mem, NCDValSafeRef *out_key);
+static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValRef value);
+static int value_to_value (NCDModuleInst *i, struct value *v, NCDValMem *mem, NCDValRef *out_value);
+static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValRef where, int no_error);
+static struct value * value_get_path (NCDModuleInst *i, struct value *v, NCDValRef path);
+static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValRef where, NCDValRef what, struct value **out_oldv);
+static int value_remove (NCDModuleInst *i, struct value *v, NCDValRef where);
 static void valref_init (struct valref *r, struct value *v);
 static void valref_free (struct valref *r);
 static struct value * valref_val (struct valref *r);
 static void valref_break (struct valref *r);
 
-static int ncdvalue_comparator (void *unused, void *vv1, void *vv2)
+static int ncdval_comparator (void *unused, void *vv1, void *vv2)
 {
-    NCDValue *v1 = vv1;
-    NCDValue *v2 = vv2;
+    NCDValRef *v1 = vv1;
+    NCDValRef *v2 = vv2;
     
-    return NCDValue_Compare(v1, v2);
+    return NCDVal_Compare(*v1, *v2);
 }
 
 static const char * get_type_str (int type)
 {
     switch (type) {
-        case NCDVALUE_STRING: return "string";
-        case NCDVALUE_LIST: return "list";
-        case NCDVALUE_MAP: return "map";
+        case NCDVAL_STRING: return "string";
+        case NCDVAL_LIST: return "list";
+        case NCDVAL_MAP: return "map";
     }
     ASSERT(0)
     return NULL;
@@ -229,11 +230,11 @@ static void value_cleanup (struct value *v)
     }
     
     switch (v->type) {
-        case NCDVALUE_STRING: {
+        case NCDVAL_STRING: {
             free(v->string.string);
         } break;
         
-        case NCDVALUE_LIST: {
+        case NCDVAL_LIST: {
             while (value_list_len(v) > 0) {
                 struct value *ev = value_list_at(v, 0);
                 value_list_remove(v, ev);
@@ -241,7 +242,7 @@ static void value_cleanup (struct value *v)
             }
         } break;
         
-        case NCDVALUE_MAP: {
+        case NCDVAL_MAP: {
             while (value_map_len(v) > 0) {
                 struct value *ev = value_map_at(v, 0);
                 value_map_remove(v, ev);
@@ -259,10 +260,10 @@ static void value_delete (struct value *v)
 {
     if (v->parent) {
         switch (v->parent->type) {
-            case NCDVALUE_LIST: {
+            case NCDVAL_LIST: {
                 value_list_remove(v->parent, v);
             } break;
-            case NCDVALUE_MAP: {
+            case NCDVAL_MAP: {
                 value_map_remove(v->parent, v);
             } break;
             default: ASSERT(0);
@@ -277,18 +278,18 @@ static void value_delete (struct value *v)
     }
     
     switch (v->type) {
-        case NCDVALUE_STRING: {
+        case NCDVAL_STRING: {
             free(v->string.string);
         } break;
         
-        case NCDVALUE_LIST: {
+        case NCDVAL_LIST: {
             while (value_list_len(v) > 0) {
                 struct value *ev = value_list_at(v, 0);
                 value_delete(ev);
             }
         } break;
         
-        case NCDVALUE_MAP: {
+        case NCDVAL_MAP: {
             while (value_map_len(v) > 0) {
                 struct value *ev = value_map_at(v, 0);
                 value_delete(ev);
@@ -311,7 +312,7 @@ static struct value * value_init_string (NCDModuleInst *i, const uint8_t *str, s
     
     LinkedList0_Init(&v->refs_list);
     v->parent = NULL;
-    v->type = NCDVALUE_STRING;
+    v->type = NCDVAL_STRING;
     
     if (!(v->string.string = malloc(len))) {
         ModuleLog(i, BLOG_ERROR, "malloc failed");
@@ -340,7 +341,7 @@ static struct value * value_init_list (NCDModuleInst *i)
     
     LinkedList0_Init(&v->refs_list);
     v->parent = NULL;
-    v->type = NCDVALUE_LIST;
+    v->type = NCDVAL_LIST;
     
     IndexedList_Init(&v->list.list_contents_il);
     
@@ -349,14 +350,14 @@ static struct value * value_init_list (NCDModuleInst *i)
 
 static size_t value_list_len (struct value *v)
 {
-    ASSERT(v->type == NCDVALUE_LIST)
+    ASSERT(v->type == NCDVAL_LIST)
     
     return IndexedList_Count(&v->list.list_contents_il);
 }
 
 static struct value * value_list_at (struct value *v, size_t index)
 {
-    ASSERT(v->type == NCDVALUE_LIST)
+    ASSERT(v->type == NCDVAL_LIST)
     ASSERT(index < value_list_len(v))
     
     IndexedListNode *iln = IndexedList_GetAt(&v->list.list_contents_il, index);
@@ -370,7 +371,7 @@ static struct value * value_list_at (struct value *v, size_t index)
 
 static size_t value_list_indexof (struct value *v, struct value *ev)
 {
-    ASSERT(v->type == NCDVALUE_LIST)
+    ASSERT(v->type == NCDVAL_LIST)
     ASSERT(ev->parent == v)
     
     uint64_t index = IndexedList_IndexOf(&v->list.list_contents_il, &ev->list_parent.list_contents_il_node);
@@ -381,7 +382,7 @@ static size_t value_list_indexof (struct value *v, struct value *ev)
 
 static int value_list_insert (NCDModuleInst *i, struct value *list, struct value *v, size_t index)
 {
-    ASSERT(list->type == NCDVALUE_LIST)
+    ASSERT(list->type == NCDVAL_LIST)
     ASSERT(!v->parent)
     ASSERT(index <= value_list_len(list))
     
@@ -398,7 +399,7 @@ static int value_list_insert (NCDModuleInst *i, struct value *list, struct value
 
 static void value_list_remove (struct value *list, struct value *v)
 {
-    ASSERT(list->type == NCDVALUE_LIST)
+    ASSERT(list->type == NCDVAL_LIST)
     ASSERT(v->parent == list)
     
     IndexedList_Remove(&list->list.list_contents_il, &v->list_parent.list_contents_il_node);
@@ -415,23 +416,23 @@ static struct value * value_init_map (NCDModuleInst *i)
     
     LinkedList0_Init(&v->refs_list);
     v->parent = NULL;
-    v->type = NCDVALUE_MAP;
+    v->type = NCDVAL_MAP;
     
-    BCountAVL_Init(&v->map.map_contents_tree, OFFSET_DIFF(struct value, map_parent.key, map_parent.map_contents_tree_node), ncdvalue_comparator, NULL);
+    BCountAVL_Init(&v->map.map_contents_tree, OFFSET_DIFF(struct value, map_parent.key, map_parent.map_contents_tree_node), ncdval_comparator, NULL);
     
     return v;
 }
 
 static size_t value_map_len (struct value *map)
 {
-    ASSERT(map->type == NCDVALUE_MAP)
+    ASSERT(map->type == NCDVAL_MAP)
     
     return BCountAVL_Count(&map->map.map_contents_tree);
 }
 
 static struct value * value_map_at (struct value *map, size_t index)
 {
-    ASSERT(map->type == NCDVALUE_MAP)
+    ASSERT(map->type == NCDVAL_MAP)
     ASSERT(index < value_map_len(map))
     
     BCountAVLNode *tn = BCountAVL_GetAt(&map->map.map_contents_tree, index);
@@ -443,12 +444,12 @@ static struct value * value_map_at (struct value *map, size_t index)
     return e;
 }
 
-static struct value * value_map_find (struct value *map, NCDValue *key)
+static struct value * value_map_find (struct value *map, NCDValRef key)
 {
-    ASSERT(map->type == NCDVALUE_MAP)
-    ASSERT(key)
+    ASSERT(map->type == NCDVAL_MAP)
+    ASSERT(NCDVal_Type(key))
     
-    BCountAVLNode *tn = BCountAVL_LookupExact(&map->map.map_contents_tree, key);
+    BCountAVLNode *tn = BCountAVL_LookupExact(&map->map.map_contents_tree, &key);
     if (!tn) {
         return NULL;
     }
@@ -459,18 +460,20 @@ static struct value * value_map_find (struct value *map, NCDValue *key)
     return e;
 }
 
-static int value_map_insert (struct value *map, struct value *v, NCDValue key, NCDModuleInst *i)
+static int value_map_insert (struct value *map, struct value *v, NCDValMem mem, NCDValSafeRef key, NCDModuleInst *i)
 {
-    ASSERT(map->type == NCDVALUE_MAP)
+    ASSERT(map->type == NCDVAL_MAP)
     ASSERT(!v->parent)
-    ASSERT(!value_map_find(map, &key))
+    ASSERT((NCDVal_Type(NCDVal_FromSafe(&mem, key)), 1))
+    ASSERT(!value_map_find(map, NCDVal_FromSafe(&mem, key)))
     
     if (value_map_len(map) == SIZE_MAX) {
         ModuleLog(i, BLOG_ERROR, "map has too many elements");
         return 0;
     }
     
-    v->map_parent.key = key;
+    v->map_parent.key_mem = mem;
+    v->map_parent.key = NCDVal_FromSafe(&v->map_parent.key_mem, key);
     int res = BCountAVL_Insert(&map->map.map_contents_tree, &v->map_parent.map_contents_tree_node, NULL);
     ASSERT(res)
     v->parent = map;
@@ -480,43 +483,49 @@ static int value_map_insert (struct value *map, struct value *v, NCDValue key, N
 
 static void value_map_remove (struct value *map, struct value *v)
 {
-    ASSERT(map->type == NCDVALUE_MAP)
+    ASSERT(map->type == NCDVAL_MAP)
     ASSERT(v->parent == map)
     
     BCountAVL_Remove(&map->map.map_contents_tree, &v->map_parent.map_contents_tree_node);
-    NCDValue_Free(&v->map_parent.key);
+    NCDValMem_Free(&v->map_parent.key_mem);
     v->parent = NULL;
 }
 
-static void value_map_remove2 (struct value *map, struct value *v, NCDValue *out_key)
+static void value_map_remove2 (struct value *map, struct value *v, NCDValMem *out_mem, NCDValSafeRef *out_key)
 {
-    ASSERT(map->type == NCDVALUE_MAP)
+    ASSERT(map->type == NCDVAL_MAP)
     ASSERT(v->parent == map)
+    ASSERT(out_mem)
     ASSERT(out_key)
     
     BCountAVL_Remove(&map->map.map_contents_tree, &v->map_parent.map_contents_tree_node);
-    *out_key = v->map_parent.key;
+    *out_mem = v->map_parent.key_mem;
+    *out_key = NCDVal_ToSafe(v->map_parent.key);
     v->parent = NULL;
 }
 
-static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValue *value)
+static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValRef value)
 {
+    ASSERT((NCDVal_Type(value), 1))
+    
     struct value *v;
     
-    switch (NCDValue_Type(value)) {
-        case NCDVALUE_STRING: {
-            if (!(v = value_init_string(i, (const uint8_t *)NCDValue_StringValue(value), NCDValue_StringLength(value)))) {
+    switch (NCDVal_Type(value)) {
+        case NCDVAL_STRING: {
+            if (!(v = value_init_string(i, (const uint8_t *)NCDVal_StringValue(value), NCDVal_StringLength(value)))) {
                 goto fail0;
             }
         } break;
         
-        case NCDVALUE_LIST: {
+        case NCDVAL_LIST: {
             if (!(v = value_init_list(i))) {
                 goto fail0;
             }
             
-            for (NCDValue *eval = NCDValue_ListFirst(value); eval; eval = NCDValue_ListNext(value, eval)) {
-                struct value *ev = value_init_fromvalue(i, eval);
+            size_t count = NCDVal_ListCount(value);
+            
+            for (size_t j = 0; j < count; j++) {
+                struct value *ev = value_init_fromvalue(i, NCDVal_ListGet(value, j));
                 if (!ev) {
                     goto fail1;
                 }
@@ -528,28 +537,33 @@ static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValue *value)
             }
         } break;
         
-        case NCDVALUE_MAP: {
+        case NCDVAL_MAP: {
             if (!(v = value_init_map(i))) {
                 goto fail0;
             }
             
-            for (NCDValue *ekey = NCDValue_MapFirstKey(value); ekey; ekey = NCDValue_MapNextKey(value, ekey)) {
-                NCDValue *eval = NCDValue_MapKeyValue(value, ekey);
+            for (NCDValMapElem e = NCDVal_MapFirst(value); !NCDVal_MapElemInvalid(e); e = NCDVal_MapNext(value, e)) {
+                NCDValRef ekey = NCDVal_MapElemKey(value, e);
+                NCDValRef eval = NCDVal_MapElemVal(value, e);
+                
+                NCDValMem key_mem;
+                NCDValMem_Init(&key_mem);
                 
-                NCDValue key;
-                if (!NCDValue_InitCopy(&key, ekey)) {
-                    BLog(BLOG_ERROR, "NCDValue_InitCopy failed");
+                NCDValRef key = NCDVal_NewCopy(&key_mem, ekey);
+                if (NCDVal_IsInvalid(key)) {
+                    BLog(BLOG_ERROR, "NCDVal_NewCopy failed");
+                    NCDValMem_Free(&key_mem);
                     goto fail1;
                 }
                 
                 struct value *ev = value_init_fromvalue(i, eval);
                 if (!ev) {
-                    NCDValue_Free(&key);
+                    NCDValMem_Free(&key_mem);
                     goto fail1;
                 }
                 
-                if (!value_map_insert(v, ev, key, i)) {
-                    NCDValue_Free(&key);
+                if (!value_map_insert(v, ev, key_mem, NCDVal_ToSafe(key), i)) {
+                    NCDValMem_Free(&key_mem);
                     value_cleanup(ev);
                     goto fail1;
                 }
@@ -567,58 +581,60 @@ fail0:
     return NULL;
 }
 
-static int value_to_value (NCDModuleInst *i, struct value *v, NCDValue *out_value)
+static int value_to_value (NCDModuleInst *i, struct value *v, NCDValMem *mem, NCDValRef *out_value)
 {
+    ASSERT(mem)
+    ASSERT(out_value)
+    
     switch (v->type) {
-        case NCDVALUE_STRING: {
-            if (!(NCDValue_InitStringBin(out_value, v->string.string, v->string.length))) {
-                ModuleLog(i, BLOG_ERROR, "NCDValue_InitStringBin failed");
-                goto fail0;
+        case NCDVAL_STRING: {
+            *out_value = NCDVal_NewStringBin(mem, v->string.string, v->string.length);
+            if (NCDVal_IsInvalid(*out_value)) {
+                ModuleLog(i, BLOG_ERROR, "NCDVal_NewStringBin failed");
+                goto fail;
             }
         } break;
         
-        case NCDVALUE_LIST: {
-            NCDValue_InitList(out_value);
+        case NCDVAL_LIST: {
+            *out_value = NCDVal_NewList(mem, value_list_len(v));
+            if (NCDVal_IsInvalid(*out_value)) {
+                ModuleLog(i, BLOG_ERROR, "NCDVal_NewList failed");
+                goto fail;
+            }
             
             for (size_t index = 0; index < value_list_len(v); index++) {
-                NCDValue eval;
-                if (!value_to_value(i, value_list_at(v, index), &eval)) {
-                    goto fail1;
+                NCDValRef eval;
+                if (!value_to_value(i, value_list_at(v, index), mem, &eval)) {
+                    goto fail;
                 }
                 
-                if (!NCDValue_ListAppend(out_value, eval)) {
-                    ModuleLog(i, BLOG_ERROR, "NCDValue_ListAppend failed");
-                    NCDValue_Free(&eval);
-                    goto fail1;
-                }
+                NCDVal_ListAppend(*out_value, eval);
             }
         } break;
         
-        case NCDVALUE_MAP: {
-            NCDValue_InitMap(out_value);
+        case NCDVAL_MAP: {
+            *out_value = NCDVal_NewMap(mem, value_map_len(v));
+            if (NCDVal_IsInvalid(*out_value)) {
+                ModuleLog(i, BLOG_ERROR, "NCDVal_NewMap failed");
+                goto fail;
+            }
             
             for (size_t index = 0; index < value_map_len(v); index++) {
                 struct value *ev = value_map_at(v, index);
                 
-                NCDValue key;
-                NCDValue val;
-                
-                if (!NCDValue_InitCopy(&key, &ev->map_parent.key)) {
-                    ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
-                    goto fail1;
+                NCDValRef key = NCDVal_NewCopy(mem, ev->map_parent.key);
+                if (NCDVal_IsInvalid(key)) {
+                    ModuleLog(i, BLOG_ERROR, "NCDVal_NewCopy failed");
+                    goto fail;
                 }
                 
-                if (!value_to_value(i, ev, &val)) {
-                    NCDValue_Free(&key);
-                    goto fail1;
+                NCDValRef val;
+                if (!value_to_value(i, ev, mem, &val)) {
+                    goto fail;
                 }
                 
-                if (!NCDValue_MapInsert(out_value, key, val)) {
-                    ModuleLog(i, BLOG_ERROR, "NCDValue_MapInsert failed");
-                    NCDValue_Free(&key);
-                    NCDValue_Free(&val);
-                    goto fail1;
-                }
+                int res = NCDVal_MapInsert(*out_value, key, val);
+                ASSERT(res)
             }
         } break;
         
@@ -627,28 +643,23 @@ static int value_to_value (NCDModuleInst *i, struct value *v, NCDValue *out_valu
     
     return 1;
     
-fail1:
-    NCDValue_Free(out_value);
-fail0:
+fail:
     return 0;
 }
 
-static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValue *where, int no_error)
+static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValRef where, int no_error)
 {
+    ASSERT((NCDVal_Type(where), 1))
+    
     switch (v->type) {
-        case NCDVALUE_STRING: {
+        case NCDVAL_STRING: {
             if (!no_error) ModuleLog(i, BLOG_ERROR, "cannot resolve into a string");
             goto fail;
         } break;
         
-        case NCDVALUE_LIST: {
-            if (NCDValue_Type(where) != NCDVALUE_STRING) {
-                if (!no_error) ModuleLog(i, BLOG_ERROR, "index is not a string (resolving into list)");
-                goto fail;
-            }
-            
+        case NCDVAL_LIST: {
             uintmax_t index;
-            if (NCDValue_StringHasNulls(where) || !parse_unsigned_integer(NCDValue_StringValue(where), &index)) {
+            if (!NCDVal_IsStringNoNulls(where) || !parse_unsigned_integer(NCDVal_StringValue(where), &index)) {
                 if (!no_error) ModuleLog(i, BLOG_ERROR, "index is not a valid number (resolving into list)");
                 goto fail;
             }
@@ -661,7 +672,7 @@ static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValue *wh
             v = value_list_at(v, index);
         } break;
         
-        case NCDVALUE_MAP: {
+        case NCDVAL_MAP: {
             v = value_map_find(v, where);
             if (!v) {
                 if (!no_error) ModuleLog(i, BLOG_ERROR, "key does not exist (resolving into map)");
@@ -678,12 +689,14 @@ fail:
     return NULL;
 }
 
-static struct value * value_get_path (NCDModuleInst *i, struct value *v, NCDValue *path)
+static struct value * value_get_path (NCDModuleInst *i, struct value *v, NCDValRef path)
 {
-    ASSERT(NCDValue_Type(path) == NCDVALUE_LIST)
+    ASSERT(NCDVal_IsList(path))
     
-    for (NCDValue *ev = NCDValue_ListFirst(path); ev; ev = NCDValue_ListNext(path, ev)) {
-        if (!(v = value_get(i, v, ev, 0))) {
+    size_t count = NCDVal_ListCount(path);
+    
+    for (size_t j = 0; j < count; j++) {
+        if (!(v = value_get(i, v, NCDVal_ListGet(path, j), 0))) {
             goto fail;
         }
     }
@@ -694,11 +707,11 @@ fail:
     return NULL;
 }
 
-static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValue *where, NCDValue *what, struct value **out_oldv)
+static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValRef where, NCDValRef what, struct value **out_oldv)
 {
     ASSERT(v)
-    NCDValue_Type(where);
-    NCDValue_Type(what);
+    ASSERT((NCDVal_Type(where), 1))
+    ASSERT((NCDVal_Type(what), 1))
     
     struct value *nv = value_init_fromvalue(i, what);
     if (!nv) {
@@ -708,19 +721,14 @@ static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValue
     struct value *oldv = NULL;
     
     switch (v->type) {
-        case NCDVALUE_STRING: {
+        case NCDVAL_STRING: {
             ModuleLog(i, BLOG_ERROR, "cannot insert into a string");
             goto fail1;
         } break;
         
-        case NCDVALUE_LIST: {
-            if (NCDValue_Type(where) != NCDVALUE_STRING) {
-                ModuleLog(i, BLOG_ERROR, "index is not a string (inserting into list)");
-                goto fail1;
-            }
-            
+        case NCDVAL_LIST: {
             uintmax_t index;
-            if (NCDValue_StringHasNulls(where) || !parse_unsigned_integer(NCDValue_StringValue(where), &index)) {
+            if (!NCDVal_IsStringNoNulls(where) || !parse_unsigned_integer(NCDVal_StringValue(where), &index)) {
                 ModuleLog(i, BLOG_ERROR, "index is not a valid number (inserting into list)");
                 goto fail1;
             }
@@ -735,7 +743,7 @@ static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValue
             }
         } break;
         
-        case NCDVALUE_MAP: {
+        case NCDVAL_MAP: {
             oldv = value_map_find(v, where);
             
             if (!oldv && value_map_len(v) == SIZE_MAX) {
@@ -743,9 +751,13 @@ static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValue
                 goto fail1;
             }
             
-            NCDValue key;
-            if (!NCDValue_InitCopy(&key, where)) {
-                ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
+            NCDValMem key_mem;
+            NCDValMem_Init(&key_mem);
+            
+            NCDValRef key = NCDVal_NewCopy(&key_mem, where);
+            if (NCDVal_IsInvalid(key)) {
+                ModuleLog(i, BLOG_ERROR, "NCDVal_NewCopy failed");
+                NCDValMem_Free(&key_mem);
                 goto fail1;
             }
             
@@ -753,7 +765,7 @@ static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValue
                 value_map_remove(v, oldv);
             }
             
-            int res = value_map_insert(v, nv, key, i);
+            int res = value_map_insert(v, nv, key_mem, NCDVal_ToSafe(key), i);
             ASSERT(res)
         } break;
         
@@ -775,22 +787,20 @@ fail0:
     return NULL;
 }
 
-static int value_remove (NCDModuleInst *i, struct value *v, NCDValue *where)
+static int value_remove (NCDModuleInst *i, struct value *v, NCDValRef where)
 {
+    ASSERT(v)
+    ASSERT((NCDVal_Type(where), 1))
+    
     switch (v->type) {
-        case NCDVALUE_STRING: {
+        case NCDVAL_STRING: {
             ModuleLog(i, BLOG_ERROR, "cannot remove from a string");
             goto fail;
         } break;
         
-        case NCDVALUE_LIST: {
-            if (NCDValue_Type(where) != NCDVALUE_STRING) {
-                ModuleLog(i, BLOG_ERROR, "index is not a string (removing from list)");
-                goto fail;
-            }
-            
+        case NCDVAL_LIST: {
             uintmax_t index;
-            if (NCDValue_StringHasNulls(where) || !parse_unsigned_integer(NCDValue_StringValue(where), &index)) {
+            if (!NCDVal_IsStringNoNulls(where) || !parse_unsigned_integer(NCDVal_StringValue(where), &index)) {
                 ModuleLog(i, BLOG_ERROR, "index is not a valid number (removing from list)");
                 goto fail;
             }
@@ -806,7 +816,7 @@ static int value_remove (NCDModuleInst *i, struct value *v, NCDValue *where)
             value_cleanup(ov);
         } break;
         
-        case NCDVALUE_MAP: {
+        case NCDVAL_MAP: {
             struct value *ov = value_map_find(v, where);
             if (!ov) {
                 ModuleLog(i, BLOG_ERROR, "key does not exist (removing from map)");
@@ -905,16 +915,16 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out_value)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     struct value *v = valref_val(&o->ref);
     
     if (!strcmp(name, "exists")) {
         const char *str = v ? "true" : "false";
-        if (!NCDValue_InitString(out_value, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         return 1;
     }
@@ -929,21 +939,21 @@ static int func_getvar (void *vo, const char *name, NCDValue *out_value)
     }
     
     if (!strcmp(name, "type")) {
-        if (!NCDValue_InitString(out_value, get_type_str(v->type))) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, get_type_str(v->type));
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
     }
     else if (!strcmp(name, "length")) {
         size_t len;
         switch (v->type) {
-            case NCDVALUE_LIST:
+            case NCDVAL_LIST:
                 len = value_list_len(v);
                 break;
-            case NCDVALUE_MAP:
+            case NCDVAL_MAP:
                 len = value_map_len(v);
                 break;
-            case NCDVALUE_STRING:
+            case NCDVAL_STRING:
                 len = v->string.length;
                 break;
             default:
@@ -952,43 +962,38 @@ static int func_getvar (void *vo, const char *name, NCDValue *out_value)
         
         char str[64];
         snprintf(str, sizeof(str), "%zu", len);
-        if (!NCDValue_InitString(out_value, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
     }
     else if (!strcmp(name, "keys")) {
-        if (v->type != NCDVALUE_MAP) {
+        if (v->type != NCDVAL_MAP) {
             ModuleLog(o->i, BLOG_ERROR, "value is not a map (reading keys variable)");
             return 0;
         }
         
-        NCDValue_InitList(out_value);
+        *out = NCDVal_NewList(mem, value_map_len(v));
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewList failed");
+            goto fail;
+        }
         
-        for (size_t i = 0; i < value_map_len(v); i++) {
-            struct value *ev = value_map_at(v, i);
+        for (size_t j = 0; j < value_map_len(v); j++) {
+            struct value *ev = value_map_at(v, j);
             
-            NCDValue key;
-            if (!NCDValue_InitCopy(&key, &ev->map_parent.key)) {
-                ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-                goto map_fail1;
+            NCDValRef key = NCDVal_NewCopy(mem, ev->map_parent.key);
+            if (NCDVal_IsInvalid(key)) {
+                ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
+                goto fail;
             }
             
-            if (!NCDValue_ListAppend(out_value, key)) {
-                ModuleLog(o->i, BLOG_ERROR, "NCDValue_ListAppend failed");
-                NCDValue_Free(&key);
-                goto map_fail1;
-            }
+            NCDVal_ListAppend(*out, key);
         }
-        
-        return 1;
-        
-    map_fail1:
-        NCDValue_Free(out_value);
-        return 0;
     }
     else if (!strcmp(name, "")) {
-        if (!value_to_value(o->i, v, out_value)) {
+        if (!value_to_value(o->i, v, mem, out)) {
             return 0;
         }
     }
@@ -997,12 +1002,16 @@ static int func_getvar (void *vo, const char *name, NCDValue *out_value)
     }
     
     return 1;
+    
+fail:
+    *out = NCDVal_NewInvalid();
+    return 1;
 }
 
 static void func_new_value (NCDModuleInst *i)
 {
-    NCDValue *value_arg;
-    if (!NCDValue_ListRead(i->args, 1, &value_arg)) {
+    NCDValRef value_arg;
+    if (!NCDVal_ListRead(i->args, 1, &value_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -1022,8 +1031,8 @@ fail0:
 
 static void func_new_get (NCDModuleInst *i)
 {
-    NCDValue *where_arg;
-    if (!NCDValue_ListRead(i->args, 1, &where_arg)) {
+    NCDValRef where_arg;
+    if (!NCDVal_ListRead(i->args, 1, &where_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -1051,8 +1060,8 @@ fail0:
 
 static void func_new_try_get (NCDModuleInst *i)
 {
-    NCDValue *where_arg;
-    if (!NCDValue_ListRead(i->args, 1, &where_arg)) {
+    NCDValRef where_arg;
+    if (!NCDVal_ListRead(i->args, 1, &where_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -1077,12 +1086,12 @@ fail0:
 
 static void func_new_getpath (NCDModuleInst *i)
 {
-    NCDValue *path_arg;
-    if (!NCDValue_ListRead(i->args, 1, &path_arg)) {
+    NCDValRef path_arg;
+    if (!NCDVal_ListRead(i->args, 1, &path_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (NCDValue_Type(path_arg) != NCDVALUE_LIST) {
+    if (!NCDVal_IsList(path_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
@@ -1110,9 +1119,9 @@ fail0:
 
 static void func_new_insert (NCDModuleInst *i)
 {
-    NCDValue *where_arg;
-    NCDValue *what_arg;
-    if (!NCDValue_ListRead(i->args, 2, &where_arg, &what_arg)) {
+    NCDValRef where_arg;
+    NCDValRef what_arg;
+    if (!NCDVal_ListRead(i->args, 2, &where_arg, &what_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -1154,7 +1163,7 @@ static void insert_undo_deinit_func (struct insert_undo_deinit_data *data, NCDMo
         
         // remove this value from parent and restore saved one (or none)
         switch (parent->type) {
-            case NCDVALUE_LIST: {
+            case NCDVAL_LIST: {
                 size_t index = value_list_indexof(parent, val);
                 value_list_remove(parent, val);
                 if (oldval) {
@@ -1163,14 +1172,15 @@ static void insert_undo_deinit_func (struct insert_undo_deinit_data *data, NCDMo
                 }
             } break;
             
-            case NCDVALUE_MAP: {
-                NCDValue key;
-                value_map_remove2(parent, val, &key);
+            case NCDVAL_MAP: {
+                NCDValMem key_mem;
+                NCDValSafeRef key;
+                value_map_remove2(parent, val, &key_mem, &key);
                 if (oldval) {
-                    int res = value_map_insert(parent, oldval, key, i);
+                    int res = value_map_insert(parent, oldval, key_mem, key, i);
                     ASSERT(res)
                 } else {
-                    NCDValue_Free(&key);
+                    NCDValMem_Free(&key_mem);
                 }
             } break;
             
@@ -1185,9 +1195,9 @@ static void insert_undo_deinit_func (struct insert_undo_deinit_data *data, NCDMo
 
 static void func_new_insert_undo (NCDModuleInst *i)
 {
-    NCDValue *where_arg;
-    NCDValue *what_arg;
-    if (!NCDValue_ListRead(i->args, 2, &where_arg, &what_arg)) {
+    NCDValRef where_arg;
+    NCDValRef what_arg;
+    if (!NCDVal_ListRead(i->args, 2, &where_arg, &what_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -1227,26 +1237,26 @@ fail0:
 
 static void func_new_substr (NCDModuleInst *i)
 {
-    NCDValue *start_arg;
-    NCDValue *length_arg = NULL;
-    if (!NCDValue_ListRead(i->args, 1, &start_arg) &&
-        !NCDValue_ListRead(i->args, 2, &start_arg, &length_arg)) {
+    NCDValRef start_arg;
+    NCDValRef length_arg = NCDVal_NewInvalid();
+    if (!NCDVal_ListRead(i->args, 1, &start_arg) &&
+        !NCDVal_ListRead(i->args, 2, &start_arg, &length_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
-    if (!NCDValue_IsStringNoNulls(start_arg) || (length_arg && !NCDValue_IsStringNoNulls(length_arg))) {
+    if (!NCDVal_IsStringNoNulls(start_arg) || (!NCDVal_IsInvalid(length_arg) && !NCDVal_IsStringNoNulls(length_arg))) {
         ModuleLog(i, BLOG_ERROR, "wrong type");
         goto fail0;
     }
     
     uintmax_t start;
-    if (!parse_unsigned_integer(NCDValue_StringValue(start_arg), &start)) {
+    if (!parse_unsigned_integer(NCDVal_StringValue(start_arg), &start)) {
         ModuleLog(i, BLOG_ERROR, "start is not a number");
         goto fail0;
     }
     
     uintmax_t length = UINTMAX_MAX;
-    if (length_arg && !parse_unsigned_integer(NCDValue_StringValue(length_arg), &length)) {
+    if (!NCDVal_IsInvalid(length_arg) && !parse_unsigned_integer(NCDVal_StringValue(length_arg), &length)) {
         ModuleLog(i, BLOG_ERROR, "length is not a number");
         goto fail0;
     }
@@ -1259,7 +1269,7 @@ static void func_new_substr (NCDModuleInst *i)
         goto fail0;
     }
     
-    if (mov->type != NCDVALUE_STRING) {
+    if (mov->type != NCDVAL_STRING) {
         ModuleLog(i, BLOG_ERROR, "value is not a string");
         goto fail0;
     }
@@ -1287,8 +1297,8 @@ fail0:
 
 static void remove_func_new (NCDModuleInst *i)
 {
-    NCDValue *where_arg;
-    if (!NCDValue_ListRead(i->args, 1, &where_arg)) {
+    NCDValRef where_arg;
+    if (!NCDVal_ListRead(i->args, 1, &where_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -1315,7 +1325,7 @@ fail0:
 
 static void delete_func_new (NCDModuleInst *i)
 {
-    if (!NCDValue_ListRead(i->args, 0)) {
+    if (!NCDVal_ListRead(i->args, 0)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }

+ 20 - 20
ncd/modules/valuemetic.c

@@ -68,36 +68,36 @@ struct instance {
     int result;
 };
 
-typedef int (*compute_func) (NCDValue *v1, NCDValue *v2);
+typedef int (*compute_func) (NCDValRef v1, NCDValRef v2);
 
-static int compute_lesser (NCDValue *v1, NCDValue *v2)
+static int compute_lesser (NCDValRef v1, NCDValRef v2)
 {
-    return NCDValue_Compare(v1, v2) < 0;
+    return NCDVal_Compare(v1, v2) < 0;
 }
 
-static int compute_greater (NCDValue *v1, NCDValue *v2)
+static int compute_greater (NCDValRef v1, NCDValRef v2)
 {
-    return NCDValue_Compare(v1, v2) > 0;
+    return NCDVal_Compare(v1, v2) > 0;
 }
 
-static int compute_lesser_equal (NCDValue *v1, NCDValue *v2)
+static int compute_lesser_equal (NCDValRef v1, NCDValRef v2)
 {
-    return NCDValue_Compare(v1, v2) <= 0;
+    return NCDVal_Compare(v1, v2) <= 0;
 }
 
-static int compute_greater_equal (NCDValue *v1, NCDValue *v2)
+static int compute_greater_equal (NCDValRef v1, NCDValRef v2)
 {
-    return NCDValue_Compare(v1, v2) >= 0;
+    return NCDVal_Compare(v1, v2) >= 0;
 }
 
-static int compute_equal (NCDValue *v1, NCDValue *v2)
+static int compute_equal (NCDValRef v1, NCDValRef v2)
 {
-    return NCDValue_Compare(v1, v2) == 0;
+    return NCDVal_Compare(v1, v2) == 0;
 }
 
-static int compute_different (NCDValue *v1, NCDValue *v2)
+static int compute_different (NCDValRef v1, NCDValRef v2)
 {
-    return NCDValue_Compare(v1, v2) != 0;
+    return NCDVal_Compare(v1, v2) != 0;
 }
 
 static void new_templ (NCDModuleInst *i, compute_func cfunc)
@@ -110,9 +110,9 @@ static void new_templ (NCDModuleInst *i, compute_func cfunc)
     o->i = i;
     NCDModuleInst_Backend_SetUser(i, o);
     
-    NCDValue *v1_arg;
-    NCDValue *v2_arg;
-    if (!NCDValue_ListRead(i->args, 2, &v1_arg, &v2_arg)) {
+    NCDValRef v1_arg;
+    NCDValRef v2_arg;
+    if (!NCDVal_ListRead(i->args, 2, &v1_arg, &v2_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
@@ -140,16 +140,16 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out_value)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
         const char *str = o->result ? "true" : "false";
         
-        if (!NCDValue_InitString(out_value, str)) {
-            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
-            return 0;
+        *out = NCDVal_NewString(mem, str);
+        if (NCDVal_IsInvalid(*out)) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
         }
         return 1;
     }

+ 35 - 23
ncd/modules/var.c

@@ -48,7 +48,8 @@
 
 struct instance {
     NCDModuleInst *i;
-    NCDValue value;
+    NCDValMem mem;
+    NCDValRef value;
 };
 
 static void func_new (NCDModuleInst *i)
@@ -65,23 +66,28 @@ static void func_new (NCDModuleInst *i)
     o->i = i;
     
     // read argument
-    NCDValue *value_arg;
-    if (!NCDValue_ListRead(o->i->args, 1, &value_arg)) {
+    NCDValRef value_arg;
+    if (!NCDVal_ListRead(i->args, 1, &value_arg)) {
         ModuleLog(o->i, BLOG_ERROR, "wrong arity");
         goto fail1;
     }
     
-    // copy to value
-    if (!NCDValue_InitCopy(&o->value, value_arg)) {
-        ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail1;
+    // init mem
+    NCDValMem_Init(&o->mem);
+    
+    // copy value
+    o->value = NCDVal_NewCopy(&o->mem, value_arg);
+    if (NCDVal_IsInvalid(o->value)) {
+        ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
+        goto fail2;
     }
     
     // signal up
     NCDModuleInst_Backend_Up(o->i);
-    
     return;
     
+fail2:
+    NCDValMem_Free(&o->mem);
 fail1:
     free(o);
 fail0:
@@ -94,8 +100,8 @@ static void func_die (void *vo)
     struct instance *o = vo;
     NCDModuleInst *i = o->i;
     
-    // free value
-    NCDValue_Free(&o->value);
+    // free mem
+    NCDValMem_Free(&o->mem);
     
     // free instance
     free(o);
@@ -103,16 +109,15 @@ static void func_die (void *vo)
     NCDModuleInst_Backend_Dead(i);
 }
 
-static int func_getvar (void *vo, const char *name, NCDValue *out)
+static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
 {
     struct instance *o = vo;
     
     if (!strcmp(name, "")) {
-        if (!NCDValue_InitCopy(out, &o->value)) {
+        *out = NCDVal_NewCopy(mem, o->value);
+        if (NCDVal_IsInvalid(*out)) {
             ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
-            return 0;
         }
-        
         return 1;
     }
     
@@ -121,9 +126,9 @@ static int func_getvar (void *vo, const char *name, NCDValue *out)
 
 static void set_func_new (NCDModuleInst *i)
 {
-    // read argument
-    NCDValue *value_arg;
-    if (!NCDValue_ListRead(i->args, 1, &value_arg)) {
+    // read arguments
+    NCDValRef value_arg;
+    if (!NCDVal_ListRead(i->args, 1, &value_arg)) {
         ModuleLog(i, BLOG_ERROR, "wrong arity");
         goto fail0;
     }
@@ -131,21 +136,28 @@ static void set_func_new (NCDModuleInst *i)
     // get method object
     struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
     
+    // allocate new mem
+    NCDValMem mem;
+    NCDValMem_Init(&mem);
+    
     // copy value
-    NCDValue v;
-    if (!NCDValue_InitCopy(&v, value_arg)) {
-        ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
-        goto fail0;
+    NCDValRef copy = NCDVal_NewCopy(&mem, value_arg);
+    if (NCDVal_IsInvalid(copy)) {
+        ModuleLog(i, BLOG_ERROR, "NCDVal_NewCopy failed");
+        goto fail1;
     }
     
     // replace value in var
-    NCDValue_Free(&mo->value);
-    mo->value = v;
+    NCDValMem_Free(&mo->mem);
+    mo->mem = mem;
+    mo->value = NCDVal_Moved(&mo->mem, copy);
     
     // signal up
     NCDModuleInst_Backend_Up(i);
     return;
     
+fail1:
+    NCDValMem_Free(&mem);
 fail0:
     NCDModuleInst_Backend_SetError(i);
     NCDModuleInst_Backend_Dead(i);

+ 74 - 79
ncd/ncd.c

@@ -82,7 +82,7 @@ struct process_statement {
     struct process *p;
     btime_t error_until;
     NCDModuleInst inst;
-    NCDValue inst_args;
+    NCDValMem args_mem;
     int i;
     int state;
     int have_error;
@@ -169,17 +169,17 @@ static void process_advance (struct process *p);
 static void process_wait_timer_handler (struct process *p);
 static int process_find_object (struct process *p, int pos, const char *name, NCDObject *out_object);
 static int process_resolve_object_expr (struct process *p, int pos, char **names, NCDObject *out_object);
-static int process_resolve_variable_expr (struct process *p, int pos, char **names, NCDValue *out_value);
+static int process_resolve_variable_expr (struct process *p, int pos, char **names, NCDValMem *mem, NCDValRef *out_value);
 static void process_statement_logfunc (struct process_statement *ps);
 static void process_statement_log (struct process_statement *ps, int level, const char *fmt, ...);
 static void process_statement_set_error (struct process_statement *ps);
-static int process_statement_resolve_argument (struct process_statement *ps, NCDInterpValue *arg, NCDValue *out);
+static int process_statement_resolve_argument (struct process_statement *ps, NCDInterpValue *arg, NCDValMem *mem, NCDValRef *out);
 static void process_statement_instance_func_event (struct process_statement *ps, int event);
 static int process_statement_instance_func_getobj (struct process_statement *ps, const char *objname, NCDObject *out_object);
 static int process_statement_instance_func_initprocess (struct process_statement *ps, NCDModuleProcess *mp, const char *template_name);
 static void process_statement_instance_logfunc (struct process_statement *ps);
 static void process_statement_instance_func_interp_exit (struct process_statement *ps, int exit_code);
-static int process_statement_instance_func_interp_getargs (struct process_statement *ps, NCDValue *out_value);
+static int process_statement_instance_func_interp_getargs (struct process_statement *ps, NCDValMem *mem, NCDValRef *out_value);
 static btime_t process_statement_instance_func_interp_getretrytime (struct process_statement *ps);
 static void process_moduleprocess_func_event (struct process *p, int event);
 static int process_moduleprocess_func_getobj (struct process *p, const char *name, NCDObject *out_object);
@@ -961,7 +961,7 @@ void process_advance (struct process *p)
     if (object_names) {
         // get object
         if (!process_resolve_object_expr(p, p->ap, object_names, &object)) {
-            goto fail;
+            goto fail0;
         }
         object_ptr = &object;
         
@@ -969,14 +969,14 @@ void process_advance (struct process *p)
         const char *object_type = NCDObject_Type(&object);
         if (!object_type) {
             process_statement_log(ps, BLOG_ERROR, "cannot call method on object with no type");
-            goto fail;
+            goto fail0;
         }
         
         // build type string
         int res = snprintf(method_concat_buf, sizeof(method_concat_buf), "%s::%s", object_type, type);
         if (res >= sizeof(method_concat_buf) || res < 0) {
             process_statement_log(ps, BLOG_ERROR, "type/method name too long");
-            goto fail;
+            goto fail0;
         }
         type = method_concat_buf;
     }
@@ -985,17 +985,22 @@ void process_advance (struct process *p)
     const struct NCDModule *module = NCDModuleIndex_FindModule(&mindex, type);
     if (!module) {
         process_statement_log(ps, BLOG_ERROR, "failed to find module: %s", type);
-        goto fail;
+        goto fail0;
     }
     
+    // init args mem
+    NCDValMem_Init(&ps->args_mem);
+    
     // resolve arguments
-    if (!process_statement_resolve_argument(ps, NCDInterpBlock_StatementInterpValue(p->iblock, ps->i), &ps->inst_args)) {
+    NCDValRef args;
+    NCDInterpValue *iargs = NCDInterpBlock_StatementInterpValue(p->iblock, ps->i);
+    if (!process_statement_resolve_argument(ps, iargs, &ps->args_mem, &args)) {
         process_statement_log(ps, BLOG_ERROR, "failed to resolve arguments");
-        goto fail;
+        goto fail1;
     }
     
     // initialize module instance
-    NCDModuleInst_Init(&ps->inst, module, object_ptr, &ps->inst_args, ps, &module_params, &module_iparams);
+    NCDModuleInst_Init(&ps->inst, module, object_ptr, args, ps, &module_params, &module_iparams);
     
     // set statement state CHILD
     ps->state = SSTATE_CHILD;
@@ -1009,7 +1014,9 @@ void process_advance (struct process *p)
     process_assert_pointers(p);
     return;
     
-fail:
+fail1:
+    NCDValMem_Free(&ps->args_mem);
+fail0:
     // mark error
     process_statement_set_error(ps);
     
@@ -1090,12 +1097,13 @@ fail:;
     return 0;
 }
 
-int process_resolve_variable_expr (struct process *p, int pos, char **names, NCDValue *out_value)
+int process_resolve_variable_expr (struct process *p, int pos, char **names, NCDValMem *mem, NCDValRef *out_value)
 {
     ASSERT(pos >= 0)
     ASSERT(pos <= p->num_statements)
     ASSERT(names)
     ASSERT(count_strings(names) > 0)
+    ASSERT(mem)
     ASSERT(out_value)
     
     NCDObject object;
@@ -1103,7 +1111,7 @@ int process_resolve_variable_expr (struct process *p, int pos, char **names, NCD
         goto fail;
     }
     
-    if (!NCDObject_ResolveVarExpr(&object, names + 1, out_value)) {
+    if (!NCDObject_ResolveVarExpr(&object, names + 1, mem, out_value)) {
         goto fail;
     }
     
@@ -1142,90 +1150,77 @@ void process_statement_set_error (struct process_statement *ps)
     ps->error_until = btime_add(btime_gettime(), options.retry_time);
 }
 
-int process_statement_resolve_argument (struct process_statement *ps, NCDInterpValue *arg, NCDValue *out)
+int process_statement_resolve_argument (struct process_statement *ps, NCDInterpValue *arg, NCDValMem *mem, NCDValRef *out)
 {
     ASSERT(ps->i <= process_rap(ps->p))
     ASSERT(arg)
+    ASSERT(mem)
     ASSERT(out)
     
     switch (arg->type) {
         case NCDVALUE_STRING: {
-            if (!NCDValue_InitStringBin(out, (uint8_t *)arg->string, arg->string_len)) {
-                process_statement_log(ps, BLOG_ERROR, "NCDValue_InitStringBin failed");
+            *out = NCDVal_NewStringBin(mem, (uint8_t *)arg->string, arg->string_len);
+            if (NCDVal_IsInvalid(*out)) {
+                process_statement_log(ps, BLOG_ERROR, "NCDVal_NewStringBin failed");
                 return 0;
             }
         } break;
         
         case NCDVALUE_VAR: {
-            if (!process_resolve_variable_expr(ps->p, ps->i, arg->variable_names, out)) {
+            if (!process_resolve_variable_expr(ps->p, ps->i, arg->variable_names, mem, out)) {
+                return 0;
+            }
+            if (NCDVal_IsInvalid(*out)) {
                 return 0;
             }
         } break;
         
-        case NCDVALUE_LIST: do {
-            NCDValue_InitList(out);
+        case NCDVALUE_LIST: {
+            *out = NCDVal_NewList(mem, arg->list_count);
+            if (NCDVal_IsInvalid(*out)) {
+                process_statement_log(ps, BLOG_ERROR, "NCDVal_NewList failed");
+                return 0;
+            }
             
             for (LinkedList1Node *n = LinkedList1_GetFirst(&arg->list); n; n = LinkedList1Node_Next(n)) {
                 struct NCDInterpValueListElem *elem = UPPER_OBJECT(n, struct NCDInterpValueListElem, list_node);
                 
-                NCDValue v;
-                if (!process_statement_resolve_argument(ps, &elem->value, &v)) {
-                    goto list_fail1;
+                NCDValRef new_elem;
+                if (!process_statement_resolve_argument(ps, &elem->value, mem, &new_elem)) {
+                    return 0;
                 }
                 
-                if (!NCDValue_ListAppend(out, v)) {
-                    process_statement_log(ps, BLOG_ERROR, "NCDValue_ListAppend failed");
-                    NCDValue_Free(&v);
-                    goto list_fail1;
-                }
+                NCDVal_ListAppend(*out, new_elem);
             }
-            
-            break;
-            
-        list_fail1:
-            NCDValue_Free(out);
-            return 0;
-        } while (0); break;
+        } break;
         
-        case NCDVALUE_MAP: do {
-            NCDValue_InitMap(out);
+        case NCDVALUE_MAP: {
+            *out = NCDVal_NewMap(mem, arg->map_count);
+            if (NCDVal_IsInvalid(*out)) {
+                process_statement_log(ps, BLOG_ERROR, "NCDVal_NewMap failed");
+                return 0;
+            }
             
             for (LinkedList1Node *n = LinkedList1_GetFirst(&arg->maplist); n; n = LinkedList1Node_Next(n)) {
                 struct NCDInterpValueMapElem *elem = UPPER_OBJECT(n, struct NCDInterpValueMapElem, maplist_node);
                 
-                NCDValue key;
-                NCDValue val;
-                
-                if (!process_statement_resolve_argument(ps, &elem->key, &key)) {
-                    goto map_fail;
+                NCDValRef new_key;
+                if (!process_statement_resolve_argument(ps, &elem->key, mem, &new_key)) {
+                    return 0;
                 }
                 
-                if (!process_statement_resolve_argument(ps, &elem->val, &val)) {
-                    NCDValue_Free(&key);
-                    goto map_fail;
+                NCDValRef new_val;
+                if (!process_statement_resolve_argument(ps, &elem->val, mem, &new_val)) {
+                    return 0;
                 }
                 
-                if (NCDValue_MapFindKey(out, &key)) {
+                int res = NCDVal_MapInsert(*out, new_key, new_val);
+                if (!res) {
                     process_statement_log(ps, BLOG_ERROR, "duplicate map keys");
-                    NCDValue_Free(&key);
-                    NCDValue_Free(&val);
-                    goto map_fail;
-                }
-                
-                if (!NCDValue_MapInsert(out, key, val)) {
-                    process_statement_log(ps, BLOG_ERROR, "NCDValue_MapInsert failed");
-                    NCDValue_Free(&key);
-                    NCDValue_Free(&val);
-                    goto map_fail;
+                    return 0;
                 }
             }
-            
-            break;
-            
-        map_fail:
-            NCDValue_Free(out);
-            return 0;
-        } while (0); break;
+        } break;
         
         default: ASSERT(0);
     }
@@ -1279,8 +1274,8 @@ void process_statement_instance_func_event (struct process_statement *ps, int ev
             // free instance
             NCDModuleInst_Free(&ps->inst);
             
-            // free instance arguments
-            NCDValue_Free(&ps->inst_args);
+            // free arguments memory
+            NCDValMem_Free(&ps->args_mem);
             
             // set state FORGOTTEN
             ps->state = SSTATE_FORGOTTEN;
@@ -1348,31 +1343,31 @@ void process_statement_instance_func_interp_exit (struct process_statement *ps,
     start_terminate(exit_code);
 }
 
-int process_statement_instance_func_interp_getargs (struct process_statement *ps, NCDValue *out_value)
+int process_statement_instance_func_interp_getargs (struct process_statement *ps, NCDValMem *mem, NCDValRef *out_value)
 {
     ASSERT(ps->state != SSTATE_FORGOTTEN)
     
-    NCDValue_InitList(out_value);
+    *out_value = NCDVal_NewList(mem, options.num_extra_args);
+    if (NCDVal_IsInvalid(*out_value)) {
+        process_statement_log(ps, BLOG_ERROR, "NCDVal_NewList failed");
+        goto fail;
+    }
     
     for (int i = 0; i < options.num_extra_args; i++) {
-        NCDValue arg;
-        if (!NCDValue_InitString(&arg, options.extra_args[i])) {
-             process_statement_log(ps, BLOG_ERROR, "NCDValue_InitString failed");
-             goto fail1;
+        NCDValRef arg = NCDVal_NewString(mem, options.extra_args[i]);
+        if (NCDVal_IsInvalid(arg)) {
+            process_statement_log(ps, BLOG_ERROR, "NCDVal_NewString failed");
+            goto fail;
         }
         
-        if (!NCDValue_ListAppend(out_value, arg)) {
-            process_statement_log(ps, BLOG_ERROR, "NCDValue_ListAppend failed");
-            NCDValue_Free(&arg);
-            goto fail1;
-        }
+        NCDVal_ListAppend(*out_value, arg);
     }
     
     return 1;
     
-fail1:
-    NCDValue_Free(out_value);
-    return 0;
+fail:
+    *out_value = NCDVal_NewInvalid();
+    return 1;
 }
 
 btime_t process_statement_instance_func_interp_getretrytime (struct process_statement *ps)