list.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  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. #include <stdlib.h>
  90. #include <string.h>
  91. #include <stdio.h>
  92. #include <inttypes.h>
  93. #include <misc/parse_number.h>
  94. #include <misc/offset.h>
  95. #include <structure/IndexedList.h>
  96. #include <ncd/NCDModule.h>
  97. #include <generated/blog_channel_ncd_list.h>
  98. #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
  99. struct elem {
  100. IndexedListNode il_node;
  101. NCDValMem mem;
  102. NCDValRef val;
  103. };
  104. struct instance {
  105. NCDModuleInst *i;
  106. IndexedList il;
  107. };
  108. struct length_instance {
  109. NCDModuleInst *i;
  110. uint64_t length;
  111. };
  112. struct get_instance {
  113. NCDModuleInst *i;
  114. NCDValMem mem;
  115. NCDValRef val;
  116. };
  117. struct contains_instance {
  118. NCDModuleInst *i;
  119. int contains;
  120. };
  121. struct find_instance {
  122. NCDModuleInst *i;
  123. int is_found;
  124. uint64_t found_pos;
  125. };
  126. static uint64_t list_count (struct instance *o)
  127. {
  128. return IndexedList_Count(&o->il);
  129. }
  130. static struct elem * insert_value (NCDModuleInst *i, struct instance *o, NCDValRef val, uint64_t idx)
  131. {
  132. ASSERT(idx <= list_count(o))
  133. ASSERT(!NCDVal_IsInvalid(val))
  134. struct elem *e = malloc(sizeof(*e));
  135. if (!e) {
  136. ModuleLog(i, BLOG_ERROR, "malloc failed");
  137. goto fail0;
  138. }
  139. NCDValMem_Init(&e->mem);
  140. e->val = NCDVal_NewCopy(&e->mem, val);
  141. if (NCDVal_IsInvalid(e->val)) {
  142. ModuleLog(i, BLOG_ERROR, "NCDVal_NewCopy failed");
  143. goto fail1;
  144. }
  145. IndexedList_InsertAt(&o->il, &e->il_node, idx);
  146. return e;
  147. fail1:
  148. NCDValMem_Free(&e->mem);
  149. free(e);
  150. fail0:
  151. return NULL;
  152. }
  153. static void remove_elem (struct instance *o, struct elem *e)
  154. {
  155. IndexedList_Remove(&o->il, &e->il_node);
  156. NCDValMem_Free(&e->mem);
  157. free(e);
  158. }
  159. static struct elem * get_elem_at (struct instance *o, uint64_t idx)
  160. {
  161. ASSERT(idx < list_count(o))
  162. IndexedListNode *iln = IndexedList_GetAt(&o->il, idx);
  163. struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
  164. return e;
  165. }
  166. static struct elem * get_first_elem (struct instance *o)
  167. {
  168. ASSERT(list_count(o) > 0)
  169. IndexedListNode *iln = IndexedList_GetFirst(&o->il);
  170. struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
  171. return e;
  172. }
  173. static struct elem * get_last_elem (struct instance *o)
  174. {
  175. ASSERT(list_count(o) > 0)
  176. IndexedListNode *iln = IndexedList_GetLast(&o->il);
  177. struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
  178. return e;
  179. }
  180. static void cut_list_front (struct instance *o, uint64_t count)
  181. {
  182. while (list_count(o) > count) {
  183. remove_elem(o, get_first_elem(o));
  184. }
  185. }
  186. static void cut_list_back (struct instance *o, uint64_t count)
  187. {
  188. while (list_count(o) > count) {
  189. remove_elem(o, get_last_elem(o));
  190. }
  191. }
  192. static int append_list_contents (NCDModuleInst *i, struct instance *o, NCDValRef args)
  193. {
  194. ASSERT(NCDVal_IsList(args))
  195. uint64_t orig_count = list_count(o);
  196. size_t append_count = NCDVal_ListCount(args);
  197. for (size_t j = 0; j < append_count; j++) {
  198. NCDValRef elem = NCDVal_ListGet(args, j);
  199. if (!insert_value(i, o, elem, list_count(o))) {
  200. goto fail;
  201. }
  202. }
  203. return 1;
  204. fail:
  205. cut_list_back(o, orig_count);
  206. return 0;
  207. }
  208. static int append_list_contents_contents (NCDModuleInst *i, struct instance *o, NCDValRef args)
  209. {
  210. ASSERT(NCDVal_IsList(args))
  211. uint64_t orig_count = list_count(o);
  212. size_t append_count = NCDVal_ListCount(args);
  213. for (size_t j = 0; j < append_count; j++) {
  214. NCDValRef elem = NCDVal_ListGet(args, j);
  215. if (!NCDVal_IsList(elem)) {
  216. ModuleLog(i, BLOG_ERROR, "wrong type");
  217. goto fail;
  218. }
  219. if (!append_list_contents(i, o, elem)) {
  220. goto fail;
  221. }
  222. }
  223. return 1;
  224. fail:
  225. cut_list_back(o, orig_count);
  226. return 0;
  227. }
  228. static struct elem * find_elem (struct instance *o, NCDValRef val, uint64_t start_idx, uint64_t *out_idx)
  229. {
  230. if (start_idx >= list_count(o)) {
  231. return NULL;
  232. }
  233. for (IndexedListNode *iln = IndexedList_GetAt(&o->il, start_idx); iln; iln = IndexedList_GetNext(&o->il, iln)) {
  234. struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
  235. if (NCDVal_Compare(e->val, val) == 0) {
  236. if (out_idx) {
  237. *out_idx = start_idx;
  238. }
  239. return e;
  240. }
  241. start_idx++;
  242. }
  243. return NULL;
  244. }
  245. static int list_to_value (NCDModuleInst *i, struct instance *o, NCDValMem *mem, NCDValRef *out_val)
  246. {
  247. *out_val = NCDVal_NewList(mem, IndexedList_Count(&o->il));
  248. if (NCDVal_IsInvalid(*out_val)) {
  249. ModuleLog(i, BLOG_ERROR, "NCDVal_NewList failed");
  250. goto fail;
  251. }
  252. for (IndexedListNode *iln = IndexedList_GetFirst(&o->il); iln; iln = IndexedList_GetNext(&o->il, iln)) {
  253. struct elem *e = UPPER_OBJECT(iln, struct elem, il_node);
  254. NCDValRef copy = NCDVal_NewCopy(mem, e->val);
  255. if (NCDVal_IsInvalid(copy)) {
  256. ModuleLog(i, BLOG_ERROR, "NCDVal_NewCopy failed");
  257. goto fail;
  258. }
  259. NCDVal_ListAppend(*out_val, copy);
  260. }
  261. return 1;
  262. fail:
  263. return 0;
  264. }
  265. static void func_new_list (NCDModuleInst *i)
  266. {
  267. // allocate instance
  268. struct instance *o = malloc(sizeof(*o));
  269. if (!o) {
  270. ModuleLog(i, BLOG_ERROR, "malloc failed");
  271. goto fail0;
  272. }
  273. o->i = i;
  274. NCDModuleInst_Backend_SetUser(i, o);
  275. // init list
  276. IndexedList_Init(&o->il);
  277. // append contents
  278. if (!append_list_contents(i, o, i->args)) {
  279. goto fail1;
  280. }
  281. // signal up
  282. NCDModuleInst_Backend_Up(o->i);
  283. return;
  284. fail1:
  285. cut_list_front(o, 0);
  286. free(o);
  287. fail0:
  288. NCDModuleInst_Backend_SetError(i);
  289. NCDModuleInst_Backend_Dead(i);
  290. }
  291. static void func_new_listfrom (NCDModuleInst *i)
  292. {
  293. // allocate instance
  294. struct instance *o = malloc(sizeof(*o));
  295. if (!o) {
  296. ModuleLog(i, BLOG_ERROR, "malloc failed");
  297. goto fail0;
  298. }
  299. o->i = i;
  300. NCDModuleInst_Backend_SetUser(i, o);
  301. // init list
  302. IndexedList_Init(&o->il);
  303. // append contents contents
  304. if (!append_list_contents_contents(i, o, i->args)) {
  305. goto fail1;
  306. }
  307. // signal up
  308. NCDModuleInst_Backend_Up(o->i);
  309. return;
  310. fail1:
  311. cut_list_front(o, 0);
  312. free(o);
  313. fail0:
  314. NCDModuleInst_Backend_SetError(i);
  315. NCDModuleInst_Backend_Dead(i);
  316. }
  317. static void func_die (void *vo)
  318. {
  319. struct instance *o = vo;
  320. NCDModuleInst *i = o->i;
  321. // free list elements
  322. cut_list_front(o, 0);
  323. // free instance
  324. free(o);
  325. NCDModuleInst_Backend_Dead(i);
  326. }
  327. static int func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
  328. {
  329. struct instance *o = vo;
  330. if (!strcmp(name, "")) {
  331. if (!list_to_value(o->i, o, mem, out)) {
  332. return 0;
  333. }
  334. return 1;
  335. }
  336. if (!strcmp(name, "length")) {
  337. char str[64];
  338. snprintf(str, sizeof(str), "%"PRIu64, list_count(o));
  339. *out = NCDVal_NewString(mem, str);
  340. if (NCDVal_IsInvalid(*out)) {
  341. ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
  342. }
  343. return 1;
  344. }
  345. return 0;
  346. }
  347. static void append_func_new (NCDModuleInst *i)
  348. {
  349. // check arguments
  350. NCDValRef arg;
  351. if (!NCDVal_ListRead(i->args, 1, &arg)) {
  352. ModuleLog(i, BLOG_ERROR, "wrong arity");
  353. goto fail0;
  354. }
  355. // get method object
  356. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  357. // append
  358. if (!insert_value(i, mo, arg, list_count(mo))) {
  359. goto fail0;
  360. }
  361. // signal up
  362. NCDModuleInst_Backend_Up(i);
  363. return;
  364. fail0:
  365. NCDModuleInst_Backend_SetError(i);
  366. NCDModuleInst_Backend_Dead(i);
  367. }
  368. static void appendv_func_new (NCDModuleInst *i)
  369. {
  370. // check arguments
  371. NCDValRef arg;
  372. if (!NCDVal_ListRead(i->args, 1, &arg)) {
  373. ModuleLog(i, BLOG_ERROR, "wrong arity");
  374. goto fail0;
  375. }
  376. if (!NCDVal_IsList(arg)) {
  377. ModuleLog(i, BLOG_ERROR, "wrong type");
  378. goto fail0;
  379. }
  380. // get method object
  381. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  382. // append
  383. if (!append_list_contents(i, mo, arg)) {
  384. goto fail0;
  385. }
  386. // signal up
  387. NCDModuleInst_Backend_Up(i);
  388. return;
  389. fail0:
  390. NCDModuleInst_Backend_SetError(i);
  391. NCDModuleInst_Backend_Dead(i);
  392. }
  393. static void length_func_new (NCDModuleInst *i)
  394. {
  395. // allocate instance
  396. struct length_instance *o = malloc(sizeof(*o));
  397. if (!o) {
  398. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  399. goto fail0;
  400. }
  401. NCDModuleInst_Backend_SetUser(i, o);
  402. // init arguments
  403. o->i = i;
  404. // check arguments
  405. if (!NCDVal_ListRead(o->i->args, 0)) {
  406. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  407. goto fail1;
  408. }
  409. // get method object
  410. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  411. // remember length
  412. o->length = list_count(mo);
  413. // signal up
  414. NCDModuleInst_Backend_Up(o->i);
  415. return;
  416. fail1:
  417. free(o);
  418. fail0:
  419. NCDModuleInst_Backend_SetError(i);
  420. NCDModuleInst_Backend_Dead(i);
  421. }
  422. static void length_func_die (void *vo)
  423. {
  424. struct length_instance *o = vo;
  425. NCDModuleInst *i = o->i;
  426. // free instance
  427. free(o);
  428. NCDModuleInst_Backend_Dead(i);
  429. }
  430. static int length_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
  431. {
  432. struct length_instance *o = vo;
  433. if (!strcmp(name, "")) {
  434. char str[64];
  435. snprintf(str, sizeof(str), "%"PRIu64, o->length);
  436. *out = NCDVal_NewString(mem, str);
  437. if (NCDVal_IsInvalid(*out)) {
  438. ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
  439. }
  440. return 1;
  441. }
  442. return 0;
  443. }
  444. static void get_func_new (NCDModuleInst *i)
  445. {
  446. // allocate instance
  447. struct get_instance *o = malloc(sizeof(*o));
  448. if (!o) {
  449. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  450. goto fail0;
  451. }
  452. NCDModuleInst_Backend_SetUser(i, o);
  453. // init arguments
  454. o->i = i;
  455. // check arguments
  456. NCDValRef index_arg;
  457. if (!NCDVal_ListRead(o->i->args, 1, &index_arg)) {
  458. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  459. goto fail1;
  460. }
  461. if (!NCDVal_IsStringNoNulls(index_arg)) {
  462. ModuleLog(o->i, BLOG_ERROR, "wrong type");
  463. goto fail1;
  464. }
  465. uintmax_t index;
  466. if (!parse_unsigned_integer(NCDVal_StringValue(index_arg), &index)) {
  467. ModuleLog(o->i, BLOG_ERROR, "wrong value");
  468. goto fail1;
  469. }
  470. // get method object
  471. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  472. // check index
  473. if (index >= list_count(mo)) {
  474. ModuleLog(o->i, BLOG_ERROR, "no element at index %"PRIuMAX, index);
  475. goto fail1;
  476. }
  477. // get element
  478. struct elem *e = get_elem_at(mo, index);
  479. // init mem
  480. NCDValMem_Init(&o->mem);
  481. // copy value
  482. o->val = NCDVal_NewCopy(&o->mem, e->val);
  483. if (NCDVal_IsInvalid(o->val)) {
  484. ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
  485. goto fail2;
  486. }
  487. // signal up
  488. NCDModuleInst_Backend_Up(o->i);
  489. return;
  490. fail2:
  491. NCDValMem_Free(&o->mem);
  492. fail1:
  493. free(o);
  494. fail0:
  495. NCDModuleInst_Backend_SetError(i);
  496. NCDModuleInst_Backend_Dead(i);
  497. }
  498. static void get_func_die (void *vo)
  499. {
  500. struct get_instance *o = vo;
  501. NCDModuleInst *i = o->i;
  502. // free mem
  503. NCDValMem_Free(&o->mem);
  504. // free instance
  505. free(o);
  506. NCDModuleInst_Backend_Dead(i);
  507. }
  508. static int get_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
  509. {
  510. struct get_instance *o = vo;
  511. if (!strcmp(name, "")) {
  512. *out = NCDVal_NewCopy(mem, o->val);
  513. if (NCDVal_IsInvalid(*out)) {
  514. ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewCopy failed");
  515. }
  516. return 1;
  517. }
  518. return 0;
  519. }
  520. static void shift_func_new (NCDModuleInst *i)
  521. {
  522. // check arguments
  523. if (!NCDVal_ListRead(i->args, 0)) {
  524. ModuleLog(i, BLOG_ERROR, "wrong arity");
  525. goto fail0;
  526. }
  527. // get method object
  528. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  529. // check first
  530. if (list_count(mo) == 0) {
  531. ModuleLog(i, BLOG_ERROR, "list has no elements");
  532. goto fail0;
  533. }
  534. // remove first
  535. remove_elem(mo, get_first_elem(mo));
  536. // signal up
  537. NCDModuleInst_Backend_Up(i);
  538. return;
  539. fail0:
  540. NCDModuleInst_Backend_SetError(i);
  541. NCDModuleInst_Backend_Dead(i);
  542. }
  543. static void contains_func_new (NCDModuleInst *i)
  544. {
  545. // allocate instance
  546. struct contains_instance *o = malloc(sizeof(*o));
  547. if (!o) {
  548. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  549. goto fail0;
  550. }
  551. NCDModuleInst_Backend_SetUser(i, o);
  552. // init arguments
  553. o->i = i;
  554. // read arguments
  555. NCDValRef value_arg;
  556. if (!NCDVal_ListRead(i->args, 1, &value_arg)) {
  557. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  558. goto fail1;
  559. }
  560. // get method object
  561. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  562. // search
  563. o->contains = !!find_elem(mo, value_arg, 0, NULL);
  564. // signal up
  565. NCDModuleInst_Backend_Up(o->i);
  566. return;
  567. fail1:
  568. free(o);
  569. fail0:
  570. NCDModuleInst_Backend_SetError(i);
  571. NCDModuleInst_Backend_Dead(i);
  572. }
  573. static void contains_func_die (void *vo)
  574. {
  575. struct contains_instance *o = vo;
  576. NCDModuleInst *i = o->i;
  577. // free instance
  578. free(o);
  579. NCDModuleInst_Backend_Dead(i);
  580. }
  581. static int contains_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
  582. {
  583. struct contains_instance *o = vo;
  584. if (!strcmp(name, "")) {
  585. const char *value = (o->contains ? "true" : "false");
  586. *out = NCDVal_NewString(mem, value);
  587. if (NCDVal_IsInvalid(*out)) {
  588. ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
  589. }
  590. return 1;
  591. }
  592. return 0;
  593. }
  594. static void find_func_new (NCDModuleInst *i)
  595. {
  596. // allocate instance
  597. struct find_instance *o = malloc(sizeof(*o));
  598. if (!o) {
  599. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  600. goto fail0;
  601. }
  602. NCDModuleInst_Backend_SetUser(i, o);
  603. // init arguments
  604. o->i = i;
  605. // read arguments
  606. NCDValRef start_pos_arg;
  607. NCDValRef value_arg;
  608. if (!NCDVal_ListRead(i->args, 2, &start_pos_arg, &value_arg)) {
  609. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  610. goto fail1;
  611. }
  612. if (!NCDVal_IsStringNoNulls(start_pos_arg)) {
  613. ModuleLog(o->i, BLOG_ERROR, "wrong type");
  614. goto fail1;
  615. }
  616. // read start position
  617. uintmax_t start_pos;
  618. if (!parse_unsigned_integer(NCDVal_StringValue(start_pos_arg), &start_pos) || start_pos > UINT64_MAX) {
  619. ModuleLog(o->i, BLOG_ERROR, "wrong start pos");
  620. goto fail1;
  621. }
  622. // get method object
  623. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  624. // find
  625. o->is_found = !!find_elem(mo, value_arg, start_pos, &o->found_pos);
  626. // signal up
  627. NCDModuleInst_Backend_Up(o->i);
  628. return;
  629. fail1:
  630. free(o);
  631. fail0:
  632. NCDModuleInst_Backend_SetError(i);
  633. NCDModuleInst_Backend_Dead(i);
  634. }
  635. static void find_func_die (void *vo)
  636. {
  637. struct find_instance *o = vo;
  638. NCDModuleInst *i = o->i;
  639. // free instance
  640. free(o);
  641. NCDModuleInst_Backend_Dead(i);
  642. }
  643. static int find_func_getvar (void *vo, const char *name, NCDValMem *mem, NCDValRef *out)
  644. {
  645. struct find_instance *o = vo;
  646. if (!strcmp(name, "pos")) {
  647. char value[64];
  648. if (o->is_found) {
  649. snprintf(value, sizeof(value), "%"PRIu64, o->found_pos);
  650. } else {
  651. snprintf(value, sizeof(value), "none");
  652. }
  653. *out = NCDVal_NewString(mem, value);
  654. if (NCDVal_IsInvalid(*out)) {
  655. ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
  656. }
  657. return 1;
  658. }
  659. if (!strcmp(name, "found")) {
  660. const char *value = (o->is_found ? "true" : "false");
  661. *out = NCDVal_NewString(mem, value);
  662. if (NCDVal_IsInvalid(*out)) {
  663. ModuleLog(o->i, BLOG_ERROR, "NCDVal_NewString failed");
  664. }
  665. return 1;
  666. }
  667. return 0;
  668. }
  669. static void removeat_func_new (NCDModuleInst *i)
  670. {
  671. // read arguments
  672. NCDValRef remove_pos_arg;
  673. if (!NCDVal_ListRead(i->args, 1, &remove_pos_arg)) {
  674. ModuleLog(i, BLOG_ERROR, "wrong arity");
  675. goto fail0;
  676. }
  677. if (!NCDVal_IsStringNoNulls(remove_pos_arg)) {
  678. ModuleLog(i, BLOG_ERROR, "wrong type");
  679. goto fail0;
  680. }
  681. // read position
  682. uintmax_t remove_pos;
  683. if (!parse_unsigned_integer(NCDVal_StringValue(remove_pos_arg), &remove_pos)) {
  684. ModuleLog(i, BLOG_ERROR, "wrong pos");
  685. goto fail0;
  686. }
  687. // get method object
  688. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  689. // check position
  690. if (remove_pos >= list_count(mo)) {
  691. ModuleLog(i, BLOG_ERROR, "pos out of range");
  692. goto fail0;
  693. }
  694. // remove
  695. remove_elem(mo, get_elem_at(mo, remove_pos));
  696. // signal up
  697. NCDModuleInst_Backend_Up(i);
  698. return;
  699. fail0:
  700. NCDModuleInst_Backend_SetError(i);
  701. NCDModuleInst_Backend_Dead(i);
  702. }
  703. static void remove_func_new (NCDModuleInst *i)
  704. {
  705. // read arguments
  706. NCDValRef value_arg;
  707. if (!NCDVal_ListRead(i->args, 1, &value_arg)) {
  708. ModuleLog(i, BLOG_ERROR, "wrong arity");
  709. goto fail0;
  710. }
  711. // get method object
  712. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  713. // find element
  714. struct elem *e = find_elem(mo, value_arg, 0, NULL);
  715. if (!e) {
  716. ModuleLog(i, BLOG_ERROR, "value does not exist");
  717. goto fail0;
  718. }
  719. // remove element
  720. remove_elem(mo, e);
  721. // signal up
  722. NCDModuleInst_Backend_Up(i);
  723. return;
  724. fail0:
  725. NCDModuleInst_Backend_SetError(i);
  726. NCDModuleInst_Backend_Dead(i);
  727. }
  728. static void set_func_new (NCDModuleInst *i)
  729. {
  730. // get method object
  731. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  732. // remember old count
  733. uint64_t old_count = list_count(mo);
  734. // append contents of our lists
  735. if (!append_list_contents_contents(i, mo, i->args)) {
  736. goto fail0;
  737. }
  738. // remove old elements
  739. cut_list_front(mo, list_count(mo) - old_count);
  740. // signal up
  741. NCDModuleInst_Backend_Up(i);
  742. return;
  743. fail0:
  744. NCDModuleInst_Backend_SetError(i);
  745. NCDModuleInst_Backend_Dead(i);
  746. }
  747. static const struct NCDModule modules[] = {
  748. {
  749. .type = "list",
  750. .func_new = func_new_list,
  751. .func_die = func_die,
  752. .func_getvar = func_getvar
  753. }, {
  754. .type = "listfrom",
  755. .base_type = "list",
  756. .func_new = func_new_listfrom,
  757. .func_die = func_die,
  758. .func_getvar = func_getvar
  759. }, {
  760. .type = "concatlist", // alias for listfrom
  761. .base_type = "list",
  762. .func_new = func_new_listfrom,
  763. .func_die = func_die,
  764. .func_getvar = func_getvar
  765. }, {
  766. .type = "list::append",
  767. .func_new = append_func_new
  768. }, {
  769. .type = "list::appendv",
  770. .func_new = appendv_func_new
  771. }, {
  772. .type = "list::length",
  773. .func_new = length_func_new,
  774. .func_die = length_func_die,
  775. .func_getvar = length_func_getvar
  776. }, {
  777. .type = "list::get",
  778. .func_new = get_func_new,
  779. .func_die = get_func_die,
  780. .func_getvar = get_func_getvar
  781. }, {
  782. .type = "list::shift",
  783. .func_new = shift_func_new
  784. }, {
  785. .type = "list::contains",
  786. .func_new = contains_func_new,
  787. .func_die = contains_func_die,
  788. .func_getvar = contains_func_getvar
  789. }, {
  790. .type = "list::find",
  791. .func_new = find_func_new,
  792. .func_die = find_func_die,
  793. .func_getvar = find_func_getvar
  794. }, {
  795. .type = "list::remove_at",
  796. .func_new = removeat_func_new
  797. }, {
  798. .type = "list::remove",
  799. .func_new = remove_func_new
  800. }, {
  801. .type = "list::set",
  802. .func_new = set_func_new
  803. }, {
  804. .type = NULL
  805. }
  806. };
  807. const struct NCDModuleGroup ncdmodule_list = {
  808. .modules = modules
  809. };