BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file NCDVal.h
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #ifndef BADVPN_NCDVAL_H
31 #define BADVPN_NCDVAL_H
32  
33 #include <stddef.h>
34 #include <stdint.h>
35  
36 #include <misc/debug.h>
37 #include <misc/BRefTarget.h>
38 #include <misc/memref.h>
39 #include <ncd/NCDStringIndex.h>
40 #include <ncd/NCDVal_types.h>
41  
42 #define NCDVAL_STRING 1
43 #define NCDVAL_LIST 2
44 #define NCDVAL_MAP 3
45 #define NCDVAL_PLACEHOLDER 4
46  
47 /**
48 * Initializes a value memory object.
49 * A value memory object holds memory for value structures. Values within
50 * the memory are referenced using {@link NCDValRef} objects, which point
51 * to values within memory objects.
52 *
53 * Values may be added to a memory object using functions such as
54 * {@link NCDVal_NewString}, {@link NCDVal_NewList} and {@link NCDVal_NewMap},
55 * and {@link NCDVal_NewCopy}, which return references to the new values within
56 * the memory object.
57 *
58 * It is not possible to remove values from the memory object, or modify existing
59 * values other than adding elements to pre-allocated slots in lists and maps.
60 * Once a value is added, it will consume memory as long as its memory object
61 * exists. This is by design - this code is intended and optimized for constructing
62 * and passing around values, not for operating on them in place. In fact, al
63 * values within a memory object are stored in a single memory buffer, as an
64 * embedded data structure with relativepointers. For example, map values use an
65 * embedded AVL tree.
66 */
67 void NCDValMem_Init (NCDValMem *o, NCDStringIndex *string_index);
68  
69 /**
70 * Frees a value memory object.
71 * All values within the memory object cease to exist, and any {@link NCDValRef}
72 * object pointing to them must no longer be used.
73 */
74 void NCDValMem_Free (NCDValMem *o);
75  
76 /**
77 * Initializes the memory object to be a copy of an existing memory object.
78 * Value references from the original may be used if they are first turned
79 * to {@link NCDValSafeRef} using {@link NCDVal_ToSafe} and back to
80 * {@link NCDValRef} using {@link NCDVal_FromSafe} with the new memory object
81 * specified. Alternatively, {@link NCDVal_Moved} can be used.
82 * Returns 1 on success and 0 on failure.
83 */
84 int NCDValMem_InitCopy (NCDValMem *o, NCDValMem *other) WARN_UNUSED;
85  
86 /**
87 * Get the string index of a value memory object.
88 */
89 NCDStringIndex * NCDValMem_StringIndex (NCDValMem *o);
90  
91 /**
92 * Does nothing.
93 * The value reference object must either point to a valid value within a valid
94 * memory object, or must be an invalid reference (most functions operating on
95 * {@link NCDValRef} implicitly require that).
96 */
97 void NCDVal_Assert (NCDValRef val);
98  
99 /**
100 * Determines if a value reference is invalid.
101 */
102 int NCDVal_IsInvalid (NCDValRef val);
103  
104 /**
105 * Determines if a value is a placeholder value.
106 * The value reference must not be an invalid reference.
107 */
108 int NCDVal_IsPlaceholder (NCDValRef val);
109  
110 /**
111 * Returns the type of the value reference, which must not be an invalid reference.
112 * Possible values are NCDVAL_STRING, NCDVAL_LIST, NCDVAL_MAP and NCDVAL_PLACEHOLDER.
113 * The placeholder type is only used internally in the interpreter for argument
114 * resolution, and is never seen by modules; see {@link NCDVal_NewPlaceholder}.
115 */
116 int NCDVal_Type (NCDValRef val);
117  
118 /**
119 * Returns an invalid reference.
120 * An invalid reference must not be passed to any function here, except:
121 * {@link NCDVal_Assert}, {@link NCDVal_IsInvalid}, {@link NCDVal_ToSafe},
122 * {@link NCDVal_FromSafe}, {@link NCDVal_Moved}.
123 */
124 NCDValRef NCDVal_NewInvalid (void);
125  
126 /**
127 * Returns a new placeholder value reference. A placeholder value is a valid value
128 * containing an integer placeholder identifier.
129 * This always succeeds; however, the caller must ensure the identifier is in the
130 * range [0, NCDVAL_TOPPLID).
131 *
132 * The placeholder type is only used internally in the interpreter for argument
133 * resolution, and is never seen by modules.
134 */
135 NCDValRef NCDVal_NewPlaceholder (NCDValMem *mem, int plid);
136  
137 /**
138 * Returns the indentifier of a placeholder value.
139 * The value reference must point to a placeholder value.
140 */
141 int NCDVal_PlaceholderId (NCDValRef val);
142  
143 /**
144 * Copies a value into the specified memory object. The source
145 * must not be an invalid reference, however it may reside in any memory
146 * object (including 'mem').
147 * Returns a reference to the copied value. On out of memory, returns
148 * an invalid reference.
149 */
150 NCDValRef NCDVal_NewCopy (NCDValMem *mem, NCDValRef val);
151  
152 /**
153 * Compares two values, both of which must not be invalid references.
154 * Returns -1, 0 or 1.
155 */
156 int NCDVal_Compare (NCDValRef val1, NCDValRef val2);
157  
158 /**
159 * Converts a value reference to a safe referece format, which remains valid
160 * if the memory object is moved (safe references do not contain a pointer
161 * to the memory object, unlike {@link NCDValRef} references).
162 */
163 NCDValSafeRef NCDVal_ToSafe (NCDValRef val);
164  
165 /**
166 * Converts a safe value reference to a normal value reference.
167 * This should be used to recover references from safe references
168 * after the memory object is moved.
169 */
170 NCDValRef NCDVal_FromSafe (NCDValMem *mem, NCDValSafeRef sval);
171  
172 /**
173 * Fixes a value reference after its memory object was moved.
174 */
175 NCDValRef NCDVal_Moved (NCDValMem *mem, NCDValRef val);
176  
177 /**
178 * Determines whether a safe reference is a placeholder.
179 */
180 int NCDVal_IsSafeRefPlaceholder (NCDValSafeRef sval);
181  
182 /**
183 * Gets the placeholder ID of a placeholder safe reference.
184 */
185 int NCDVal_GetSafeRefPlaceholderId (NCDValSafeRef sval);
186  
187 /**
188 * Determines if the value implements the String interface.
189 * The value reference must not be an invalid reference.
190 */
191 int NCDVal_IsString (NCDValRef val);
192  
193 /**
194 * Determines if the value is a StoredString.
195 * A StoredString implements the String interface.
196 * The value reference must not be an invalid reference.
197 */
198 int NCDVal_IsStoredString (NCDValRef val);
199  
200 /**
201 * Determines if the value is an IdString. See {@link NCDVal_NewIdString}
202 * for details.
203 * An IdString implements the String interface.
204 * The value reference must not be an invalid reference.
205 */
206 int NCDVal_IsIdString (NCDValRef val);
207  
208 /**
209 * Determines if a value is an ExternalString.
210 * See {@link NCDVal_NewExternalString} for details.
211 * An ExternalString implements the String interface.
212 * The value reference must not be an invalid reference.
213 */
214 int NCDVal_IsExternalString (NCDValRef val);
215  
216 /**
217 * Determines if a value is a String which contains no null bytes.
218 * The value reference must not be an invalid reference.
219 */
220 int NCDVal_IsStringNoNulls (NCDValRef val);
221  
222 /**
223 * Equivalent to NCDVal_NewStringBin(mem, data, strlen(data)).
224 */
225 NCDValRef NCDVal_NewString (NCDValMem *mem, const char *data);
226  
227 /**
228 * Builds a new StoredString.
229 * Returns a reference to the new value, or an invalid reference
230 * on out of memory.
231 * WARNING: The buffer passed must NOT be part of any value in the
232 * memory object specified. In particular, you may NOT use this
233 * function to copy a string that resides in the same memory object.
234 *
235 * A StoredString is a kind of String which is represented directly in the
236 * value memory object.
237 */
238 NCDValRef NCDVal_NewStringBin (NCDValMem *mem, const uint8_t *data, size_t len);
239  
240 /**
241 * See NCDVal_NewStringBin.
242 */
243 NCDValRef NCDVal_NewStringBinMr (NCDValMem *mem, MemRef data);
244  
245 /**
246 * Builds a new StoredString of the given length with undefined contents.
247 * You can define the contents of the string later by copying to the address
248 * returned by {@link NCDVal_StringData}.
249 */
250 NCDValRef NCDVal_NewStringUninitialized (NCDValMem *mem, size_t len);
251  
252 /**
253 * Builds a new IdString.
254 * Returns a reference to the new value, or an invalid reference
255 * on out of memory.
256 *
257 * An IdString is a kind of String which is represented efficiently as a string
258 * identifier via {@link NCDStringIndex}.
259 */
260 NCDValRef NCDVal_NewIdString (NCDValMem *mem, NCD_string_id_t string_id);
261  
262 /**
263 * Builds a new ExternalString, pointing to the given external data. A reference to
264 * the external data is taken using {@link BRefTarget}, unless 'ref_target' is
265 * NULL. The data must not change while this value exists.
266 * Returns a reference to the new value, or an invalid reference
267 * on out of memory.
268 *
269 * An ExternalString is a kind of String where the actual string contents are
270 * stored outside of the value memory object.
271 */
272 NCDValRef NCDVal_NewExternalString (NCDValMem *mem, const char *data, size_t len,
273 BRefTarget *ref_target);
274  
275 /**
276 * Returns a pointer to the data of a String.
277 * WARNING: the string data may not be null-terminated. To get a null-terminated
278 * version, use {@link NCDVal_StringNullTerminate}.
279 * The value reference must point to a String.
280 * WARNING: the returned pointer may become invalid when any new value is inserted
281 * into the residing memory object (due to a realloc of the value memory).
282 */
283 const char * NCDVal_StringData (NCDValRef string);
284  
285 /**
286 * Returns the length of a String.
287 * The value reference must point to a String.
288 */
289 size_t NCDVal_StringLength (NCDValRef string);
290  
291 /**
292 * Returns a MemRef interface to the given string value.
293 * WARNING: the returned pointer may become invalid when any new value is inserted
294 * into the residing memory object (due to a realloc of the value memory).
295 */
296 MemRef NCDVal_StringMemRef (NCDValRef string);
297  
298 /**
299 * Produces a null-terminated version of a String. On success, the result is
300 * stored into an {@link NCDValNullTermString} structure, and the null-terminated
301 * string is available via its 'data' member. This function may either simply pass
302 * through the data pointer (if the string is known to be null-terminated) or
303 * produce a null-terminated dynamically allocated copy.
304 * On success, {@link NCDValNullTermString_Free} should be called to release any allocated
305 * memory when the null-terminated string is no longer needed. This must be called before
306 * the memory object is freed, because it may point to data inside the memory object.
307 * It is guaranteed that *out is not modified on failure.
308 * Returns 1 on success and 0 on failure.
309 */
310 int NCDVal_StringNullTerminate (NCDValRef string, NCDValNullTermString *out) WARN_UNUSED;
311  
312 /**
313 * Returns a dummy {@link NCDValNullTermString} which can be freed using
314 * {@link NCDValNullTermString_Free}, but need not be.
315 */
316 NCDValNullTermString NCDValNullTermString_NewDummy (void);
317  
318 /**
319 * Releases any memory which was dynamically allocated by {@link NCDVal_StringNullTerminate}
320 * to null-terminate a string.
321 */
322 void NCDValNullTermString_Free (NCDValNullTermString *o);
323  
324 /**
325 * Returns the string ID of an IdString.
326 */
327 NCD_string_id_t NCDVal_IdStringId (NCDValRef idstring);
328  
329 /**
330 * Returns the reference target of an ExternalString. This may be NULL
331 * if the external string is not associated with a reference target.
332 */
333 BRefTarget * NCDVal_ExternalStringTarget (NCDValRef externalstring);
334  
335 /**
336 * Determines if the String has any null bytes in its contents.
337 */
338 int NCDVal_StringHasNulls (NCDValRef string);
339  
340 /**
341 * Determines if the String value is equal to the given null-terminated
342 * string.
343 * The value reference must point to a String value.
344 */
345 int NCDVal_StringEquals (NCDValRef string, const char *data);
346  
347 /**
348 * Determines if the String is equal to the given string represented
349 * by an {@link NCDStringIndex} identifier.
350 */
351 int NCDVal_StringEqualsId (NCDValRef string, NCD_string_id_t string_id);
352  
353 /**
354 * Compares two String's in a manner similar to memcmp().
355 * The startN and length arguments must refer to a valid region within
356 * stringN, i.e. startN + length <= length_of_stringN must hold.
357 */
358 int NCDVal_StringMemCmp (NCDValRef string1, NCDValRef string2, size_t start1, size_t start2, size_t length);
359  
360 /**
361 * Copies a part of a String to a buffer.
362 * \a start and \a length must refer to a valid region within the string,
363 * i.e. start + length <= length_of_string must hold.
364 */
365 void NCDVal_StringCopyOut (NCDValRef string, size_t start, size_t length, char *dst);
366  
367 /**
368 * Determines if a part of a String is equal to the \a length bytes in \a data.
369 * \a start and \a length must refer to a valid region within the string,
370 * i.e. start + length <= length_of_string must hold.
371 */
372 int NCDVal_StringRegionEquals (NCDValRef string, size_t start, size_t length, const char *data);
373  
374 /**
375 * Determines if a value is a list value.
376 * The value reference must not be an invalid reference.
377 */
378 int NCDVal_IsList (NCDValRef val);
379  
380 /**
381 * Builds a new list value. The 'maxcount' argument specifies how
382 * many element slots to preallocate. Not more than that many
383 * elements may be appended to the list using {@link NCDVal_ListAppend}.
384 * Returns a reference to the new value, or an invalid reference
385 * on out of memory.
386 */
387 NCDValRef NCDVal_NewList (NCDValMem *mem, size_t maxcount);
388  
389 /**
390 * Appends a value to to the list value.
391 * The 'list' reference must point to a list value, and the
392 * 'elem' reference must be non-invalid and point to a value within
393 * the same memory object as the list.
394 * Inserting a value into a list does not in any way change it;
395 * internally, the list only points to it.
396 * You must not modify the element after it has been inserted into the
397 * list.
398 * Returns 1 on success and 0 on failure (depth limit exceeded).
399 */
400 int NCDVal_ListAppend (NCDValRef list, NCDValRef elem) WARN_UNUSED;
401  
402 /**
403 * Returns the number of elements in a list value, i.e. the number
404 * of times {@link NCDVal_ListAppend} was called.
405 * The 'list' reference must point to a list value.
406 */
407 size_t NCDVal_ListCount (NCDValRef list);
408  
409 /**
410 * Returns the maximum number of elements a list value may contain,
411 * i.e. the 'maxcount' argument to {@link NCDVal_NewList}.
412 * The 'list' reference must point to a list value.
413 */
414 size_t NCDVal_ListMaxCount (NCDValRef list);
415  
416 /**
417 * Returns a reference to the value at the given position 'pos' in a list,
418 * starting with zero.
419 * The 'list' reference must point to a list value.
420 * The position 'pos' must refer to an existing element, i.e.
421 * pos < NCDVal_ListCount().
422 */
423 NCDValRef NCDVal_ListGet (NCDValRef list, size_t pos);
424  
425 /**
426 * Returns references to elements within a list by writing them
427 * via (NCDValRef *) variable arguments.
428 * If 'num' == NCDVal_ListCount(), succeeds, returing 1 and writing 'num'
429 * references, as mentioned.
430 * If 'num' != NCDVal_ListCount(), fails, returning 0, without writing any
431 * references
432 */
433 int NCDVal_ListRead (NCDValRef list, int num, ...);
434  
435 /**
436 * Like NCDVal_ListRead but ignores the initial 'start' arguments,
437 * that is, reads 'num' arguments after 'start'.
438 * The 'start' must be <= the length of the list.
439 */
440 int NCDVal_ListReadStart (NCDValRef list, int start, int num, ...);
441  
442 /**
443 * Like {@link NCDVal_ListRead}, but the list can contain more than 'num'
444 * elements.
445 */
446 int NCDVal_ListReadHead (NCDValRef list, int num, ...);
447  
448 /**
449 * Determines if a value is a map value.
450 * The value reference must not be an invalid reference.
451 */
452 int NCDVal_IsMap (NCDValRef val);
453  
454 /**
455 * Builds a new map value. The 'maxcount' argument specifies how
456 * many entry slots to preallocate. Not more than that many
457 * entries may be inserted to the map using {@link NCDVal_MapInsert}.
458 * Returns a reference to the new value, or an invalid reference
459 * on out of memory.
460 */
461 NCDValRef NCDVal_NewMap (NCDValMem *mem, size_t maxcount);
462  
463 /**
464 * Inserts an entry to the map value.
465 * The 'map' reference must point to a map value, and the
466 * 'key' and 'val' references must be non-invalid and point to values within
467 * the same memory object as the map.
468 * Inserting an entry does not in any way change the 'key'and 'val';
469 * internally, the map only points to it.
470 * You must not modify the key after inserting it into a map. This is because
471 * the map builds an embedded AVL tree of entries indexed by keys.
472 * If insertion fails due to a maximum depth limit, returns 0.
473 * Otherwise returns 1, and *out_inserted is set to 1 if the key did not
474 * yet exist and the entry was inserted, and to 0 if it did exist and the
475 * entry was not inserted. The 'out_inserted' pointer may be NULL, in which
476 * case *out_inserted is never set.
477 */
478 int NCDVal_MapInsert (NCDValRef map, NCDValRef key, NCDValRef val, int *out_inserted) WARN_UNUSED;
479  
480 /**
481 * Returns the number of entries in a map value, i.e. the number
482 * of times {@link NCDVal_MapInsert} was called successfully.
483 * The 'map' reference must point to a map value.
484 */
485 size_t NCDVal_MapCount (NCDValRef map);
486  
487 /**
488 * Returns the maximum number of entries a map value may contain,
489 * i.e. the 'maxcount' argument to {@link NCDVal_NewMap}.
490 * The 'map' reference must point to a map value.
491 */
492 size_t NCDVal_MapMaxCount (NCDValRef map);
493  
494 /**
495 * Determines if a map entry reference is invalid. This is used in combination
496 * with the map iteration functions to detect the end of iteration.
497 */
498 int NCDVal_MapElemInvalid (NCDValMapElem me);
499  
500 /**
501 * Returns a reference to the first entry in a map, with respect to some
502 * arbitrary order.
503 * If the map is empty, returns an invalid map entry reference.
504 */
505 NCDValMapElem NCDVal_MapFirst (NCDValRef map);
506  
507 /**
508 * Returns a reference to the entry in a map that follows the entry referenced
509 * by 'me', with respect to some arbitrary order.
510 * The 'me' argument must be a non-invalid reference to an entry in the map.
511 * If 'me' is the last entry, returns an invalid map entry reference.
512 */
513 NCDValMapElem NCDVal_MapNext (NCDValRef map, NCDValMapElem me);
514  
515 /**
516 * Like {@link NCDVal_MapFirst}, but with respect to the order defined by
517 * {@link NCDVal_Compare}.
518 * Ordered iteration is slower and should only be used when needed.
519 */
520 NCDValMapElem NCDVal_MapOrderedFirst (NCDValRef map);
521  
522 /**
523 * Like {@link NCDVal_MapNext}, but with respect to the order defined by
524 * {@link NCDVal_Compare}.
525 * Ordered iteration is slower and should only be used when needed.
526 */
527 NCDValMapElem NCDVal_MapOrderedNext (NCDValRef map, NCDValMapElem me);
528  
529 /**
530 * Returns a reference to the key of the map entry referenced by 'me'.
531 * The 'me' argument must be a non-invalid reference to an entry in the map.
532 */
533 NCDValRef NCDVal_MapElemKey (NCDValRef map, NCDValMapElem me);
534  
535 /**
536 * Returns a reference to the value of the map entry referenced by 'me'.
537 * The 'me' argument must be a non-invalid reference to an entry in the map.
538 */
539 NCDValRef NCDVal_MapElemVal (NCDValRef map, NCDValMapElem me);
540  
541 /**
542 * Looks for a key in the map. The 'key' reference must be a non-invalid
543 * value reference, and may point to a value in a different memory object
544 * than the map.
545 * If the key exists in the map, returns a reference to the corresponding
546 * map entry.
547 * If the key does not exist, returns an invalid map entry reference.
548 */
549 NCDValMapElem NCDVal_MapFindKey (NCDValRef map, NCDValRef key);
550  
551 /**
552 * Retrieves the value reference to the value of the map entry whose key is a
553 * string value equal to the given null-terminated string. If there is no such
554 * entry, returns an invalid value reference.
555 */
556 NCDValRef NCDVal_MapGetValue (NCDValRef map, const char *key_str);
557  
558 /**
559 * Builds a placeholder replacement program, which is a list of instructions for
560 * efficiently replacing placeholders in identical values in identical memory
561 * objects.
562 * To actually perform replacements, make copies of the memory object of this value
563 * using {@link NCDValMem_InitCopy}, then call {@link NCDValReplaceProg_Execute}
564 * on the copies.
565 * The value passed must be a valid value, and not a placeholder.
566 * Returns 1 on success, 0 on failure.
567 */
568 int NCDValReplaceProg_Init (NCDValReplaceProg *o, NCDValRef val);
569  
570 /**
571 * Frees the placeholder replacement program.
572 */
573 void NCDValReplaceProg_Free (NCDValReplaceProg *o);
574  
575 /**
576 * Callback used by {@link NCDValReplaceProg_Execute} to allow the caller to produce
577 * values of placeholders.
578 * This function should build a new value within the memory object 'mem' (which is
579 * the same as of the memory object where placeholders are being replaced).
580 * On success, it should return 1, writing a valid value reference to *out.
581 * On failure, it can either return 0, or return 1 but write an invalid value reference.
582 * This callback must not access the memory object in any other way than building
583 * new values in it; it must not modify any values that were already present at the
584 * point it was called.
585 */
586 typedef int (*NCDVal_replace_func) (void *arg, int plid, NCDValMem *mem, NCDValRef *out);
587  
588 /**
589 * Executes the replacement program, replacing placeholders in a value.
590 * The memory object must given be identical to the memory object which was used in
591 * {@link NCDValReplaceProg_Init}; see {@link NCDValMem_InitCopy}.
592 * This will call the callback 'replace', which should build the values to replace
593 * the placeholders.
594 * Returns 1 on success and 0 on failure. On failure, the entire memory object enters
595 * and inconsistent state and must be freed using {@link NCDValMem_Free} before
596 * performing any other operation on it.
597 * The program is passed by value instead of pointer because this appears to be faster.
598 * Is is not modified in any way.
599 */
600 int NCDValReplaceProg_Execute (NCDValReplaceProg prog, NCDValMem *mem, NCDVal_replace_func replace, void *arg);
601  
602 #endif