Просмотр исходного кода

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

ambrop7 13 лет назад
Родитель
Сommit
27c36e7859
80 измененных файлов с 3107 добавлено и 1635 удалено
  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 <ambrop7@gmail.com>
+ * 
+ * @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 <ambrop7@gmail.com>
+ * 
+ * @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 <ambrop7@gmail.com>
+ * 
+ * @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 <ambrop7@gmail.com>
+ * 
+ * @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)