list.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /**
  2. * @file list.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * This file is part of BadVPN.
  8. *
  9. * BadVPN is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2
  11. * as published by the Free Software Foundation.
  12. *
  13. * BadVPN is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. *
  22. * @section DESCRIPTION
  23. *
  24. * List construction module.
  25. *
  26. * Synopsis:
  27. * list(elem1, ..., elemN)
  28. * list listfrom(list l1, ..., list lN)
  29. *
  30. * Description:
  31. * The first form creates a list with the given elements.
  32. * The second form creates a list by concatenating the given
  33. * lists.
  34. *
  35. * Variables:
  36. * (empty) - list containing elem1, ..., elemN
  37. * length - number of elements in list
  38. *
  39. * Synopsis: list::append(arg)
  40. *
  41. * Synopsis: list::appendv(list arg)
  42. * Description: Appends the elements of arg to the list.
  43. *
  44. * Synopsis: list::length()
  45. * Variables:
  46. * (empty) - number of elements in list at the time of initialization
  47. * of this method
  48. *
  49. * Synopsis: list::get(string index)
  50. * Variables:
  51. * (empty) - element of list at position index (starting from zero) at the time of initialization
  52. *
  53. * Synopsis: list::shift()
  54. *
  55. * Synopsis: list::contains(value)
  56. * Variables:
  57. * (empty) - "true" if list contains value, "false" if not
  58. *
  59. * Synopsis:
  60. * list::find(start_pos, value)
  61. * Description:
  62. * finds the first occurance of 'value' in the list at position >='start_pos'.
  63. * Variables:
  64. * pos - position of element, or "none" if not found
  65. * found - "true" if found, "false" if not
  66. */
  67. #include <stdlib.h>
  68. #include <string.h>
  69. #include <stdio.h>
  70. #include <inttypes.h>
  71. #include <misc/parse_number.h>
  72. #include <ncd/NCDModule.h>
  73. #include <generated/blog_channel_ncd_list.h>
  74. #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
  75. struct instance {
  76. NCDModuleInst *i;
  77. NCDValue list;
  78. };
  79. struct append_instance {
  80. NCDModuleInst *i;
  81. };
  82. struct appendv_instance {
  83. NCDModuleInst *i;
  84. };
  85. struct length_instance {
  86. NCDModuleInst *i;
  87. size_t length;
  88. };
  89. struct get_instance {
  90. NCDModuleInst *i;
  91. NCDValue value;
  92. };
  93. struct shift_instance {
  94. NCDModuleInst *i;
  95. };
  96. struct contains_instance {
  97. NCDModuleInst *i;
  98. int contains;
  99. };
  100. struct find_instance {
  101. NCDModuleInst *i;
  102. int is_found;
  103. size_t found_pos;
  104. };
  105. static void func_new_list (NCDModuleInst *i)
  106. {
  107. // allocate instance
  108. struct instance *o = malloc(sizeof(*o));
  109. if (!o) {
  110. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  111. goto fail0;
  112. }
  113. NCDModuleInst_Backend_SetUser(i, o);
  114. // init arguments
  115. o->i = i;
  116. // copy list
  117. if (!NCDValue_InitCopy(&o->list, i->args)) {
  118. ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
  119. goto fail1;
  120. }
  121. // signal up
  122. NCDModuleInst_Backend_Up(o->i);
  123. return;
  124. fail1:
  125. free(o);
  126. fail0:
  127. NCDModuleInst_Backend_SetError(i);
  128. NCDModuleInst_Backend_Dead(i);
  129. }
  130. static void func_new_listfrom (NCDModuleInst *i)
  131. {
  132. // allocate instance
  133. struct instance *o = malloc(sizeof(*o));
  134. if (!o) {
  135. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  136. goto fail0;
  137. }
  138. NCDModuleInst_Backend_SetUser(i, o);
  139. // init arguments
  140. o->i = i;
  141. // init list
  142. NCDValue_InitList(&o->list);
  143. // append contents of list arguments
  144. for (NCDValue *arg = NCDValue_ListFirst(i->args); arg; arg = NCDValue_ListNext(i->args, arg)) {
  145. // check type
  146. if (NCDValue_Type(arg) != NCDVALUE_LIST) {
  147. ModuleLog(i, BLOG_ERROR, "wrong type");
  148. goto fail2;
  149. }
  150. // copy list
  151. NCDValue copy;
  152. if (!NCDValue_InitCopy(&copy, arg)) {
  153. ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
  154. goto fail2;
  155. }
  156. // append
  157. if (!NCDValue_ListAppendList(&o->list, copy)) {
  158. ModuleLog(i, BLOG_ERROR, "NCDValue_ListAppendList failed");
  159. NCDValue_Free(&copy);
  160. goto fail2;
  161. }
  162. }
  163. // signal up
  164. NCDModuleInst_Backend_Up(o->i);
  165. return;
  166. fail2:
  167. NCDValue_Free(&o->list);
  168. fail1:
  169. free(o);
  170. fail0:
  171. NCDModuleInst_Backend_SetError(i);
  172. NCDModuleInst_Backend_Dead(i);
  173. }
  174. static void func_die (void *vo)
  175. {
  176. struct instance *o = vo;
  177. NCDModuleInst *i = o->i;
  178. // free list
  179. NCDValue_Free(&o->list);
  180. // free instance
  181. free(o);
  182. NCDModuleInst_Backend_Dead(i);
  183. }
  184. static int func_getvar (void *vo, const char *name, NCDValue *out)
  185. {
  186. struct instance *o = vo;
  187. if (!strcmp(name, "")) {
  188. if (!NCDValue_InitCopy(out, &o->list)) {
  189. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
  190. return 0;
  191. }
  192. return 1;
  193. }
  194. if (!strcmp(name, "length")) {
  195. char str[64];
  196. snprintf(str, sizeof(str), "%zu", NCDValue_ListCount(&o->list));
  197. if (!NCDValue_InitString(out, str)) {
  198. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
  199. return 0;
  200. }
  201. return 1;
  202. }
  203. return 0;
  204. }
  205. static void append_func_new (NCDModuleInst *i)
  206. {
  207. // allocate instance
  208. struct append_instance *o = malloc(sizeof(*o));
  209. if (!o) {
  210. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  211. goto fail0;
  212. }
  213. NCDModuleInst_Backend_SetUser(i, o);
  214. // init arguments
  215. o->i = i;
  216. // check arguments
  217. NCDValue *arg;
  218. if (!NCDValue_ListRead(o->i->args, 1, &arg)) {
  219. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  220. goto fail1;
  221. }
  222. // get method object
  223. struct instance *mo = i->method_object->inst_user;
  224. // append
  225. NCDValue v;
  226. if (!NCDValue_InitCopy(&v, arg)) {
  227. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
  228. goto fail1;
  229. }
  230. if (!NCDValue_ListAppend(&mo->list, v)) {
  231. NCDValue_Free(&v);
  232. ModuleLog(o->i, BLOG_ERROR, "NCDValue_ListAppend failed");
  233. goto fail1;
  234. }
  235. // signal up
  236. NCDModuleInst_Backend_Up(o->i);
  237. return;
  238. fail1:
  239. free(o);
  240. fail0:
  241. NCDModuleInst_Backend_SetError(i);
  242. NCDModuleInst_Backend_Dead(i);
  243. }
  244. static void append_func_die (void *vo)
  245. {
  246. struct append_instance *o = vo;
  247. NCDModuleInst *i = o->i;
  248. // free instance
  249. free(o);
  250. NCDModuleInst_Backend_Dead(i);
  251. }
  252. static void appendv_func_new (NCDModuleInst *i)
  253. {
  254. // allocate instance
  255. struct appendv_instance *o = malloc(sizeof(*o));
  256. if (!o) {
  257. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  258. goto fail0;
  259. }
  260. NCDModuleInst_Backend_SetUser(i, o);
  261. // init arguments
  262. o->i = i;
  263. // check arguments
  264. NCDValue *arg;
  265. if (!NCDValue_ListRead(o->i->args, 1, &arg)) {
  266. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  267. goto fail1;
  268. }
  269. if (NCDValue_Type(arg) != NCDVALUE_LIST) {
  270. ModuleLog(o->i, BLOG_ERROR, "wrong type");
  271. goto fail1;
  272. }
  273. // get method object
  274. struct instance *mo = i->method_object->inst_user;
  275. // append
  276. NCDValue l;
  277. if (!NCDValue_InitCopy(&l, arg)) {
  278. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
  279. goto fail1;
  280. }
  281. if (!NCDValue_ListAppendList(&mo->list, l)) {
  282. ModuleLog(o->i, BLOG_ERROR, "NCDValue_ListAppendList failed");
  283. NCDValue_Free(&l);
  284. goto fail1;
  285. }
  286. // signal up
  287. NCDModuleInst_Backend_Up(o->i);
  288. return;
  289. fail1:
  290. free(o);
  291. fail0:
  292. NCDModuleInst_Backend_SetError(i);
  293. NCDModuleInst_Backend_Dead(i);
  294. }
  295. static void appendv_func_die (void *vo)
  296. {
  297. struct appendv_instance *o = vo;
  298. NCDModuleInst *i = o->i;
  299. // free instance
  300. free(o);
  301. NCDModuleInst_Backend_Dead(i);
  302. }
  303. static void length_func_new (NCDModuleInst *i)
  304. {
  305. // allocate instance
  306. struct length_instance *o = malloc(sizeof(*o));
  307. if (!o) {
  308. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  309. goto fail0;
  310. }
  311. NCDModuleInst_Backend_SetUser(i, o);
  312. // init arguments
  313. o->i = i;
  314. // check arguments
  315. if (!NCDValue_ListRead(o->i->args, 0)) {
  316. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  317. goto fail1;
  318. }
  319. // get method object
  320. struct instance *mo = i->method_object->inst_user;
  321. // remember length
  322. o->length = NCDValue_ListCount(&mo->list);
  323. // signal up
  324. NCDModuleInst_Backend_Up(o->i);
  325. return;
  326. fail1:
  327. free(o);
  328. fail0:
  329. NCDModuleInst_Backend_SetError(i);
  330. NCDModuleInst_Backend_Dead(i);
  331. }
  332. static void length_func_die (void *vo)
  333. {
  334. struct length_instance *o = vo;
  335. NCDModuleInst *i = o->i;
  336. // free instance
  337. free(o);
  338. NCDModuleInst_Backend_Dead(i);
  339. }
  340. static int length_func_getvar (void *vo, const char *name, NCDValue *out)
  341. {
  342. struct length_instance *o = vo;
  343. if (!strcmp(name, "")) {
  344. char str[64];
  345. snprintf(str, sizeof(str), "%zu", o->length);
  346. if (!NCDValue_InitString(out, str)) {
  347. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
  348. return 0;
  349. }
  350. return 1;
  351. }
  352. return 0;
  353. }
  354. static void get_func_new (NCDModuleInst *i)
  355. {
  356. // allocate instance
  357. struct get_instance *o = malloc(sizeof(*o));
  358. if (!o) {
  359. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  360. goto fail0;
  361. }
  362. NCDModuleInst_Backend_SetUser(i, o);
  363. // init arguments
  364. o->i = i;
  365. // check arguments
  366. NCDValue *index_arg;
  367. if (!NCDValue_ListRead(o->i->args, 1, &index_arg)) {
  368. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  369. goto fail1;
  370. }
  371. if (NCDValue_Type(index_arg) != NCDVALUE_STRING) {
  372. ModuleLog(o->i, BLOG_ERROR, "wrong type");
  373. goto fail1;
  374. }
  375. uintmax_t index;
  376. if (!parse_unsigned_integer(NCDValue_StringValue(index_arg), &index)) {
  377. ModuleLog(o->i, BLOG_ERROR, "wrong value");
  378. goto fail1;
  379. }
  380. // get method object
  381. struct instance *mo = i->method_object->inst_user;
  382. // check index
  383. if (index >= NCDValue_ListCount(&mo->list)) {
  384. ModuleLog(o->i, BLOG_ERROR, "no element at index %"PRIuMAX, index);
  385. goto fail1;
  386. }
  387. // copy value
  388. if (!NCDValue_InitCopy(&o->value, NCDValue_ListGet(&mo->list, index))) {
  389. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
  390. goto fail1;
  391. }
  392. // signal up
  393. NCDModuleInst_Backend_Up(o->i);
  394. return;
  395. fail1:
  396. free(o);
  397. fail0:
  398. NCDModuleInst_Backend_SetError(i);
  399. NCDModuleInst_Backend_Dead(i);
  400. }
  401. static void get_func_die (void *vo)
  402. {
  403. struct get_instance *o = vo;
  404. NCDModuleInst *i = o->i;
  405. // free value
  406. NCDValue_Free(&o->value);
  407. // free instance
  408. free(o);
  409. NCDModuleInst_Backend_Dead(i);
  410. }
  411. static int get_func_getvar (void *vo, const char *name, NCDValue *out)
  412. {
  413. struct get_instance *o = vo;
  414. if (!strcmp(name, "")) {
  415. if (!NCDValue_InitCopy(out, &o->value)) {
  416. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
  417. return 0;
  418. }
  419. return 1;
  420. }
  421. return 0;
  422. }
  423. static void shift_func_new (NCDModuleInst *i)
  424. {
  425. // allocate instance
  426. struct shift_instance *o = malloc(sizeof(*o));
  427. if (!o) {
  428. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  429. goto fail0;
  430. }
  431. NCDModuleInst_Backend_SetUser(i, o);
  432. // init arguments
  433. o->i = i;
  434. // check arguments
  435. if (!NCDValue_ListRead(o->i->args, 0)) {
  436. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  437. goto fail1;
  438. }
  439. // get method object
  440. struct instance *mo = i->method_object->inst_user;
  441. // shift
  442. if (!NCDValue_ListFirst(&mo->list)) {
  443. ModuleLog(o->i, BLOG_ERROR, "list has no elements");
  444. goto fail1;
  445. }
  446. NCDValue v = NCDValue_ListShift(&mo->list);
  447. NCDValue_Free(&v);
  448. // signal up
  449. NCDModuleInst_Backend_Up(o->i);
  450. return;
  451. fail1:
  452. free(o);
  453. fail0:
  454. NCDModuleInst_Backend_SetError(i);
  455. NCDModuleInst_Backend_Dead(i);
  456. }
  457. static void shift_func_die (void *vo)
  458. {
  459. struct shift_instance *o = vo;
  460. NCDModuleInst *i = o->i;
  461. // free instance
  462. free(o);
  463. NCDModuleInst_Backend_Dead(i);
  464. }
  465. static void contains_func_new (NCDModuleInst *i)
  466. {
  467. // allocate instance
  468. struct contains_instance *o = malloc(sizeof(*o));
  469. if (!o) {
  470. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  471. goto fail0;
  472. }
  473. NCDModuleInst_Backend_SetUser(i, o);
  474. // init arguments
  475. o->i = i;
  476. // read arguments
  477. NCDValue *value_arg;
  478. if (!NCDValue_ListRead(i->args, 1, &value_arg)) {
  479. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  480. goto fail1;
  481. }
  482. // get method object
  483. struct instance *mo = i->method_object->inst_user;
  484. // search
  485. o->contains = 0;
  486. for (NCDValue *v = NCDValue_ListFirst(&mo->list); v; v = NCDValue_ListNext(&mo->list, v)) {
  487. if (NCDValue_Compare(v, value_arg) == 0) {
  488. o->contains = 1;
  489. break;
  490. }
  491. }
  492. // signal up
  493. NCDModuleInst_Backend_Up(o->i);
  494. return;
  495. fail1:
  496. free(o);
  497. fail0:
  498. NCDModuleInst_Backend_SetError(i);
  499. NCDModuleInst_Backend_Dead(i);
  500. }
  501. static void contains_func_die (void *vo)
  502. {
  503. struct contains_instance *o = vo;
  504. NCDModuleInst *i = o->i;
  505. // free instance
  506. free(o);
  507. NCDModuleInst_Backend_Dead(i);
  508. }
  509. static int contains_func_getvar (void *vo, const char *name, NCDValue *out)
  510. {
  511. struct contains_instance *o = vo;
  512. if (!strcmp(name, "")) {
  513. const char *value = (o->contains ? "true" : "false");
  514. if (!NCDValue_InitString(out, value)) {
  515. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
  516. return 0;
  517. }
  518. return 1;
  519. }
  520. return 0;
  521. }
  522. static void find_func_new (NCDModuleInst *i)
  523. {
  524. // allocate instance
  525. struct find_instance *o = malloc(sizeof(*o));
  526. if (!o) {
  527. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  528. goto fail0;
  529. }
  530. NCDModuleInst_Backend_SetUser(i, o);
  531. // init arguments
  532. o->i = i;
  533. // read arguments
  534. NCDValue *start_pos_arg;
  535. NCDValue *value_arg;
  536. if (!NCDValue_ListRead(i->args, 2, &start_pos_arg, &value_arg)) {
  537. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  538. goto fail1;
  539. }
  540. if (NCDValue_Type(start_pos_arg) != NCDVALUE_STRING) {
  541. ModuleLog(o->i, BLOG_ERROR, "wrong type");
  542. goto fail1;
  543. }
  544. // read start position
  545. uintmax_t start_pos;
  546. if (!parse_unsigned_integer(NCDValue_StringValue(start_pos_arg), &start_pos)) {
  547. ModuleLog(o->i, BLOG_ERROR, "wrong start pos");
  548. goto fail1;
  549. }
  550. // get method object
  551. struct instance *mo = i->method_object->inst_user;
  552. // search
  553. o->is_found = 0;
  554. size_t pos = 0;
  555. for (NCDValue *v = NCDValue_ListFirst(&mo->list); v; v = NCDValue_ListNext(&mo->list, v)) {
  556. if (pos >= start_pos && NCDValue_Compare(v, value_arg) == 0) {
  557. o->is_found = 1;
  558. o->found_pos = pos;
  559. break;
  560. }
  561. pos++;
  562. }
  563. // signal up
  564. NCDModuleInst_Backend_Up(o->i);
  565. return;
  566. fail1:
  567. free(o);
  568. fail0:
  569. NCDModuleInst_Backend_SetError(i);
  570. NCDModuleInst_Backend_Dead(i);
  571. }
  572. static void find_func_die (void *vo)
  573. {
  574. struct find_instance *o = vo;
  575. NCDModuleInst *i = o->i;
  576. // free instance
  577. free(o);
  578. NCDModuleInst_Backend_Dead(i);
  579. }
  580. static int find_func_getvar (void *vo, const char *name, NCDValue *out)
  581. {
  582. struct find_instance *o = vo;
  583. if (!strcmp(name, "pos")) {
  584. char value[64];
  585. if (o->is_found) {
  586. snprintf(value, sizeof(value), "%zu", o->found_pos);
  587. } else {
  588. snprintf(value, sizeof(value), "none");
  589. }
  590. if (!NCDValue_InitString(out, value)) {
  591. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
  592. return 0;
  593. }
  594. return 1;
  595. }
  596. if (!strcmp(name, "found")) {
  597. const char *value = (o->is_found ? "true" : "false");
  598. if (!NCDValue_InitString(out, value)) {
  599. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
  600. return 0;
  601. }
  602. return 1;
  603. }
  604. return 0;
  605. }
  606. static const struct NCDModule modules[] = {
  607. {
  608. .type = "list",
  609. .func_new = func_new_list,
  610. .func_die = func_die,
  611. .func_getvar = func_getvar
  612. }, {
  613. .type = "listfrom",
  614. .base_type = "list",
  615. .func_new = func_new_listfrom,
  616. .func_die = func_die,
  617. .func_getvar = func_getvar
  618. }, {
  619. .type = "concatlist", // alias for listfrom
  620. .base_type = "list",
  621. .func_new = func_new_listfrom,
  622. .func_die = func_die,
  623. .func_getvar = func_getvar
  624. }, {
  625. .type = "list::append",
  626. .func_new = append_func_new,
  627. .func_die = append_func_die
  628. }, {
  629. .type = "list::appendv",
  630. .func_new = appendv_func_new,
  631. .func_die = appendv_func_die
  632. }, {
  633. .type = "list::length",
  634. .func_new = length_func_new,
  635. .func_die = length_func_die,
  636. .func_getvar = length_func_getvar
  637. }, {
  638. .type = "list::get",
  639. .func_new = get_func_new,
  640. .func_die = get_func_die,
  641. .func_getvar = get_func_getvar
  642. }, {
  643. .type = "list::shift",
  644. .func_new = shift_func_new,
  645. .func_die = shift_func_die
  646. }, {
  647. .type = "list::contains",
  648. .func_new = contains_func_new,
  649. .func_die = contains_func_die,
  650. .func_getvar = contains_func_getvar
  651. }, {
  652. .type = "list::find",
  653. .func_new = find_func_new,
  654. .func_die = find_func_die,
  655. .func_getvar = find_func_getvar
  656. }, {
  657. .type = NULL
  658. }
  659. };
  660. const struct NCDModuleGroup ncdmodule_list = {
  661. .modules = modules
  662. };