value.c 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396
  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_undo(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_undo(where, what) is like insert(), except that, on
  70. * deinitialization, it attempts to revert the value to the original state.
  71. * It does this by taking a reference to the old value at 'where' (if any) and
  72. * before inserting the new value 'what' to that location. On deinitialization,
  73. * it removes the value that it inserted from its parent and inserts the stored
  74. * referenced value in its place, assuming this is possible (the inserted value
  75. * has not been deleted and has a parent at deinitialization time).
  76. *
  77. * Variables:
  78. * (empty) - the value stored in the value object
  79. * type - type of the value; "string", "list" or "map"
  80. * length - number of elements in the list or map, or the number of bytes in a
  81. * string
  82. * keys - a list of keys in the map (only if the value is a map)
  83. * exists - "true" or "false", reflecting whether the value object holds a value
  84. * (is not in deleted state)
  85. *
  86. * Synopsis:
  87. * value::remove(where)
  88. * value::delete()
  89. *
  90. * Description:
  91. * value::remove(where) removes from an existing value object.
  92. * For lists, 'where' is the index of the element to remove, and must be in range.
  93. * For maps, 'where' is the key to remove, and must be an existing key.
  94. * In any case, any references to the removed value remain valid.
  95. *
  96. * value::delete() deletes the underlying value data of this value object.
  97. * After delection, the value object enters a deleted state, which will cause any
  98. * operation on it to fail. Any other value objects which referred to the same value
  99. * or parts of it will too enter deleted state. If the value was an element
  100. * in a list or map, is is removed from it.
  101. *
  102. * Synopsis:
  103. * value value::substr(string start [, string length])
  104. *
  105. * Description:
  106. * Constructs a string value by extracting a part of a string.
  107. * 'start' specifies the index of the character (from zero) where the substring to
  108. * extract starts, and must be <= the length of the string.
  109. * 'length' specifies the maximum number of characters to extract, if given.
  110. * The newly constructed value is a copy of the extracted substring.
  111. * The value must be a string value.
  112. */
  113. #include <stdlib.h>
  114. #include <string.h>
  115. #include <stddef.h>
  116. #include <limits.h>
  117. #include <inttypes.h>
  118. #include <misc/offset.h>
  119. #include <misc/debug.h>
  120. #include <misc/parse_number.h>
  121. #include <structure/LinkedList0.h>
  122. #include <structure/IndexedList.h>
  123. #include <structure/BCountAVL.h>
  124. #include <ncd/NCDModule.h>
  125. #include <generated/blog_channel_ncd_value.h>
  126. #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
  127. struct value;
  128. struct valref {
  129. struct value *v;
  130. LinkedList0Node refs_list_node;
  131. };
  132. typedef void (*value_deinit_func) (void *deinit_data, NCDModuleInst *i);
  133. struct instance {
  134. NCDModuleInst *i;
  135. struct valref ref;
  136. value_deinit_func deinit_func;
  137. void *deinit_data;
  138. };
  139. struct value {
  140. LinkedList0 refs_list;
  141. struct value *parent;
  142. union {
  143. struct {
  144. IndexedListNode list_contents_il_node;
  145. } list_parent;
  146. struct {
  147. NCDValue key;
  148. BCountAVLNode map_contents_tree_node;
  149. } map_parent;
  150. };
  151. int type;
  152. union {
  153. struct {
  154. uint8_t *string;
  155. size_t length;
  156. } string;
  157. struct {
  158. IndexedList list_contents_il;
  159. } list;
  160. struct {
  161. BCountAVL map_contents_tree;
  162. } map;
  163. };
  164. };
  165. static int ncdvalue_comparator (void *unused, void *vv1, void *vv2);
  166. static const char * get_type_str (int type);
  167. static void value_cleanup (struct value *v);
  168. static void value_delete (struct value *v);
  169. static struct value * value_init_string (NCDModuleInst *i, const uint8_t *str, size_t len);
  170. static struct value * value_init_list (NCDModuleInst *i);
  171. static size_t value_list_len (struct value *v);
  172. static struct value * value_list_at (struct value *v, size_t index);
  173. static size_t value_list_indexof (struct value *v, struct value *ev);
  174. static int value_list_insert (NCDModuleInst *i, struct value *list, struct value *v, size_t index);
  175. static void value_list_remove (struct value *list, struct value *v);
  176. static struct value * value_init_map (NCDModuleInst *i);
  177. static size_t value_map_len (struct value *map);
  178. static struct value * value_map_at (struct value *map, size_t index);
  179. static struct value * value_map_find (struct value *map, NCDValue *key);
  180. static int value_map_insert (struct value *map, struct value *v, NCDValue key, NCDModuleInst *i);
  181. static void value_map_remove (struct value *map, struct value *v);
  182. static void value_map_remove2 (struct value *map, struct value *v, NCDValue *out_key);
  183. static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValue *value);
  184. static int value_to_value (NCDModuleInst *i, struct value *v, NCDValue *out_value);
  185. static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValue *where, int no_error);
  186. static struct value * value_get_path (NCDModuleInst *i, struct value *v, NCDValue *path);
  187. static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValue *where, NCDValue *what, struct value **out_oldv);
  188. static int value_remove (NCDModuleInst *i, struct value *v, NCDValue *where);
  189. static void valref_init (struct valref *r, struct value *v);
  190. static void valref_free (struct valref *r);
  191. static struct value * valref_val (struct valref *r);
  192. static void valref_break (struct valref *r);
  193. static int ncdvalue_comparator (void *unused, void *vv1, void *vv2)
  194. {
  195. NCDValue *v1 = vv1;
  196. NCDValue *v2 = vv2;
  197. return NCDValue_Compare(v1, v2);
  198. }
  199. static const char * get_type_str (int type)
  200. {
  201. switch (type) {
  202. case NCDVALUE_STRING: return "string";
  203. case NCDVALUE_LIST: return "list";
  204. case NCDVALUE_MAP: return "map";
  205. }
  206. ASSERT(0)
  207. return NULL;
  208. }
  209. static void value_cleanup (struct value *v)
  210. {
  211. if (v->parent || !LinkedList0_IsEmpty(&v->refs_list)) {
  212. return;
  213. }
  214. switch (v->type) {
  215. case NCDVALUE_STRING: {
  216. free(v->string.string);
  217. } break;
  218. case NCDVALUE_LIST: {
  219. while (value_list_len(v) > 0) {
  220. struct value *ev = value_list_at(v, 0);
  221. value_list_remove(v, ev);
  222. value_cleanup(ev);
  223. }
  224. } break;
  225. case NCDVALUE_MAP: {
  226. while (value_map_len(v) > 0) {
  227. struct value *ev = value_map_at(v, 0);
  228. value_map_remove(v, ev);
  229. value_cleanup(ev);
  230. }
  231. } break;
  232. default: ASSERT(0);
  233. }
  234. free(v);
  235. }
  236. static void value_delete (struct value *v)
  237. {
  238. if (v->parent) {
  239. switch (v->parent->type) {
  240. case NCDVALUE_LIST: {
  241. value_list_remove(v->parent, v);
  242. } break;
  243. case NCDVALUE_MAP: {
  244. value_map_remove(v->parent, v);
  245. } break;
  246. default: ASSERT(0);
  247. }
  248. }
  249. LinkedList0Node *ln;
  250. while (ln = LinkedList0_GetFirst(&v->refs_list)) {
  251. struct valref *r = UPPER_OBJECT(ln, struct valref, refs_list_node);
  252. ASSERT(r->v == v)
  253. valref_break(r);
  254. }
  255. switch (v->type) {
  256. case NCDVALUE_STRING: {
  257. free(v->string.string);
  258. } break;
  259. case NCDVALUE_LIST: {
  260. while (value_list_len(v) > 0) {
  261. struct value *ev = value_list_at(v, 0);
  262. value_delete(ev);
  263. }
  264. } break;
  265. case NCDVALUE_MAP: {
  266. while (value_map_len(v) > 0) {
  267. struct value *ev = value_map_at(v, 0);
  268. value_delete(ev);
  269. }
  270. } break;
  271. default: ASSERT(0);
  272. }
  273. free(v);
  274. }
  275. static struct value * value_init_string (NCDModuleInst *i, const uint8_t *str, size_t len)
  276. {
  277. struct value *v = malloc(sizeof(*v));
  278. if (!v) {
  279. ModuleLog(i, BLOG_ERROR, "malloc failed");
  280. goto fail0;
  281. }
  282. LinkedList0_Init(&v->refs_list);
  283. v->parent = NULL;
  284. v->type = NCDVALUE_STRING;
  285. if (!(v->string.string = malloc(len))) {
  286. ModuleLog(i, BLOG_ERROR, "malloc failed");
  287. goto fail1;
  288. }
  289. memcpy(v->string.string, str, len);
  290. v->string.length = len;
  291. return v;
  292. fail1:
  293. free(v);
  294. fail0:
  295. return NULL;
  296. }
  297. static struct value * value_init_list (NCDModuleInst *i)
  298. {
  299. struct value *v = malloc(sizeof(*v));
  300. if (!v) {
  301. ModuleLog(i, BLOG_ERROR, "malloc failed");
  302. return NULL;
  303. }
  304. LinkedList0_Init(&v->refs_list);
  305. v->parent = NULL;
  306. v->type = NCDVALUE_LIST;
  307. IndexedList_Init(&v->list.list_contents_il);
  308. return v;
  309. }
  310. static size_t value_list_len (struct value *v)
  311. {
  312. ASSERT(v->type == NCDVALUE_LIST)
  313. return IndexedList_Count(&v->list.list_contents_il);
  314. }
  315. static struct value * value_list_at (struct value *v, size_t index)
  316. {
  317. ASSERT(v->type == NCDVALUE_LIST)
  318. ASSERT(index < value_list_len(v))
  319. IndexedListNode *iln = IndexedList_GetAt(&v->list.list_contents_il, index);
  320. ASSERT(iln)
  321. struct value *e = UPPER_OBJECT(iln, struct value, list_parent.list_contents_il_node);
  322. ASSERT(e->parent == v)
  323. return e;
  324. }
  325. static size_t value_list_indexof (struct value *v, struct value *ev)
  326. {
  327. ASSERT(v->type == NCDVALUE_LIST)
  328. ASSERT(ev->parent == v)
  329. uint64_t index = IndexedList_IndexOf(&v->list.list_contents_il, &ev->list_parent.list_contents_il_node);
  330. ASSERT(index < value_list_len(v))
  331. return index;
  332. }
  333. static int value_list_insert (NCDModuleInst *i, struct value *list, struct value *v, size_t index)
  334. {
  335. ASSERT(list->type == NCDVALUE_LIST)
  336. ASSERT(!v->parent)
  337. ASSERT(index <= value_list_len(list))
  338. if (value_list_len(list) == SIZE_MAX) {
  339. ModuleLog(i, BLOG_ERROR, "list has too many elements");
  340. return 0;
  341. }
  342. IndexedList_InsertAt(&list->list.list_contents_il, &v->list_parent.list_contents_il_node, index);
  343. v->parent = list;
  344. return 1;
  345. }
  346. static void value_list_remove (struct value *list, struct value *v)
  347. {
  348. ASSERT(list->type == NCDVALUE_LIST)
  349. ASSERT(v->parent == list)
  350. IndexedList_Remove(&list->list.list_contents_il, &v->list_parent.list_contents_il_node);
  351. v->parent = NULL;
  352. }
  353. static struct value * value_init_map (NCDModuleInst *i)
  354. {
  355. struct value *v = malloc(sizeof(*v));
  356. if (!v) {
  357. ModuleLog(i, BLOG_ERROR, "malloc failed");
  358. return NULL;
  359. }
  360. LinkedList0_Init(&v->refs_list);
  361. v->parent = NULL;
  362. v->type = NCDVALUE_MAP;
  363. BCountAVL_Init(&v->map.map_contents_tree, OFFSET_DIFF(struct value, map_parent.key, map_parent.map_contents_tree_node), ncdvalue_comparator, NULL);
  364. return v;
  365. }
  366. static size_t value_map_len (struct value *map)
  367. {
  368. ASSERT(map->type == NCDVALUE_MAP)
  369. return BCountAVL_Count(&map->map.map_contents_tree);
  370. }
  371. static struct value * value_map_at (struct value *map, size_t index)
  372. {
  373. ASSERT(map->type == NCDVALUE_MAP)
  374. ASSERT(index < value_map_len(map))
  375. BCountAVLNode *tn = BCountAVL_GetAt(&map->map.map_contents_tree, index);
  376. ASSERT(tn)
  377. struct value *e = UPPER_OBJECT(tn, struct value, map_parent.map_contents_tree_node);
  378. ASSERT(e->parent == map)
  379. return e;
  380. }
  381. static struct value * value_map_find (struct value *map, NCDValue *key)
  382. {
  383. ASSERT(map->type == NCDVALUE_MAP)
  384. ASSERT(key)
  385. BCountAVLNode *tn = BCountAVL_LookupExact(&map->map.map_contents_tree, key);
  386. if (!tn) {
  387. return NULL;
  388. }
  389. struct value *e = UPPER_OBJECT(tn, struct value, map_parent.map_contents_tree_node);
  390. ASSERT(e->parent == map)
  391. return e;
  392. }
  393. static int value_map_insert (struct value *map, struct value *v, NCDValue key, NCDModuleInst *i)
  394. {
  395. ASSERT(map->type == NCDVALUE_MAP)
  396. ASSERT(!v->parent)
  397. ASSERT(!value_map_find(map, &key))
  398. if (value_map_len(map) == SIZE_MAX) {
  399. ModuleLog(i, BLOG_ERROR, "map has too many elements");
  400. return 0;
  401. }
  402. v->map_parent.key = key;
  403. int res = BCountAVL_Insert(&map->map.map_contents_tree, &v->map_parent.map_contents_tree_node, NULL);
  404. ASSERT(res)
  405. v->parent = map;
  406. return 1;
  407. }
  408. static void value_map_remove (struct value *map, struct value *v)
  409. {
  410. ASSERT(map->type == NCDVALUE_MAP)
  411. ASSERT(v->parent == map)
  412. BCountAVL_Remove(&map->map.map_contents_tree, &v->map_parent.map_contents_tree_node);
  413. NCDValue_Free(&v->map_parent.key);
  414. v->parent = NULL;
  415. }
  416. static void value_map_remove2 (struct value *map, struct value *v, NCDValue *out_key)
  417. {
  418. ASSERT(map->type == NCDVALUE_MAP)
  419. ASSERT(v->parent == map)
  420. ASSERT(out_key)
  421. BCountAVL_Remove(&map->map.map_contents_tree, &v->map_parent.map_contents_tree_node);
  422. *out_key = v->map_parent.key;
  423. v->parent = NULL;
  424. }
  425. static struct value * value_init_fromvalue (NCDModuleInst *i, NCDValue *value)
  426. {
  427. struct value *v;
  428. switch (NCDValue_Type(value)) {
  429. case NCDVALUE_STRING: {
  430. if (!(v = value_init_string(i, (const uint8_t *)NCDValue_StringValue(value), NCDValue_StringLength(value)))) {
  431. goto fail0;
  432. }
  433. } break;
  434. case NCDVALUE_LIST: {
  435. if (!(v = value_init_list(i))) {
  436. goto fail0;
  437. }
  438. for (NCDValue *eval = NCDValue_ListFirst(value); eval; eval = NCDValue_ListNext(value, eval)) {
  439. struct value *ev = value_init_fromvalue(i, eval);
  440. if (!ev) {
  441. goto fail1;
  442. }
  443. if (!value_list_insert(i, v, ev, value_list_len(v))) {
  444. value_cleanup(ev);
  445. goto fail1;
  446. }
  447. }
  448. } break;
  449. case NCDVALUE_MAP: {
  450. if (!(v = value_init_map(i))) {
  451. goto fail0;
  452. }
  453. for (NCDValue *ekey = NCDValue_MapFirstKey(value); ekey; ekey = NCDValue_MapNextKey(value, ekey)) {
  454. NCDValue *eval = NCDValue_MapKeyValue(value, ekey);
  455. NCDValue key;
  456. if (!NCDValue_InitCopy(&key, ekey)) {
  457. BLog(BLOG_ERROR, "NCDValue_InitCopy failed");
  458. goto fail1;
  459. }
  460. struct value *ev = value_init_fromvalue(i, eval);
  461. if (!ev) {
  462. NCDValue_Free(&key);
  463. goto fail1;
  464. }
  465. if (!value_map_insert(v, ev, key, i)) {
  466. NCDValue_Free(&key);
  467. value_cleanup(ev);
  468. goto fail1;
  469. }
  470. }
  471. } break;
  472. default: ASSERT(0);
  473. }
  474. return v;
  475. fail1:
  476. value_cleanup(v);
  477. fail0:
  478. return NULL;
  479. }
  480. static int value_to_value (NCDModuleInst *i, struct value *v, NCDValue *out_value)
  481. {
  482. switch (v->type) {
  483. case NCDVALUE_STRING: {
  484. if (!(NCDValue_InitStringBin(out_value, v->string.string, v->string.length))) {
  485. ModuleLog(i, BLOG_ERROR, "NCDValue_InitStringBin failed");
  486. goto fail0;
  487. }
  488. } break;
  489. case NCDVALUE_LIST: {
  490. NCDValue_InitList(out_value);
  491. for (size_t index = 0; index < value_list_len(v); index++) {
  492. NCDValue eval;
  493. if (!value_to_value(i, value_list_at(v, index), &eval)) {
  494. goto fail1;
  495. }
  496. if (!NCDValue_ListAppend(out_value, eval)) {
  497. ModuleLog(i, BLOG_ERROR, "NCDValue_ListAppend failed");
  498. NCDValue_Free(&eval);
  499. goto fail1;
  500. }
  501. }
  502. } break;
  503. case NCDVALUE_MAP: {
  504. NCDValue_InitMap(out_value);
  505. for (size_t index = 0; index < value_map_len(v); index++) {
  506. struct value *ev = value_map_at(v, index);
  507. NCDValue key;
  508. NCDValue val;
  509. if (!NCDValue_InitCopy(&key, &ev->map_parent.key)) {
  510. ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
  511. goto fail1;
  512. }
  513. if (!value_to_value(i, ev, &val)) {
  514. NCDValue_Free(&key);
  515. goto fail1;
  516. }
  517. if (!NCDValue_MapInsert(out_value, key, val)) {
  518. ModuleLog(i, BLOG_ERROR, "NCDValue_MapInsert failed");
  519. NCDValue_Free(&key);
  520. NCDValue_Free(&val);
  521. goto fail1;
  522. }
  523. }
  524. } break;
  525. default: ASSERT(0);
  526. }
  527. return 1;
  528. fail1:
  529. NCDValue_Free(out_value);
  530. fail0:
  531. return 0;
  532. }
  533. static struct value * value_get (NCDModuleInst *i, struct value *v, NCDValue *where, int no_error)
  534. {
  535. switch (v->type) {
  536. case NCDVALUE_STRING: {
  537. if (!no_error) ModuleLog(i, BLOG_ERROR, "cannot resolve into a string");
  538. goto fail;
  539. } break;
  540. case NCDVALUE_LIST: {
  541. if (NCDValue_Type(where) != NCDVALUE_STRING) {
  542. if (!no_error) ModuleLog(i, BLOG_ERROR, "index is not a string (resolving into list)");
  543. goto fail;
  544. }
  545. uintmax_t index;
  546. if (NCDValue_StringHasNulls(where) || !parse_unsigned_integer(NCDValue_StringValue(where), &index)) {
  547. if (!no_error) ModuleLog(i, BLOG_ERROR, "index is not a valid number (resolving into list)");
  548. goto fail;
  549. }
  550. if (index >= value_list_len(v)) {
  551. if (!no_error) ModuleLog(i, BLOG_ERROR, "index is out of bounds (resolving into list)");
  552. goto fail;
  553. }
  554. v = value_list_at(v, index);
  555. } break;
  556. case NCDVALUE_MAP: {
  557. v = value_map_find(v, where);
  558. if (!v) {
  559. if (!no_error) ModuleLog(i, BLOG_ERROR, "key does not exist (resolving into map)");
  560. goto fail;
  561. }
  562. } break;
  563. default: ASSERT(0);
  564. }
  565. return v;
  566. fail:
  567. return NULL;
  568. }
  569. static struct value * value_get_path (NCDModuleInst *i, struct value *v, NCDValue *path)
  570. {
  571. ASSERT(NCDValue_Type(path) == NCDVALUE_LIST)
  572. for (NCDValue *ev = NCDValue_ListFirst(path); ev; ev = NCDValue_ListNext(path, ev)) {
  573. if (!(v = value_get(i, v, ev, 0))) {
  574. goto fail;
  575. }
  576. }
  577. return v;
  578. fail:
  579. return NULL;
  580. }
  581. static struct value * value_insert (NCDModuleInst *i, struct value *v, NCDValue *where, NCDValue *what, struct value **out_oldv)
  582. {
  583. ASSERT(v)
  584. NCDValue_Type(where);
  585. NCDValue_Type(what);
  586. struct value *nv = value_init_fromvalue(i, what);
  587. if (!nv) {
  588. goto fail0;
  589. }
  590. struct value *oldv = NULL;
  591. switch (v->type) {
  592. case NCDVALUE_STRING: {
  593. ModuleLog(i, BLOG_ERROR, "cannot insert into a string");
  594. goto fail1;
  595. } break;
  596. case NCDVALUE_LIST: {
  597. if (NCDValue_Type(where) != NCDVALUE_STRING) {
  598. ModuleLog(i, BLOG_ERROR, "index is not a string (inserting into list)");
  599. goto fail1;
  600. }
  601. uintmax_t index;
  602. if (NCDValue_StringHasNulls(where) || !parse_unsigned_integer(NCDValue_StringValue(where), &index)) {
  603. ModuleLog(i, BLOG_ERROR, "index is not a valid number (inserting into list)");
  604. goto fail1;
  605. }
  606. if (index > value_list_len(v)) {
  607. ModuleLog(i, BLOG_ERROR, "index is out of bounds (inserting into list)");
  608. goto fail1;
  609. }
  610. if (!value_list_insert(i, v, nv, index)) {
  611. goto fail1;
  612. }
  613. } break;
  614. case NCDVALUE_MAP: {
  615. oldv = value_map_find(v, where);
  616. if (!oldv && value_map_len(v) == SIZE_MAX) {
  617. ModuleLog(i, BLOG_ERROR, "map has too many elements");
  618. goto fail1;
  619. }
  620. NCDValue key;
  621. if (!NCDValue_InitCopy(&key, where)) {
  622. ModuleLog(i, BLOG_ERROR, "NCDValue_InitCopy failed");
  623. goto fail1;
  624. }
  625. if (oldv) {
  626. value_map_remove(v, oldv);
  627. }
  628. int res = value_map_insert(v, nv, key, i);
  629. ASSERT(res)
  630. } break;
  631. default: ASSERT(0);
  632. }
  633. if (out_oldv) {
  634. *out_oldv = oldv;
  635. }
  636. else if (oldv) {
  637. value_cleanup(oldv);
  638. }
  639. return nv;
  640. fail1:
  641. value_cleanup(nv);
  642. fail0:
  643. return NULL;
  644. }
  645. static int value_remove (NCDModuleInst *i, struct value *v, NCDValue *where)
  646. {
  647. switch (v->type) {
  648. case NCDVALUE_STRING: {
  649. ModuleLog(i, BLOG_ERROR, "cannot remove from a string");
  650. goto fail;
  651. } break;
  652. case NCDVALUE_LIST: {
  653. if (NCDValue_Type(where) != NCDVALUE_STRING) {
  654. ModuleLog(i, BLOG_ERROR, "index is not a string (removing from list)");
  655. goto fail;
  656. }
  657. uintmax_t index;
  658. if (NCDValue_StringHasNulls(where) || !parse_unsigned_integer(NCDValue_StringValue(where), &index)) {
  659. ModuleLog(i, BLOG_ERROR, "index is not a valid number (removing from list)");
  660. goto fail;
  661. }
  662. if (index >= value_list_len(v)) {
  663. ModuleLog(i, BLOG_ERROR, "index is out of bounds (removing from list)");
  664. goto fail;
  665. }
  666. struct value *ov = value_list_at(v, index);
  667. value_list_remove(v, ov);
  668. value_cleanup(ov);
  669. } break;
  670. case NCDVALUE_MAP: {
  671. struct value *ov = value_map_find(v, where);
  672. if (!ov) {
  673. ModuleLog(i, BLOG_ERROR, "key does not exist (removing from map)");
  674. goto fail;
  675. }
  676. value_map_remove(v, ov);
  677. value_cleanup(ov);
  678. } break;
  679. default: ASSERT(0);
  680. }
  681. return 1;
  682. fail:
  683. return 0;
  684. }
  685. static void valref_init (struct valref *r, struct value *v)
  686. {
  687. r->v = v;
  688. if (v) {
  689. LinkedList0_Prepend(&v->refs_list, &r->refs_list_node);
  690. }
  691. }
  692. static void valref_free (struct valref *r)
  693. {
  694. if (r->v) {
  695. LinkedList0_Remove(&r->v->refs_list, &r->refs_list_node);
  696. value_cleanup(r->v);
  697. }
  698. }
  699. static struct value * valref_val (struct valref *r)
  700. {
  701. return r->v;
  702. }
  703. static void valref_break (struct valref *r)
  704. {
  705. ASSERT(r->v)
  706. LinkedList0_Remove(&r->v->refs_list, &r->refs_list_node);
  707. r->v = NULL;
  708. }
  709. static void func_new_common (NCDModuleInst *i, struct value *v, value_deinit_func deinit_func, void *deinit_data)
  710. {
  711. // allocate instance
  712. struct instance *o = malloc(sizeof(*o));
  713. if (!o) {
  714. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  715. goto fail0;
  716. }
  717. o->i = i;
  718. NCDModuleInst_Backend_SetUser(i, o);
  719. // init value references
  720. valref_init(&o->ref, v);
  721. // remember deinit
  722. o->deinit_func = deinit_func;
  723. o->deinit_data = deinit_data;
  724. NCDModuleInst_Backend_Up(i);
  725. return;
  726. fail0:
  727. value_cleanup(v);
  728. if (deinit_func) {
  729. deinit_func(deinit_data, i);
  730. }
  731. NCDModuleInst_Backend_SetError(i);
  732. NCDModuleInst_Backend_Dead(i);
  733. }
  734. static void func_die (void *vo)
  735. {
  736. struct instance *o = vo;
  737. NCDModuleInst *i = o->i;
  738. // deinit
  739. if (o->deinit_func) {
  740. o->deinit_func(o->deinit_data, i);
  741. }
  742. // free value reference
  743. valref_free(&o->ref);
  744. // free instance
  745. free(o);
  746. NCDModuleInst_Backend_Dead(i);
  747. }
  748. static int func_getvar (void *vo, const char *name, NCDValue *out_value)
  749. {
  750. struct instance *o = vo;
  751. struct value *v = valref_val(&o->ref);
  752. if (!strcmp(name, "exists")) {
  753. const char *str = v ? "true" : "false";
  754. if (!NCDValue_InitString(out_value, str)) {
  755. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
  756. return 0;
  757. }
  758. return 1;
  759. }
  760. if (strcmp(name, "type") && strcmp(name, "length") && strcmp(name, "keys") && strcmp(name, "")) {
  761. return 0;
  762. }
  763. if (!v) {
  764. ModuleLog(o->i, BLOG_ERROR, "value was deleted");
  765. return 0;
  766. }
  767. if (!strcmp(name, "type")) {
  768. if (!NCDValue_InitString(out_value, get_type_str(v->type))) {
  769. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
  770. return 0;
  771. }
  772. }
  773. else if (!strcmp(name, "length")) {
  774. size_t len;
  775. switch (v->type) {
  776. case NCDVALUE_LIST:
  777. len = value_list_len(v);
  778. break;
  779. case NCDVALUE_MAP:
  780. len = value_map_len(v);
  781. break;
  782. case NCDVALUE_STRING:
  783. len = v->string.length;
  784. break;
  785. default:
  786. ASSERT(0);
  787. }
  788. char str[64];
  789. snprintf(str, sizeof(str), "%zu", len);
  790. if (!NCDValue_InitString(out_value, str)) {
  791. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitString failed");
  792. return 0;
  793. }
  794. }
  795. else if (!strcmp(name, "keys")) {
  796. if (v->type != NCDVALUE_MAP) {
  797. ModuleLog(o->i, BLOG_ERROR, "value is not a map (reading keys variable)");
  798. return 0;
  799. }
  800. NCDValue_InitList(out_value);
  801. for (size_t i = 0; i < value_map_len(v); i++) {
  802. struct value *ev = value_map_at(v, i);
  803. NCDValue key;
  804. if (!NCDValue_InitCopy(&key, &ev->map_parent.key)) {
  805. ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
  806. goto map_fail1;
  807. }
  808. if (!NCDValue_ListAppend(out_value, key)) {
  809. ModuleLog(o->i, BLOG_ERROR, "NCDValue_ListAppend failed");
  810. NCDValue_Free(&key);
  811. goto map_fail1;
  812. }
  813. }
  814. return 1;
  815. map_fail1:
  816. NCDValue_Free(out_value);
  817. return 0;
  818. }
  819. else if (!strcmp(name, "")) {
  820. if (!value_to_value(o->i, v, out_value)) {
  821. return 0;
  822. }
  823. }
  824. else {
  825. ASSERT(0);
  826. }
  827. return 1;
  828. }
  829. static void func_new_value (NCDModuleInst *i)
  830. {
  831. NCDValue *value_arg;
  832. if (!NCDValue_ListRead(i->args, 1, &value_arg)) {
  833. ModuleLog(i, BLOG_ERROR, "wrong arity");
  834. goto fail0;
  835. }
  836. struct value *v = value_init_fromvalue(i, value_arg);
  837. if (!v) {
  838. goto fail0;
  839. }
  840. func_new_common(i, v, NULL, NULL);
  841. return;
  842. fail0:
  843. NCDModuleInst_Backend_SetError(i);
  844. NCDModuleInst_Backend_Dead(i);
  845. }
  846. static void func_new_get (NCDModuleInst *i)
  847. {
  848. NCDValue *where_arg;
  849. if (!NCDValue_ListRead(i->args, 1, &where_arg)) {
  850. ModuleLog(i, BLOG_ERROR, "wrong arity");
  851. goto fail0;
  852. }
  853. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  854. struct value *mov = valref_val(&mo->ref);
  855. if (!mov) {
  856. ModuleLog(i, BLOG_ERROR, "value was deleted");
  857. goto fail0;
  858. }
  859. struct value *v = value_get(i, mov, where_arg, 0);
  860. if (!v) {
  861. goto fail0;
  862. }
  863. func_new_common(i, v, NULL, NULL);
  864. return;
  865. fail0:
  866. NCDModuleInst_Backend_SetError(i);
  867. NCDModuleInst_Backend_Dead(i);
  868. }
  869. static void func_new_try_get (NCDModuleInst *i)
  870. {
  871. NCDValue *where_arg;
  872. if (!NCDValue_ListRead(i->args, 1, &where_arg)) {
  873. ModuleLog(i, BLOG_ERROR, "wrong arity");
  874. goto fail0;
  875. }
  876. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  877. struct value *mov = valref_val(&mo->ref);
  878. if (!mov) {
  879. ModuleLog(i, BLOG_ERROR, "value was deleted");
  880. goto fail0;
  881. }
  882. struct value *v = value_get(i, mov, where_arg, 1);
  883. func_new_common(i, v, NULL, NULL);
  884. return;
  885. fail0:
  886. NCDModuleInst_Backend_SetError(i);
  887. NCDModuleInst_Backend_Dead(i);
  888. }
  889. static void func_new_getpath (NCDModuleInst *i)
  890. {
  891. NCDValue *path_arg;
  892. if (!NCDValue_ListRead(i->args, 1, &path_arg)) {
  893. ModuleLog(i, BLOG_ERROR, "wrong arity");
  894. goto fail0;
  895. }
  896. if (NCDValue_Type(path_arg) != NCDVALUE_LIST) {
  897. ModuleLog(i, BLOG_ERROR, "wrong type");
  898. goto fail0;
  899. }
  900. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  901. struct value *mov = valref_val(&mo->ref);
  902. if (!mov) {
  903. ModuleLog(i, BLOG_ERROR, "value was deleted");
  904. goto fail0;
  905. }
  906. struct value *v = value_get_path(i, mov, path_arg);
  907. if (!v) {
  908. goto fail0;
  909. }
  910. func_new_common(i, v, NULL, NULL);
  911. return;
  912. fail0:
  913. NCDModuleInst_Backend_SetError(i);
  914. NCDModuleInst_Backend_Dead(i);
  915. }
  916. static void func_new_insert (NCDModuleInst *i)
  917. {
  918. NCDValue *where_arg;
  919. NCDValue *what_arg;
  920. if (!NCDValue_ListRead(i->args, 2, &where_arg, &what_arg)) {
  921. ModuleLog(i, BLOG_ERROR, "wrong arity");
  922. goto fail0;
  923. }
  924. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  925. struct value *mov = valref_val(&mo->ref);
  926. if (!mov) {
  927. ModuleLog(i, BLOG_ERROR, "value was deleted");
  928. goto fail0;
  929. }
  930. struct value *v = value_insert(i, mov, where_arg, what_arg, NULL);
  931. if (!v) {
  932. goto fail0;
  933. }
  934. func_new_common(i, v, NULL, NULL);
  935. return;
  936. fail0:
  937. NCDModuleInst_Backend_SetError(i);
  938. NCDModuleInst_Backend_Dead(i);
  939. }
  940. struct insert_undo_deinit_data {
  941. struct valref val_ref;
  942. struct valref oldval_ref;
  943. };
  944. static void insert_undo_deinit_func (struct insert_undo_deinit_data *data, NCDModuleInst *i)
  945. {
  946. struct value *val = valref_val(&data->val_ref);
  947. struct value *oldval = valref_val(&data->oldval_ref);
  948. if (val && val->parent && (!oldval || !oldval->parent)) {
  949. // get parent
  950. struct value *parent = val->parent;
  951. // remove this value from parent and restore saved one (or none)
  952. switch (parent->type) {
  953. case NCDVALUE_LIST: {
  954. size_t index = value_list_indexof(parent, val);
  955. value_list_remove(parent, val);
  956. if (oldval) {
  957. int res = value_list_insert(i, parent, oldval, index);
  958. ASSERT(res)
  959. }
  960. } break;
  961. case NCDVALUE_MAP: {
  962. NCDValue key;
  963. value_map_remove2(parent, val, &key);
  964. if (oldval) {
  965. int res = value_map_insert(parent, oldval, key, i);
  966. ASSERT(res)
  967. } else {
  968. NCDValue_Free(&key);
  969. }
  970. } break;
  971. default: ASSERT(0);
  972. }
  973. }
  974. valref_free(&data->oldval_ref);
  975. valref_free(&data->val_ref);
  976. free(data);
  977. }
  978. static void func_new_insert_undo (NCDModuleInst *i)
  979. {
  980. NCDValue *where_arg;
  981. NCDValue *what_arg;
  982. if (!NCDValue_ListRead(i->args, 2, &where_arg, &what_arg)) {
  983. ModuleLog(i, BLOG_ERROR, "wrong arity");
  984. goto fail0;
  985. }
  986. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  987. struct value *mov = valref_val(&mo->ref);
  988. if (!mov) {
  989. ModuleLog(i, BLOG_ERROR, "value was deleted");
  990. goto fail0;
  991. }
  992. struct insert_undo_deinit_data *data = malloc(sizeof(*data));
  993. if (!data) {
  994. ModuleLog(i, BLOG_ERROR, "malloc failed");
  995. goto fail0;
  996. }
  997. struct value *oldv;
  998. struct value *v = value_insert(i, mov, where_arg, what_arg, &oldv);
  999. if (!v) {
  1000. goto fail1;
  1001. }
  1002. valref_init(&data->val_ref, v);
  1003. valref_init(&data->oldval_ref, oldv);
  1004. func_new_common(i, v, (value_deinit_func)insert_undo_deinit_func, data);
  1005. return;
  1006. fail1:
  1007. free(data);
  1008. fail0:
  1009. NCDModuleInst_Backend_SetError(i);
  1010. NCDModuleInst_Backend_Dead(i);
  1011. }
  1012. static void func_new_substr (NCDModuleInst *i)
  1013. {
  1014. NCDValue *start_arg;
  1015. NCDValue *length_arg = NULL;
  1016. if (!NCDValue_ListRead(i->args, 1, &start_arg) &&
  1017. !NCDValue_ListRead(i->args, 2, &start_arg, &length_arg)) {
  1018. ModuleLog(i, BLOG_ERROR, "wrong arity");
  1019. goto fail0;
  1020. }
  1021. if (!NCDValue_IsStringNoNulls(start_arg) || (length_arg && !NCDValue_IsStringNoNulls(length_arg))) {
  1022. ModuleLog(i, BLOG_ERROR, "wrong type");
  1023. goto fail0;
  1024. }
  1025. uintmax_t start;
  1026. if (!parse_unsigned_integer(NCDValue_StringValue(start_arg), &start)) {
  1027. ModuleLog(i, BLOG_ERROR, "start is not a number");
  1028. goto fail0;
  1029. }
  1030. uintmax_t length = UINTMAX_MAX;
  1031. if (length_arg && !parse_unsigned_integer(NCDValue_StringValue(length_arg), &length)) {
  1032. ModuleLog(i, BLOG_ERROR, "length is not a number");
  1033. goto fail0;
  1034. }
  1035. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  1036. struct value *mov = valref_val(&mo->ref);
  1037. if (!mov) {
  1038. ModuleLog(i, BLOG_ERROR, "value was deleted");
  1039. goto fail0;
  1040. }
  1041. if (mov->type != NCDVALUE_STRING) {
  1042. ModuleLog(i, BLOG_ERROR, "value is not a string");
  1043. goto fail0;
  1044. }
  1045. if (start > mov->string.length) {
  1046. ModuleLog(i, BLOG_ERROR, "start is out of range");
  1047. goto fail0;
  1048. }
  1049. size_t remain = mov->string.length - start;
  1050. size_t amount = length < remain ? length : remain;
  1051. struct value *v = value_init_string(i, mov->string.string + start, amount);
  1052. if (!v) {
  1053. goto fail0;
  1054. }
  1055. func_new_common(i, v, NULL, NULL);
  1056. return;
  1057. fail0:
  1058. NCDModuleInst_Backend_SetError(i);
  1059. NCDModuleInst_Backend_Dead(i);
  1060. }
  1061. static void remove_func_new (NCDModuleInst *i)
  1062. {
  1063. NCDValue *where_arg;
  1064. if (!NCDValue_ListRead(i->args, 1, &where_arg)) {
  1065. ModuleLog(i, BLOG_ERROR, "wrong arity");
  1066. goto fail0;
  1067. }
  1068. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  1069. struct value *mov = valref_val(&mo->ref);
  1070. if (!mov) {
  1071. ModuleLog(i, BLOG_ERROR, "value was deleted");
  1072. goto fail0;
  1073. }
  1074. if (!value_remove(i, mov, where_arg)) {
  1075. goto fail0;
  1076. }
  1077. NCDModuleInst_Backend_Up(i);
  1078. return;
  1079. fail0:
  1080. NCDModuleInst_Backend_SetError(i);
  1081. NCDModuleInst_Backend_Dead(i);
  1082. }
  1083. static void delete_func_new (NCDModuleInst *i)
  1084. {
  1085. if (!NCDValue_ListRead(i->args, 0)) {
  1086. ModuleLog(i, BLOG_ERROR, "wrong arity");
  1087. goto fail0;
  1088. }
  1089. struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
  1090. struct value *mov = valref_val(&mo->ref);
  1091. if (!mov) {
  1092. ModuleLog(i, BLOG_ERROR, "value was deleted");
  1093. goto fail0;
  1094. }
  1095. value_delete(mov);
  1096. NCDModuleInst_Backend_Up(i);
  1097. return;
  1098. fail0:
  1099. NCDModuleInst_Backend_SetError(i);
  1100. NCDModuleInst_Backend_Dead(i);
  1101. }
  1102. static const struct NCDModule modules[] = {
  1103. {
  1104. .type = "value",
  1105. .func_new = func_new_value,
  1106. .func_die = func_die,
  1107. .func_getvar = func_getvar
  1108. }, {
  1109. .type = "value::get",
  1110. .base_type = "value",
  1111. .func_new = func_new_get,
  1112. .func_die = func_die,
  1113. .func_getvar = func_getvar
  1114. }, {
  1115. .type = "value::try_get",
  1116. .base_type = "value",
  1117. .func_new = func_new_try_get,
  1118. .func_die = func_die,
  1119. .func_getvar = func_getvar
  1120. }, {
  1121. .type = "value::getpath",
  1122. .base_type = "value",
  1123. .func_new = func_new_getpath,
  1124. .func_die = func_die,
  1125. .func_getvar = func_getvar
  1126. }, {
  1127. .type = "value::insert",
  1128. .base_type = "value",
  1129. .func_new = func_new_insert,
  1130. .func_die = func_die,
  1131. .func_getvar = func_getvar
  1132. }, {
  1133. .type = "value::insert_undo",
  1134. .base_type = "value",
  1135. .func_new = func_new_insert_undo,
  1136. .func_die = func_die,
  1137. .func_getvar = func_getvar
  1138. }, {
  1139. .type = "value::remove",
  1140. .func_new = remove_func_new
  1141. }, {
  1142. .type = "value::delete",
  1143. .func_new = delete_func_new
  1144. }, {
  1145. .type = "value::substr",
  1146. .base_type = "value",
  1147. .func_new = func_new_substr,
  1148. .func_die = func_die,
  1149. .func_getvar = func_getvar
  1150. }, {
  1151. .type = NULL
  1152. }
  1153. };
  1154. const struct NCDModuleGroup ncdmodule_value = {
  1155. .modules = modules
  1156. };