BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file list.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * @section DESCRIPTION
30 *
31 * List construction module.
32 *
33 * Synopsis:
34 * list(elem1, ..., elemN)
35 * list listfrom(list l1, ..., list lN)
36 *
37 * Description:
38 * The first form creates a list with the given elements.
39 * The second form creates a list by concatenating the given
40 * lists.
41 *
42 * Variables:
43 * (empty) - list containing elem1, ..., elemN
44 * length - number of elements in list
45 *
46 * Synopsis: list::append(arg)
47 *
48 * Synopsis: list::appendv(list arg)
49 * Description: Appends the elements of arg to the list.
50 *
51 * Synopsis: list::length()
52 * Variables:
53 * (empty) - number of elements in list at the time of initialization
54 * of this method
55 *
56 * Synopsis: list::get(string index)
57 * Variables:
58 * (empty) - element of list at position index (starting from zero) at the time of initialization
59 *
60 * Synopsis: list::shift()
61 *
62 * Synopsis: list::contains(value)
63 * Variables:
64 * (empty) - "true" if list contains value, "false" if not
65 *
66 * Synopsis:
67 * list::find(start_pos, value)
68 * Description:
69 * finds the first occurrence of 'value' in the list at position >='start_pos'.
70 * Variables:
71 * pos - position of element, or "none" if not found
72 * found - "true" if found, "false" if not
73 *
74 * Sysnopsis:
75 * list::remove_at(remove_pos)
76 * Description:
77 * Removes the element at position 'remove_pos', which must refer to an existing element.
78 *
79 * Synopsis:
80 * list::remove(value)
81 * Description:
82 * Removes the first occurrence of value in the list, which must be in the list.
83 *
84 * Synopsis:
85 * list::set(list l1, ..., list lN)
86 * Description:
87 * Replaces the list with the concatenation of given lists.
88 */
89  
90 #include <stdlib.h>
91 #include <string.h>
92 #include <stdio.h>
93 #include <inttypes.h>
94  
95 #include <misc/offset.h>
96 #include <misc/parse_number.h>
97 #include <structure/IndexedList.h>
98  
99 #include <ncd/module_common.h>
100  
101 #include <generated/blog_channel_ncd_list.h>
102  
103 struct elem {
104 IndexedListNode il_node;
105 NCDValMem mem;
106 NCDValRef val;
107 };
108  
109 struct instance {
110 NCDModuleInst *i;
111 IndexedList il;
112 };
113  
114 struct length_instance {
115 NCDModuleInst *i;
116 uint64_t length;
117 };
118  
119 struct get_instance {
120 NCDModuleInst *i;
121 NCDValMem mem;
122 NCDValRef val;
123 };
124  
125 struct contains_instance {
126 NCDModuleInst *i;
127 int contains;
128 };
129  
130 struct find_instance {
131 NCDModuleInst *i;
132 int is_found;
133 uint64_t found_pos;
134 };
135  
136 static uint64_t list_count (struct instance *o)
137 {
138 return IndexedList_Count(&o->il);
139 }
140  
141 static struct elem * insert_value (NCDModuleInst *i, struct instance *o, NCDValRef val, uint64_t idx)
142 {
143 ASSERT(idx <= list_count(o))
144 ASSERT(!NCDVal_IsInvalid(val))
145  
146 struct elem *e = malloc(sizeof(*e));
147 if (!e) {
148 ModuleLog(i, BLOG_ERROR, "malloc failed");
149 goto fail0;
150 }
151  
152 NCDValMem_Init(&e->mem, i->params->iparams->string_index);
153  
154 e->val = NCDVal_NewCopy(&e->mem, val);
155 if (NCDVal_IsInvalid(e->val)) {
156 goto fail1;
157 }
158  
159 IndexedList_InsertAt(&o->il, &e->il_node, idx);
160  
161 return e;
162  
163 fail1:
164 NCDValMem_Free(&e->mem);
165 free(e);
166 fail0:
167 return NULL;
168 }
169  
170 static void remove_elem (struct instance *o, struct elem *e)
171 {
172 IndexedList_Remove(&o->il, &e->il_node);
173 NCDValMem_Free(&e->mem);
174 free(e);
175 }
176  
177 static struct elem * get_elem_at (struct instance *o, uint64_t idx)
178 {
179 ASSERT(idx < list_count(o))
180  
181 IndexedListNode *iln = IndexedList_GetAt(&o->il, idx);
182 struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
183  
184 return e;
185 }
186  
187 static struct elem * get_first_elem (struct instance *o)
188 {
189 ASSERT(list_count(o) > 0)
190  
191 IndexedListNode *iln = IndexedList_GetFirst(&o->il);
192 struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
193  
194 return e;
195 }
196  
197 static struct elem * get_last_elem (struct instance *o)
198 {
199 ASSERT(list_count(o) > 0)
200  
201 IndexedListNode *iln = IndexedList_GetLast(&o->il);
202 struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
203  
204 return e;
205 }
206  
207 static void cut_list_front (struct instance *o, uint64_t count)
208 {
209 while (list_count(o) > count) {
210 remove_elem(o, get_first_elem(o));
211 }
212 }
213  
214 static void cut_list_back (struct instance *o, uint64_t count)
215 {
216 while (list_count(o) > count) {
217 remove_elem(o, get_last_elem(o));
218 }
219 }
220  
221 static int append_list_contents (NCDModuleInst *i, struct instance *o, NCDValRef args)
222 {
223 ASSERT(NCDVal_IsList(args))
224  
225 uint64_t orig_count = list_count(o);
226  
227 size_t append_count = NCDVal_ListCount(args);
228  
229 for (size_t j = 0; j < append_count; j++) {
230 NCDValRef elem = NCDVal_ListGet(args, j);
231 if (!insert_value(i, o, elem, list_count(o))) {
232 goto fail;
233 }
234 }
235  
236 return 1;
237  
238 fail:
239 cut_list_back(o, orig_count);
240 return 0;
241 }
242  
243 static int append_list_contents_contents (NCDModuleInst *i, struct instance *o, NCDValRef args)
244 {
245 ASSERT(NCDVal_IsList(args))
246  
247 uint64_t orig_count = list_count(o);
248  
249 size_t append_count = NCDVal_ListCount(args);
250  
251 for (size_t j = 0; j < append_count; j++) {
252 NCDValRef elem = NCDVal_ListGet(args, j);
253  
254 if (!NCDVal_IsList(elem)) {
255 ModuleLog(i, BLOG_ERROR, "wrong type");
256 goto fail;
257 }
258  
259 if (!append_list_contents(i, o, elem)) {
260 goto fail;
261 }
262 }
263  
264 return 1;
265  
266 fail:
267 cut_list_back(o, orig_count);
268 return 0;
269 }
270  
271 static struct elem * find_elem (struct instance *o, NCDValRef val, uint64_t start_idx, uint64_t *out_idx)
272 {
273 if (start_idx >= list_count(o)) {
274 return NULL;
275 }
276  
277 for (IndexedListNode *iln = IndexedList_GetAt(&o->il, start_idx); iln; iln = IndexedList_GetNext(&o->il, iln)) {
278 struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
279 if (NCDVal_Compare(e->val, val) == 0) {
280 if (out_idx) {
281 *out_idx = start_idx;
282 }
283 return e;
284 }
285 start_idx++;
286 }
287  
288 return NULL;
289 }
290  
291 static int list_to_value (NCDModuleInst *i, struct instance *o, NCDValMem *mem, NCDValRef *out_val)
292 {
293 *out_val = NCDVal_NewList(mem, IndexedList_Count(&o->il));
294 if (NCDVal_IsInvalid(*out_val)) {
295 goto fail;
296 }
297  
298 for (IndexedListNode *iln = IndexedList_GetFirst(&o->il); iln; iln = IndexedList_GetNext(&o->il, iln)) {
299 struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
300  
301 NCDValRef copy = NCDVal_NewCopy(mem, e->val);
302 if (NCDVal_IsInvalid(copy)) {
303 goto fail;
304 }
305  
306 if (!NCDVal_ListAppend(*out_val, copy)) {
307 goto fail;
308 }
309 }
310  
311 return 1;
312  
313 fail:
314 return 0;
315 }
316  
317 static void func_new_list (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
318 {
319 struct instance *o = vo;
320 o->i = i;
321  
322 // init list
323 IndexedList_Init(&o->il);
324  
325 // append contents
326 if (!append_list_contents(i, o, params->args)) {
327 goto fail1;
328 }
329  
330 // signal up
331 NCDModuleInst_Backend_Up(o->i);
332 return;
333  
334 fail1:
335 cut_list_front(o, 0);
336 NCDModuleInst_Backend_DeadError(i);
337 }
338  
339 static void func_new_listfrom (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
340 {
341 struct instance *o = vo;
342 o->i = i;
343  
344 // init list
345 IndexedList_Init(&o->il);
346  
347 // append contents contents
348 if (!append_list_contents_contents(i, o, params->args)) {
349 goto fail1;
350 }
351  
352 // signal up
353 NCDModuleInst_Backend_Up(o->i);
354 return;
355  
356 fail1:
357 cut_list_front(o, 0);
358 NCDModuleInst_Backend_DeadError(i);
359 }
360  
361 static void func_die (void *vo)
362 {
363 struct instance *o = vo;
364  
365 // free list elements
366 cut_list_front(o, 0);
367  
368 NCDModuleInst_Backend_Dead(o->i);
369 }
370  
371 static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
372 {
373 struct instance *o = vo;
374  
375 if (!strcmp(name, "")) {
376 if (!list_to_value(o->i, o, mem, out)) {
377 return 0;
378 }
379  
380 return 1;
381 }
382  
383 if (!strcmp(name, "length")) {
384 *out = ncd_make_uintmax(mem, list_count(o));
385 return 1;
386 }
387  
388 return 0;
389 }
390  
391 static void append_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
392 {
393 // check arguments
394 NCDValRef arg;
395 if (!NCDVal_ListRead(params->args, 1, &arg)) {
396 ModuleLog(i, BLOG_ERROR, "wrong arity");
397 goto fail0;
398 }
399  
400 // get method object
401 struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
402  
403 // append
404 if (!insert_value(i, mo, arg, list_count(mo))) {
405 goto fail0;
406 }
407  
408 // signal up
409 NCDModuleInst_Backend_Up(i);
410 return;
411  
412 fail0:
413 NCDModuleInst_Backend_DeadError(i);
414 }
415  
416 static void appendv_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
417 {
418 // check arguments
419 NCDValRef arg;
420 if (!NCDVal_ListRead(params->args, 1, &arg)) {
421 ModuleLog(i, BLOG_ERROR, "wrong arity");
422 goto fail0;
423 }
424 if (!NCDVal_IsList(arg)) {
425 ModuleLog(i, BLOG_ERROR, "wrong type");
426 goto fail0;
427 }
428  
429 // get method object
430 struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
431  
432 // append
433 if (!append_list_contents(i, mo, arg)) {
434 goto fail0;
435 }
436  
437 // signal up
438 NCDModuleInst_Backend_Up(i);
439 return;
440  
441 fail0:
442 NCDModuleInst_Backend_DeadError(i);
443 }
444  
445 static void length_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
446 {
447 struct length_instance *o = vo;
448 o->i = i;
449  
450 // check arguments
451 if (!NCDVal_ListRead(params->args, 0)) {
452 ModuleLog(o->i, BLOG_ERROR, "wrong arity");
453 goto fail0;
454 }
455  
456 // get method object
457 struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
458  
459 // remember length
460 o->length = list_count(mo);
461  
462 // signal up
463 NCDModuleInst_Backend_Up(o->i);
464  
465 return;
466  
467 fail0:
468 NCDModuleInst_Backend_DeadError(i);
469 }
470  
471 static void length_func_die (void *vo)
472 {
473 struct length_instance *o = vo;
474  
475 NCDModuleInst_Backend_Dead(o->i);
476 }
477  
478 static int length_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
479 {
480 struct length_instance *o = vo;
481  
482 if (!strcmp(name, "")) {
483 *out = ncd_make_uintmax(mem, o->length);
484 return 1;
485 }
486  
487 return 0;
488 }
489  
490 static void get_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
491 {
492 struct get_instance *o = vo;
493 o->i = i;
494  
495 // check arguments
496 NCDValRef index_arg;
497 if (!NCDVal_ListRead(params->args, 1, &index_arg)) {
498 ModuleLog(o->i, BLOG_ERROR, "wrong arity");
499 goto fail0;
500 }
501 uintmax_t index;
502 if (!ncd_read_uintmax(index_arg, &index)) {
503 ModuleLog(o->i, BLOG_ERROR, "wrong value");
504 goto fail0;
505 }
506  
507 // get method object
508 struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
509  
510 // check index
511 if (index >= list_count(mo)) {
512 ModuleLog(o->i, BLOG_ERROR, "no element at index %"PRIuMAX, index);
513 goto fail0;
514 }
515  
516 // get element
517 struct elem *e = get_elem_at(mo, index);
518  
519 // init mem
520 NCDValMem_Init(&o->mem, i->params->iparams->string_index);
521  
522 // copy value
523 o->val = NCDVal_NewCopy(&o->mem, e->val);
524 if (NCDVal_IsInvalid(o->val)) {
525 goto fail1;
526 }
527  
528 // signal up
529 NCDModuleInst_Backend_Up(o->i);
530 return;
531  
532 fail1:
533 NCDValMem_Free(&o->mem);
534 fail0:
535 NCDModuleInst_Backend_DeadError(i);
536 }
537  
538 static void get_func_die (void *vo)
539 {
540 struct get_instance *o = vo;
541  
542 // free mem
543 NCDValMem_Free(&o->mem);
544  
545 NCDModuleInst_Backend_Dead(o->i);
546 }
547  
548 static int get_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
549 {
550 struct get_instance *o = vo;
551  
552 if (!strcmp(name, "")) {
553 *out = NCDVal_NewCopy(mem, o->val);
554 return 1;
555 }
556  
557 return 0;
558 }
559  
560 static void shift_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
561 {
562 // check arguments
563 if (!NCDVal_ListRead(params->args, 0)) {
564 ModuleLog(i, BLOG_ERROR, "wrong arity");
565 goto fail0;
566 }
567  
568 // get method object
569 struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
570  
571 // check first
572 if (list_count(mo) == 0) {
573 ModuleLog(i, BLOG_ERROR, "list has no elements");
574 goto fail0;
575 }
576  
577 // remove first
578 remove_elem(mo, get_first_elem(mo));
579  
580 // signal up
581 NCDModuleInst_Backend_Up(i);
582 return;
583  
584 fail0:
585 NCDModuleInst_Backend_DeadError(i);
586 }
587  
588 static void contains_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
589 {
590 struct contains_instance *o = vo;
591 o->i = i;
592  
593 // read arguments
594 NCDValRef value_arg;
595 if (!NCDVal_ListRead(params->args, 1, &value_arg)) {
596 ModuleLog(o->i, BLOG_ERROR, "wrong arity");
597 goto fail0;
598 }
599  
600 // get method object
601 struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
602  
603 // search
604 o->contains = !!find_elem(mo, value_arg, 0, NULL);
605  
606 // signal up
607 NCDModuleInst_Backend_Up(o->i);
608 return;
609  
610 fail0:
611 NCDModuleInst_Backend_DeadError(i);
612 }
613  
614 static void contains_func_die (void *vo)
615 {
616 struct contains_instance *o = vo;
617  
618 NCDModuleInst_Backend_Dead(o->i);
619 }
620  
621 static int contains_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
622 {
623 struct contains_instance *o = vo;
624  
625 if (!strcmp(name, "")) {
626 *out = ncd_make_boolean(mem, o->contains);
627 return 1;
628 }
629  
630 return 0;
631 }
632  
633 static void find_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
634 {
635 struct find_instance *o = vo;
636 o->i = i;
637  
638 // read arguments
639 NCDValRef start_pos_arg;
640 NCDValRef value_arg;
641 if (!NCDVal_ListRead(params->args, 2, &start_pos_arg, &value_arg)) {
642 ModuleLog(o->i, BLOG_ERROR, "wrong arity");
643 goto fail0;
644 }
645  
646 // read start position
647 uintmax_t start_pos;
648 if (!ncd_read_uintmax(start_pos_arg, &start_pos) || start_pos > UINT64_MAX) {
649 ModuleLog(o->i, BLOG_ERROR, "wrong start pos");
650 goto fail0;
651 }
652  
653 // get method object
654 struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
655  
656 // find
657 o->is_found = !!find_elem(mo, value_arg, start_pos, &o->found_pos);
658  
659 // signal up
660 NCDModuleInst_Backend_Up(o->i);
661 return;
662  
663 fail0:
664 NCDModuleInst_Backend_DeadError(i);
665 }
666  
667 static void find_func_die (void *vo)
668 {
669 struct find_instance *o = vo;
670  
671 NCDModuleInst_Backend_Dead(o->i);
672 }
673  
674 static int find_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
675 {
676 struct find_instance *o = vo;
677  
678 if (!strcmp(name, "pos")) {
679 char value[64] = "none";
680  
681 if (o->is_found) {
682 generate_decimal_repr_string(o->found_pos, value);
683 }
684  
685 *out = NCDVal_NewString(mem, value);
686 return 1;
687 }
688  
689 if (!strcmp(name, "found")) {
690 *out = ncd_make_boolean(mem, o->is_found);
691 return 1;
692 }
693  
694 return 0;
695 }
696  
697 static void removeat_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
698 {
699 // read arguments
700 NCDValRef remove_pos_arg;
701 if (!NCDVal_ListRead(params->args, 1, &remove_pos_arg)) {
702 ModuleLog(i, BLOG_ERROR, "wrong arity");
703 goto fail0;
704 }
705  
706 // read position
707 uintmax_t remove_pos;
708 if (!ncd_read_uintmax(remove_pos_arg, &remove_pos)) {
709 ModuleLog(i, BLOG_ERROR, "wrong pos");
710 goto fail0;
711 }
712  
713 // get method object
714 struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
715  
716 // check position
717 if (remove_pos >= list_count(mo)) {
718 ModuleLog(i, BLOG_ERROR, "pos out of range");
719 goto fail0;
720 }
721  
722 // remove
723 remove_elem(mo, get_elem_at(mo, remove_pos));
724  
725 // signal up
726 NCDModuleInst_Backend_Up(i);
727 return;
728  
729 fail0:
730 NCDModuleInst_Backend_DeadError(i);
731 }
732  
733 static void remove_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
734 {
735 // read arguments
736 NCDValRef value_arg;
737 if (!NCDVal_ListRead(params->args, 1, &value_arg)) {
738 ModuleLog(i, BLOG_ERROR, "wrong arity");
739 goto fail0;
740 }
741  
742 // get method object
743 struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
744  
745 // find element
746 struct elem *e = find_elem(mo, value_arg, 0, NULL);
747 if (!e) {
748 ModuleLog(i, BLOG_ERROR, "value does not exist");
749 goto fail0;
750 }
751  
752 // remove element
753 remove_elem(mo, e);
754  
755 // signal up
756 NCDModuleInst_Backend_Up(i);
757 return;
758  
759 fail0:
760 NCDModuleInst_Backend_DeadError(i);
761 }
762  
763 static void set_func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
764 {
765 // get method object
766 struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)params->method_user);
767  
768 // remember old count
769 uint64_t old_count = list_count(mo);
770  
771 // append contents of our lists
772 if (!append_list_contents_contents(i, mo, params->args)) {
773 goto fail0;
774 }
775  
776 // remove old elements
777 cut_list_front(mo, list_count(mo) - old_count);
778  
779 // signal up
780 NCDModuleInst_Backend_Up(i);
781 return;
782  
783 fail0:
784 NCDModuleInst_Backend_DeadError(i);
785 }
786  
787 static struct NCDModule modules[] = {
788 {
789 .type = "list",
790 .func_new2 = func_new_list,
791 .func_die = func_die,
792 .func_getvar = func_getvar,
793 .alloc_size = sizeof(struct instance)
794 }, {
795 .type = "listfrom",
796 .base_type = "list",
797 .func_new2 = func_new_listfrom,
798 .func_die = func_die,
799 .func_getvar = func_getvar,
800 .alloc_size = sizeof(struct instance)
801 }, {
802 .type = "concatlist", // alias for listfrom
803 .base_type = "list",
804 .func_new2 = func_new_listfrom,
805 .func_die = func_die,
806 .func_getvar = func_getvar,
807 .alloc_size = sizeof(struct instance)
808 }, {
809 .type = "list::append",
810 .func_new2 = append_func_new
811 }, {
812 .type = "list::appendv",
813 .func_new2 = appendv_func_new
814 }, {
815 .type = "list::length",
816 .func_new2 = length_func_new,
817 .func_die = length_func_die,
818 .func_getvar = length_func_getvar,
819 .alloc_size = sizeof(struct length_instance)
820 }, {
821 .type = "list::get",
822 .func_new2 = get_func_new,
823 .func_die = get_func_die,
824 .func_getvar = get_func_getvar,
825 .alloc_size = sizeof(struct get_instance)
826 }, {
827 .type = "list::shift",
828 .func_new2 = shift_func_new
829 }, {
830 .type = "list::contains",
831 .func_new2 = contains_func_new,
832 .func_die = contains_func_die,
833 .func_getvar = contains_func_getvar,
834 .alloc_size = sizeof(struct contains_instance)
835 }, {
836 .type = "list::find",
837 .func_new2 = find_func_new,
838 .func_die = find_func_die,
839 .func_getvar = find_func_getvar,
840 .alloc_size = sizeof(struct find_instance)
841 }, {
842 .type = "list::remove_at",
843 .func_new2 = removeat_func_new
844 }, {
845 .type = "list::remove",
846 .func_new2 = remove_func_new
847 }, {
848 .type = "list::set",
849 .func_new2 = set_func_new
850 }, {
851 .type = NULL
852 }
853 };
854  
855 const struct NCDModuleGroup ncdmodule_list = {
856 .modules = modules
857 };