value.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  1. /**
  2. * @file value.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. * Synopsis:
  32. * value(value)
  33. * value value::get(where)
  34. * value value::getpath(list path)
  35. * value value::insert(where, what)
  36. *
  37. * Description:
  38. * Value objects allow examining and manipulating values.
  39. *
  40. * value(value) constructs a new value object from the given value.
  41. *
  42. * value::get(where) constructs a value object for the element at position 'where'
  43. * (for a list), or the value corresponding to key 'where' (for a map). It is an
  44. * error if the base value is not a list or a map, the index is out of bounds of
  45. * the list, or the key does not exist in the map.
  46. * The resulting value object is NOT a copy, and shares (part of) the same
  47. * underlying value structure as the base value object. Deleting it will remove
  48. * it from the list or map it is part of.
  49. *
  50. * value::getpath(path) is like get(), except that it performs multiple
  51. * consecutive resolutions. Also, if the path is an empty list, it performs
  52. * no resulution at all.
  53. *
  54. * value::insert(where, what) constructs a value object by inserting into an
  55. * existing value object.
  56. * For lists, 'where' is the index of the element to insert before, or the length
  57. * of the list to append to it.
  58. * For maps, 'where' is the key to insert under. If the key already exists in the
  59. * map, its value is replaced; any references to the old value however remain valid.
  60. *
  61. * Variables:
  62. * (empty) - the value stored in the value object
  63. * type - type of the value; "string", "list" or "map"
  64. * length - number of elements in the list or map (only if the value if a list
  65. * or a map)
  66. * keys - a list of keys in the map (only if the value is a map)
  67. *
  68. * Synopsis:
  69. * value::remove(where)
  70. * value::delete()
  71. *
  72. * Description:
  73. * value::remove(where) removes from an existing value object.
  74. * For lists, 'where' is the index of the element to remove, and must be in range.
  75. * For maps, 'where' is the key to remove, and must be an existing key.
  76. * In any case, any references to the removed value remain valid.
  77. *
  78. * value::delete() deletes the underlying value data of this value object.
  79. * After delection, the value object enters a deleted state, which will cause any
  80. * operation on it to fail. Any other value objects which referred to the same value
  81. * or parts of it will too enter deleted state. If the value was an element
  82. * in a list or map, is is removed from it.
  83. */
  84. #include <stdlib.h>
  85. #include <string.h>
  86. #include <stddef.h>
  87. #include <limits.h>
  88. #include <misc/offset.h>
  89. #include <misc/debug.h>
  90. #include <misc/parse_number.h>
  91. #include <structure/LinkedList0.h>
  92. #include <structure/IndexedList.h>
  93. #include <structure/BCountAVL.h>
  94. #include <ncd/NCDModule.h>
  95. #include <generated/blog_channel_ncd_value.h>
  96. #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
  97. struct value;
  98. struct instance {
  99. NCDModuleInst *i;
  100. struct value *v;
  101. LinkedList0Node refs_list_node;
  102. };
  103. struct value {
  104. LinkedList0 refs_list;
  105. struct value *parent;
  106. union {
  107. struct {
  108. IndexedListNode list_contents_il_node;
  109. } list_parent;
  110. struct {
  111. NCDValue key;
  112. BCountAVLNode map_contents_tree_node;
  113. } map_parent;
  114. };
  115. int type;
  116. union {
  117. struct {
  118. char *string;
  119. } string;
  120. struct {
  121. IndexedList list_contents_il;
  122. } list;
  123. struct {
  124. BCountAVL map_contents_tree;
  125. } map;
  126. };
  127. };
  128. static int ncdvalue_comparator (void *unused, void *vv1, void *vv2);
  129. static const char * get_type_str (int type);
  130. static void value_cleanup (struct value *v);
  131. static void value_delete (struct value *v);
  132. static struct value * value_init_string (NCDModuleInst *i, const char *str);
  133. static struct value * value_init_list (NCDModuleInst *i);
  134. static size_t value_list_len (struct value *v);
  135. static struct value * value_list_at (struct value *v, size_t index);
  136. static int value_list_insert (NCDModuleInst *i, struct value *list, struct value *v, size_t index);
  137. static void value_list_remove (struct value *list, struct value *v);
  138. static struct value * value_init_map (NCDModuleInst *i);
  139. static size_t value_map_len (struct value *map);
  140. static struct value * value_map_at (struct value *map, size_t index);
  141. static struct value * value_map_find (struct value *map, NCDValue *key);
  142. static int value_map_insert (struct value *map, struct value *v, NCDValue key, NCDModuleInst *i);
  143. static void value_map_remove (struct value *map, struct value *v);
  144. static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValue *value);
  145. static int value_to_value (NCDModuleInst *i, struct value *v, NCDValue *out_value);
  146. static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValue *where);
  147. static struct value * value_get_path (NCDModuleInst *i, struct value *v, NCDValue *path);
  148. static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValue *where, NCDValue *what);
  149. static int value_remove (NCDModuleInst *i, struct value *v, NCDValue *where);
  150. static int ncdvalue_comparator (void *unused, void *vv1, void *vv2)
  151. {
  152. NCDValue *v1 = vv1;
  153. NCDValue *v2 = vv2;
  154. return NCDValue_Compare(v1, v2);
  155. }
  156. static const char * get_type_str (int type)
  157. {
  158. switch (type) {
  159. case NCDVALUE_STRING: return "string";
  160. case NCDVALUE_LIST: return "list";
  161. case NCDVALUE_MAP: return "map";
  162. }
  163. ASSERT(0)
  164. return NULL;
  165. }
  166. static void value_cleanup (struct value *v)
  167. {
  168. if (v->parent || !LinkedList0_IsEmpty(&v->refs_list)) {
  169. return;
  170. }
  171. switch (v->type) {
  172. case NCDVALUE_STRING: {
  173. free(v->string.string);
  174. } break;
  175. case NCDVALUE_LIST: {
  176. while (value_list_len(v) > 0) {
  177. struct value *ev = value_list_at(v, 0);
  178. value_list_remove(v, ev);
  179. value_cleanup(ev);
  180. }
  181. } break;
  182. case NCDVALUE_MAP: {
  183. while (value_map_len(v) > 0) {
  184. struct value *ev = value_map_at(v, 0);
  185. value_map_remove(v, ev);
  186. value_cleanup(ev);
  187. }
  188. } break;
  189. default: ASSERT(0);
  190. }
  191. free(v);
  192. }
  193. static void value_delete (struct value *v)
  194. {
  195. if (v->parent) {
  196. switch (v->parent->type) {
  197. case NCDVALUE_LIST: {
  198. value_list_remove(v->parent, v);
  199. } break;
  200. case NCDVALUE_MAP: {
  201. value_map_remove(v->parent, v);
  202. } break;
  203. default: ASSERT(0);
  204. }
  205. }
  206. LinkedList0Node *ln;
  207. while (ln = LinkedList0_GetFirst(&v->refs_list)) {
  208. struct instance *inst = UPPER_OBJECT(ln, struct instance, refs_list_node);
  209. ASSERT(inst->v == v)
  210. LinkedList0_Remove(&v->refs_list, &inst->refs_list_node);
  211. inst->v = NULL;
  212. }
  213. switch (v->type) {
  214. case NCDVALUE_STRING: {
  215. free(v->string.string);
  216. } break;
  217. case NCDVALUE_LIST: {
  218. while (value_list_len(v) > 0) {
  219. struct value *ev = value_list_at(v, 0);
  220. value_delete(ev);
  221. }
  222. } break;
  223. case NCDVALUE_MAP: {
  224. while (value_map_len(v) > 0) {
  225. struct value *ev = value_map_at(v, 0);
  226. value_delete(ev);
  227. }
  228. } break;
  229. default: ASSERT(0);
  230. }
  231. free(v);
  232. }
  233. static struct value * value_init_string (NCDModuleInst *i, const char *str)
  234. {
  235. struct value *v = malloc(sizeof(*v));
  236. if (!v) {
  237. ModuleLog(i, BLOG_ERROR, "malloc failed");
  238. goto fail0;
  239. }
  240. LinkedList0_Init(&v->refs_list);
  241. v->parent = NULL;
  242. v->type = NCDVALUE_STRING;
  243. if (!(v->string.string = strdup(str))) {
  244. ModuleLog(i, BLOG_ERROR, "strdup failed");
  245. goto fail1;
  246. }
  247. return v;
  248. fail1:
  249. free(v);
  250. fail0:
  251. return NULL;
  252. }
  253. static struct value * value_init_list (NCDModuleInst *i)
  254. {
  255. struct value *v = malloc(sizeof(*v));
  256. if (!v) {
  257. ModuleLog(i, BLOG_ERROR, "malloc failed");
  258. return NULL;
  259. }
  260. LinkedList0_Init(&v->refs_list);
  261. v->parent = NULL;
  262. v->type = NCDVALUE_LIST;
  263. IndexedList_Init(&v->list.list_contents_il);
  264. return v;
  265. }
  266. static size_t value_list_len (struct value *v)
  267. {
  268. ASSERT(v->type == NCDVALUE_LIST)
  269. return IndexedList_Count(&v->list.list_contents_il);
  270. }
  271. static struct value * value_list_at (struct value *v, size_t index)
  272. {
  273. ASSERT(v->type == NCDVALUE_LIST)
  274. ASSERT(index < value_list_len(v))
  275. IndexedListNode *iln = IndexedList_GetAt(&v->list.list_contents_il, index);
  276. ASSERT(iln)
  277. struct value *e = UPPER_OBJECT(iln, struct value, list_parent.list_contents_il_node);
  278. ASSERT(e->parent == v)
  279. return e;
  280. }
  281. static int value_list_insert (NCDModuleInst *i, struct value *list, struct value *v, size_t index)
  282. {
  283. ASSERT(list->type == NCDVALUE_LIST)
  284. ASSERT(!v->parent)
  285. ASSERT(index <= value_list_len(list))
  286. if (value_list_len(list) == SIZE_MAX) {
  287. ModuleLog(i, BLOG_ERROR, "list has too many elements");
  288. return 0;
  289. }
  290. IndexedList_InsertAt(&list->list.list_contents_il, &v->list_parent.list_contents_il_node, index);
  291. v->parent = list;
  292. return 1;
  293. }
  294. static void value_list_remove (struct value *list, struct value *v)
  295. {
  296. ASSERT(list->type == NCDVALUE_LIST)
  297. ASSERT(v->parent == list)
  298. IndexedList_Remove(&list->list.list_contents_il, &v->list_parent.list_contents_il_node);
  299. v->parent = NULL;
  300. }
  301. static struct value * value_init_map (NCDModuleInst *i)
  302. {
  303. struct value *v = malloc(sizeof(*v));
  304. if (!v) {
  305. ModuleLog(i, BLOG_ERROR, "malloc failed");
  306. return NULL;
  307. }
  308. LinkedList0_Init(&v->refs_list);
  309. v->parent = NULL;
  310. v->type = NCDVALUE_MAP;
  311. BCountAVL_Init(&v->map.map_contents_tree, OFFSET_DIFF(struct value, map_parent.key, map_parent.map_contents_tree_node), ncdvalue_comparator, NULL);
  312. return v;
  313. }
  314. static size_t value_map_len (struct value *map)
  315. {
  316. ASSERT(map->type == NCDVALUE_MAP)
  317. return BCountAVL_Count(&map->map.map_contents_tree);
  318. }
  319. static struct value * value_map_at (struct value *map, size_t index)
  320. {
  321. ASSERT(map->type == NCDVALUE_MAP)
  322. ASSERT(index < value_map_len(map))
  323. BCountAVLNode *tn = BCountAVL_GetAt(&map->map.map_contents_tree, index);
  324. ASSERT(tn)
  325. struct value *e = UPPER_OBJECT(tn, struct value, map_parent.map_contents_tree_node);
  326. ASSERT(e->parent == map)
  327. return e;
  328. }
  329. static struct value * value_map_find (struct value *map, NCDValue *key)
  330. {
  331. ASSERT(map->type == NCDVALUE_MAP)
  332. ASSERT(key)
  333. BCountAVLNode *tn = BCountAVL_LookupExact(&map->map.map_contents_tree, key);
  334. if (!tn) {
  335. return NULL;
  336. }
  337. struct value *e = UPPER_OBJECT(tn, struct value, map_parent.map_contents_tree_node);
  338. ASSERT(e->parent == map)
  339. return e;
  340. }
  341. static int value_map_insert (struct value *map, struct value *v, NCDValue key, NCDModuleInst *i)
  342. {
  343. ASSERT(map->type == NCDVALUE_MAP)
  344. ASSERT(!v->parent)
  345. ASSERT(!value_map_find(map, &key))
  346. if (value_map_len(map) == SIZE_MAX) {
  347. ModuleLog(i, BLOG_ERROR, "map has too many elements");
  348. return 0;
  349. }
  350. v->map_parent.key = key;
  351. int res = BCountAVL_Insert(&map->map.map_contents_tree, &v->map_parent.map_contents_tree_node, NULL);
  352. ASSERT(res)
  353. v->parent = map;
  354. return 1;
  355. }
  356. static void value_map_remove (struct value *map, struct value *v)
  357. {
  358. ASSERT(map->type == NCDVALUE_MAP)
  359. ASSERT(v->parent == map)
  360. BCountAVL_Remove(&map->map.map_contents_tree, &v->map_parent.map_contents_tree_node);
  361. NCDValue_Free(&v->map_parent.key);
  362. v->parent = NULL;
  363. }
  364. static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValue *value)
  365. {
  366. struct value *v;
  367. switch (NCDValue_Type(value)) {
  368. case NCDVALUE_STRING: {
  369. if (!(v = value_init_string(i, NCDValue_StringValue(value)))) {
  370. goto fail0;
  371. }
  372. } break;
  373. case NCDVALUE_LIST: {
  374. if (!(v = value_init_list(i))) {
  375. goto fail0;
  376. }
  377. for (NCDValue *eval = NCDValue_ListFirst(value); eval; eval = NCDValue_ListNext(value, eval)) {
  378. struct value *ev = value_init_fromvalue(i, eval);
  379. if (!ev) {
  380. goto fail1;
  381. }
  382. if (!value_list_insert(i, v, ev, value_list_len(v))) {
  383. value_cleanup(ev);
  384. goto fail1;
  385. }
  386. }
  387. } break;
  388. case NCDVALUE_MAP: {
  389. if (!(v = value_init_map(i))) {
  390. goto fail0;
  391. }
  392. for (NCDValue *ekey = NCDValue_MapFirstKey(value); ekey; ekey = NCDValue_MapNextKey(value, ekey)) {
  393. NCDValue *eval = NCDValue_MapKeyValue(value, ekey);
  394. NCDValue key;
  395. if (!NCDValue_InitCopy(&key, ekey)) {
  396. BLog(BLOG_ERROR, "NCDValue_InitCopy failed");
  397. goto fail1;
  398. }
  399. struct value *ev = value_init_fromvalue(i, eval);
  400. if (!ev) {
  401. NCDValue_Free(&key);
  402. goto fail1;
  403. }
  404. if (!value_map_insert(v, ev, key, i)) {
  405. NCDValue_Free(&key);
  406. value_cleanup(ev);
  407. goto fail1;
  408. }
  409. }
  410. } break;
  411. default: ASSERT(0);
  412. }
  413. return v;
  414. fail1:
  415. value_cleanup(v);
  416. fail0:
  417. return NULL;
  418. }
  419. static int value_to_value (NCDModuleInst *i, struct value *v, NCDValue *out_value)
  420. {
  421. switch (v->type) {
  422. case NCDVALUE_STRING: {
  423. if (!(NCDValue_InitString(out_value, v->string.string))) {
  424. ModuleLog(i, BLOG_ERROR, "NCDValue_InitString failed");
  425. goto fail0;
  426. }
  427. } break;
  428. case NCDVALUE_LIST: {
  429. NCDValue_InitList(out_value);
  430. for (size_t index = 0; index < value_list_len(v); index++) {
  431. NCDValue eval;
  432. if (!value_to_value(i, value_list_at(v, index), &eval)) {
  433. goto fail1;
  434. }
  435. if (!NCDValue_ListAppend(out_value, eval)) {
  436. ModuleLog(i, BLOG_ERROR, "NCDValue_ListAppend failed");
  437. NCDValue_Free(&eval);
  438. goto fail1;
  439. }
  440. }
  441. } break;
  442. case NCDVALUE_MAP: {
  443. NCDValue_InitMap(out_value);
  444. for (size_t index = 0; index < value_map_len(v); index++) {
  445. struct value *ev = value_map_at(v, index);
  446. NCDValue key;
  447. NCDValue val;
  448. if (!NCDValue_InitCopy(&key, &ev->map_parent.key)) {
  449. ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
  450. goto fail1;
  451. }
  452. if (!value_to_value(i, ev, &val)) {
  453. NCDValue_Free(&key);
  454. goto fail1;
  455. }
  456. if (!NCDValue_MapInsert(out_value, key, val)) {
  457. ModuleLog(i, BLOG_ERROR, "NCDValue_MapInsert failed");
  458. NCDValue_Free(&key);
  459. NCDValue_Free(&val);
  460. goto fail1;
  461. }
  462. }
  463. } break;
  464. default: ASSERT(0);
  465. }
  466. return 1;
  467. fail1:
  468. NCDValue_Free(out_value);
  469. fail0:
  470. return 0;
  471. }
  472. static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValue *where)
  473. {
  474. switch (v->type) {
  475. case NCDVALUE_STRING: {
  476. ModuleLog(i, BLOG_ERROR, "cannot resolve into a string");
  477. goto fail;
  478. } break;
  479. case NCDVALUE_LIST: {
  480. if (NCDValue_Type(where) != NCDVALUE_STRING) {
  481. ModuleLog(i, BLOG_ERROR, "index is not a string (resolving into list)");
  482. goto fail;
  483. }
  484. uintmax_t index;
  485. if (!parse_unsigned_integer(NCDValue_StringValue(where), &index)) {
  486. ModuleLog(i, BLOG_ERROR, "index is not a valid number (resolving into list)");
  487. goto fail;
  488. }
  489. if (index >= value_list_len(v)) {
  490. ModuleLog(i, BLOG_ERROR, "index is out of bounds (resolving into list)");
  491. goto fail;
  492. }
  493. v = value_list_at(v, index);
  494. } break;
  495. case NCDVALUE_MAP: {
  496. v = value_map_find(v, where);
  497. if (!v) {
  498. ModuleLog(i, BLOG_ERROR, "key does not exist (resolving into map)");
  499. goto fail;
  500. }
  501. } break;
  502. default: ASSERT(0);
  503. }
  504. return v;
  505. fail:
  506. return NULL;
  507. }
  508. static struct value * value_get_path (NCDModuleInst *i, struct value *v, NCDValue *path)
  509. {
  510. ASSERT(NCDValue_Type(path) == NCDVALUE_LIST)
  511. for (NCDValue *ev = NCDValue_ListFirst(path); ev; ev = NCDValue_ListNext(path, ev)) {
  512. if (!(v = value_get(i, v, ev))) {
  513. goto fail;
  514. }
  515. }
  516. return v;
  517. fail:
  518. return NULL;
  519. }
  520. static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValue *where, NCDValue *what)
  521. {
  522. struct value *nv;
  523. switch (v->type) {
  524. case NCDVALUE_STRING: {
  525. ModuleLog(i, BLOG_ERROR, "cannot insert into a string");
  526. goto fail;
  527. } break;
  528. case NCDVALUE_LIST: {
  529. if (NCDValue_Type(where) != NCDVALUE_STRING) {
  530. ModuleLog(i, BLOG_ERROR, "index is not a string (inserting into list)");
  531. goto fail;
  532. }
  533. uintmax_t index;
  534. if (!parse_unsigned_integer(NCDValue_StringValue(where), &index)) {
  535. ModuleLog(i, BLOG_ERROR, "index is not a valid number (inserting into list)");
  536. goto fail;
  537. }
  538. if (index > value_list_len(v)) {
  539. ModuleLog(i, BLOG_ERROR, "index is out of bounds (inserting into list)");
  540. goto fail;
  541. }
  542. nv = value_init_fromvalue(i, what);
  543. if (!nv) {
  544. goto fail;
  545. }
  546. if (!value_list_insert(i, v, nv, index)) {
  547. value_cleanup(nv);
  548. goto fail;
  549. }
  550. } break;
  551. case NCDVALUE_MAP: {
  552. struct value *ov = value_map_find(v, where);
  553. if (!ov && value_map_len(v) == SIZE_MAX) {
  554. ModuleLog(i, BLOG_ERROR, "map has too many elements");
  555. goto fail;
  556. }
  557. NCDValue key;
  558. if (!NCDValue_InitCopy(&key, where)) {
  559. ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
  560. goto fail;
  561. }
  562. nv = value_init_fromvalue(i, what);
  563. if (!nv) {
  564. NCDValue_Free(&key);
  565. goto fail;
  566. }
  567. if (ov) {
  568. value_map_remove(v, ov);
  569. value_cleanup(ov);
  570. }
  571. int res = value_map_insert(v, nv, key, i);
  572. ASSERT(res)
  573. } break;
  574. default: ASSERT(0);
  575. }
  576. return nv;
  577. fail:
  578. return NULL;
  579. }
  580. static int value_remove (NCDModuleInst *i, struct value *v, NCDValue *where)
  581. {
  582. switch (v->type) {
  583. case NCDVALUE_STRING: {
  584. ModuleLog(i, BLOG_ERROR, "cannot remove from a string");
  585. goto fail;
  586. } break;
  587. case NCDVALUE_LIST: {
  588. if (NCDValue_Type(where) != NCDVALUE_STRING) {
  589. ModuleLog(i, BLOG_ERROR, "index is not a string (removing from list)");
  590. goto fail;
  591. }
  592. uintmax_t index;
  593. if (!parse_unsigned_integer(NCDValue_StringValue(where), &index)) {
  594. ModuleLog(i, BLOG_ERROR, "index is not a valid number (removing from list)");
  595. goto fail;
  596. }
  597. if (index >= value_list_len(v)) {
  598. ModuleLog(i, BLOG_ERROR, "index is out of bounds (removing from list)");
  599. goto fail;
  600. }
  601. struct value *ov = value_list_at(v, index);
  602. value_list_remove(v, ov);
  603. value_cleanup(ov);
  604. } break;
  605. case NCDVALUE_MAP: {
  606. struct value *ov = value_map_find(v, where);
  607. if (!ov) {
  608. ModuleLog(i, BLOG_ERROR, "key does not exist (removing from map)");
  609. goto fail;
  610. }
  611. value_map_remove(v, ov);
  612. value_cleanup(ov);
  613. } break;
  614. default: ASSERT(0);
  615. }
  616. return 1;
  617. fail:
  618. return 0;
  619. }
  620. static void func_new_common (NCDModuleInst *i, struct value *v)
  621. {
  622. ASSERT(v)
  623. // allocate instance
  624. struct instance *o = malloc(sizeof(*o));
  625. if (!o) {
  626. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  627. goto fail0;
  628. }
  629. o->i = i;
  630. NCDModuleInst_Backend_SetUser(i, o);
  631. // set value
  632. o->v = v;
  633. // add reference
  634. LinkedList0_Prepend(&o->v->refs_list, &o->refs_list_node);
  635. NCDModuleInst_Backend_Up(i);
  636. return;
  637. fail1:
  638. free(o);
  639. fail0:
  640. value_cleanup(v);
  641. NCDModuleInst_Backend_SetError(i);
  642. NCDModuleInst_Backend_Dead(i);
  643. }
  644. static void func_die (void *vo)
  645. {
  646. struct instance *o = vo;
  647. NCDModuleInst *i = o->i;
  648. if (o->v) {
  649. // remove reference
  650. LinkedList0_Remove(&o->v->refs_list, &o->refs_list_node);
  651. // cleanup after removing reference
  652. value_cleanup(o->v);
  653. }
  654. // free instance
  655. free(o);
  656. NCDModuleInst_Backend_Dead(i);
  657. }
  658. static int func_getvar (void *vo, const char *name, NCDValue *out_value)
  659. {
  660. struct instance *o = vo;
  661. if (strcmp(name, "type") && strcmp(name, "length") && strcmp(name, "keys") && strcmp(name, "")) {
  662. return 0;
  663. }
  664. if (!o->v) {
  665. ModuleLog(o->i, BLOG_ERROR, "value was deleted");
  666. return 0;
  667. }
  668. if (!strcmp(name, "type")) {
  669. if (!NCDValue_InitString(out_value, get_type_str(o->v->type))) {
  670. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
  671. return 0;
  672. }
  673. }
  674. else if (!strcmp(name, "length")) {
  675. size_t len;
  676. switch (o->v->type) {
  677. case NCDVALUE_LIST:
  678. len = value_list_len(o->v);
  679. break;
  680. case NCDVALUE_MAP:
  681. len = value_map_len(o->v);
  682. break;
  683. default:
  684. ModuleLog(o->i, BLOG_ERROR, "value is not a list or map");
  685. return 0;
  686. }
  687. char str[64];
  688. snprintf(str, sizeof(str), "%zu", len);
  689. if (!NCDValue_InitString(out_value, str)) {
  690. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
  691. return 0;
  692. }
  693. }
  694. else if (!strcmp(name, "keys")) {
  695. if (o->v->type != NCDVALUE_MAP) {
  696. ModuleLog(o->i, BLOG_ERROR, "value is not a map (reading keys variable)");
  697. return 0;
  698. }
  699. NCDValue_InitList(out_value);
  700. for (size_t i = 0; i < value_map_len(o->v); i++) {
  701. struct value *ev = value_map_at(o->v, i);
  702. NCDValue key;
  703. if (!NCDValue_InitCopy(&key, &ev->map_parent.key)) {
  704. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
  705. goto map_fail1;
  706. }
  707. if (!NCDValue_ListAppend(out_value, key)) {
  708. ModuleLog(o->i, BLOG_ERROR, "NCDValue_ListAppend failed");
  709. NCDValue_Free(&key);
  710. goto map_fail1;
  711. }
  712. }
  713. return 1;
  714. map_fail1:
  715. NCDValue_Free(out_value);
  716. return 0;
  717. }
  718. else if (!strcmp(name, "")) {
  719. if (!value_to_value(o->i, o->v, out_value)) {
  720. return 0;
  721. }
  722. }
  723. else {
  724. ASSERT(0);
  725. }
  726. return 1;
  727. }
  728. static void func_new_value (NCDModuleInst *i)
  729. {
  730. NCDValue *value_arg;
  731. if (!NCDValue_ListRead(i->args, 1, &value_arg)) {
  732. ModuleLog(i, BLOG_ERROR, "wrong arity");
  733. goto fail0;
  734. }
  735. struct value *v = value_init_fromvalue(i, value_arg);
  736. if (!v) {
  737. goto fail0;
  738. }
  739. func_new_common(i, v);
  740. return;
  741. fail0:
  742. NCDModuleInst_Backend_SetError(i);
  743. NCDModuleInst_Backend_Dead(i);
  744. }
  745. static void func_new_get (NCDModuleInst *i)
  746. {
  747. NCDValue *where_arg;
  748. if (!NCDValue_ListRead(i->args, 1, &where_arg)) {
  749. ModuleLog(i, BLOG_ERROR, "wrong arity");
  750. goto fail0;
  751. }
  752. struct instance *mo = ((NCDModuleInst *)i->method_user)->inst_user;
  753. if (!mo->v) {
  754. ModuleLog(i, BLOG_ERROR, "value was deleted");
  755. goto fail0;
  756. }
  757. struct value *v = value_get(i, mo->v, where_arg);
  758. if (!v) {
  759. goto fail0;
  760. }
  761. func_new_common(i, v);
  762. return;
  763. fail0:
  764. NCDModuleInst_Backend_SetError(i);
  765. NCDModuleInst_Backend_Dead(i);
  766. }
  767. static void func_new_getpath (NCDModuleInst *i)
  768. {
  769. NCDValue *path_arg;
  770. if (!NCDValue_ListRead(i->args, 1, &path_arg)) {
  771. ModuleLog(i, BLOG_ERROR, "wrong arity");
  772. goto fail0;
  773. }
  774. if (NCDValue_Type(path_arg) != NCDVALUE_LIST) {
  775. ModuleLog(i, BLOG_ERROR, "wrong type");
  776. goto fail0;
  777. }
  778. struct instance *mo = ((NCDModuleInst *)i->method_user)->inst_user;
  779. if (!mo->v) {
  780. ModuleLog(i, BLOG_ERROR, "value was deleted");
  781. goto fail0;
  782. }
  783. struct value *v = value_get_path(i, mo->v, path_arg);
  784. if (!v) {
  785. goto fail0;
  786. }
  787. func_new_common(i, v);
  788. return;
  789. fail0:
  790. NCDModuleInst_Backend_SetError(i);
  791. NCDModuleInst_Backend_Dead(i);
  792. }
  793. static void func_new_insert (NCDModuleInst *i)
  794. {
  795. NCDValue *where_arg;
  796. NCDValue *what_arg;
  797. if (!NCDValue_ListRead(i->args, 2, &where_arg, &what_arg)) {
  798. ModuleLog(i, BLOG_ERROR, "wrong arity");
  799. goto fail0;
  800. }
  801. struct instance *mo = ((NCDModuleInst *)i->method_user)->inst_user;
  802. if (!mo->v) {
  803. ModuleLog(i, BLOG_ERROR, "value was deleted");
  804. goto fail0;
  805. }
  806. struct value *v = value_insert(i, mo->v, where_arg, what_arg);
  807. if (!v) {
  808. goto fail0;
  809. }
  810. func_new_common(i, v);
  811. return;
  812. fail0:
  813. NCDModuleInst_Backend_SetError(i);
  814. NCDModuleInst_Backend_Dead(i);
  815. }
  816. static void remove_func_new (NCDModuleInst *i)
  817. {
  818. NCDValue *where_arg;
  819. if (!NCDValue_ListRead(i->args, 1, &where_arg)) {
  820. ModuleLog(i, BLOG_ERROR, "wrong arity");
  821. goto fail0;
  822. }
  823. struct instance *mo = ((NCDModuleInst *)i->method_user)->inst_user;
  824. if (!mo->v) {
  825. ModuleLog(i, BLOG_ERROR, "value was deleted");
  826. goto fail0;
  827. }
  828. if (!value_remove(i, mo->v, where_arg)) {
  829. goto fail0;
  830. }
  831. NCDModuleInst_Backend_Up(i);
  832. return;
  833. fail0:
  834. NCDModuleInst_Backend_SetError(i);
  835. NCDModuleInst_Backend_Dead(i);
  836. }
  837. static void delete_func_new (NCDModuleInst *i)
  838. {
  839. if (!NCDValue_ListRead(i->args, 0)) {
  840. ModuleLog(i, BLOG_ERROR, "wrong arity");
  841. goto fail0;
  842. }
  843. struct instance *mo = ((NCDModuleInst *)i->method_user)->inst_user;
  844. if (!mo->v) {
  845. ModuleLog(i, BLOG_ERROR, "value was deleted");
  846. goto fail0;
  847. }
  848. value_delete(mo->v);
  849. NCDModuleInst_Backend_Up(i);
  850. return;
  851. fail0:
  852. NCDModuleInst_Backend_SetError(i);
  853. NCDModuleInst_Backend_Dead(i);
  854. }
  855. static const struct NCDModule modules[] = {
  856. {
  857. .type = "value",
  858. .func_new = func_new_value,
  859. .func_die = func_die,
  860. .func_getvar = func_getvar
  861. }, {
  862. .type = "value::get",
  863. .base_type = "value",
  864. .func_new = func_new_get,
  865. .func_die = func_die,
  866. .func_getvar = func_getvar
  867. }, {
  868. .type = "value::getpath",
  869. .base_type = "value",
  870. .func_new = func_new_getpath,
  871. .func_die = func_die,
  872. .func_getvar = func_getvar
  873. }, {
  874. .type = "value::insert",
  875. .base_type = "value",
  876. .func_new = func_new_insert,
  877. .func_die = func_die,
  878. .func_getvar = func_getvar
  879. }, {
  880. .type = "value::remove",
  881. .func_new = remove_func_new
  882. }, {
  883. .type = "value::delete",
  884. .func_new = delete_func_new
  885. }, {
  886. .type = NULL
  887. }
  888. };
  889. const struct NCDModuleGroup ncdmodule_value = {
  890. .modules = modules
  891. };