value.c 32 KB

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