value.c 34 KB

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