NCDValue.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. /**
  2. * @file NCDValue.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. #include <stdlib.h>
  30. #include <string.h>
  31. #include <stdarg.h>
  32. #include <inttypes.h>
  33. #include <misc/debug.h>
  34. #include <misc/offset.h>
  35. #include <ncd/NCDValue.h>
  36. static int ncdvalue_comparator (void *unused, void *vv1, void *vv2)
  37. {
  38. NCDValue *v1 = vv1;
  39. NCDValue *v2 = vv2;
  40. return NCDValue_Compare(v1, v2);
  41. }
  42. static void value_assert (NCDValue *o)
  43. {
  44. switch (o->type) {
  45. case NCDVALUE_STRING:
  46. case NCDVALUE_LIST:
  47. case NCDVALUE_MAP:
  48. case NCDVALUE_VAR:
  49. return;
  50. default:
  51. ASSERT(0);
  52. }
  53. }
  54. int NCDValue_InitCopy (NCDValue *o, NCDValue *v)
  55. {
  56. value_assert(v);
  57. switch (v->type) {
  58. case NCDVALUE_STRING: {
  59. return NCDValue_InitStringBin(o, v->string, v->string_len);
  60. } break;
  61. case NCDVALUE_LIST: {
  62. NCDValue_InitList(o);
  63. LinkedList2Iterator it;
  64. LinkedList2Iterator_InitForward(&it, &v->list);
  65. LinkedList2Node *n;
  66. while (n = LinkedList2Iterator_Next(&it)) {
  67. NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
  68. NCDValue tmp;
  69. if (!NCDValue_InitCopy(&tmp, &e->v)) {
  70. goto fail;
  71. }
  72. if (!NCDValue_ListAppend(o, tmp)) {
  73. NCDValue_Free(&tmp);
  74. goto fail;
  75. }
  76. }
  77. return 1;
  78. fail:
  79. LinkedList2Iterator_Free(&it);
  80. NCDValue_Free(o);
  81. return 0;
  82. } break;
  83. case NCDVALUE_MAP: {
  84. NCDValue_InitMap(o);
  85. for (NCDValue *ekey = NCDValue_MapFirstKey(v); ekey; ekey = NCDValue_MapNextKey(v, ekey)) {
  86. NCDValue *eval = NCDValue_MapKeyValue(v, ekey);
  87. NCDValue tmp_key;
  88. NCDValue tmp_val;
  89. if (!NCDValue_InitCopy(&tmp_key, ekey)) {
  90. goto mapfail;
  91. }
  92. if (!NCDValue_InitCopy(&tmp_val, eval)) {
  93. NCDValue_Free(&tmp_key);
  94. goto mapfail;
  95. }
  96. if (!NCDValue_MapInsert(o, tmp_key, tmp_val)) {
  97. NCDValue_Free(&tmp_key);
  98. NCDValue_Free(&tmp_val);
  99. goto mapfail;
  100. }
  101. }
  102. return 1;
  103. mapfail:
  104. NCDValue_Free(o);
  105. return 0;
  106. } break;
  107. case NCDVALUE_VAR: {
  108. return NCDValue_InitVar(o, v->var_name);
  109. } break;
  110. default:
  111. ASSERT(0);
  112. }
  113. return 0;
  114. }
  115. void NCDValue_Free (NCDValue *o)
  116. {
  117. switch (o->type) {
  118. case NCDVALUE_STRING: {
  119. free(o->string);
  120. } break;
  121. case NCDVALUE_LIST: {
  122. LinkedList2Node *n;
  123. while (n = LinkedList2_GetFirst(&o->list)) {
  124. NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
  125. NCDValue_Free(&e->v);
  126. LinkedList2_Remove(&o->list, &e->list_node);
  127. free(e);
  128. }
  129. } break;
  130. case NCDVALUE_MAP: {
  131. BAVLNode *tn;
  132. while (tn = BAVL_GetFirst(&o->map_tree)) {
  133. NCDMapElement *e = UPPER_OBJECT(tn, NCDMapElement, map_tree_node);
  134. BAVL_Remove(&o->map_tree, &e->map_tree_node);
  135. NCDValue_Free(&e->key);
  136. NCDValue_Free(&e->val);
  137. free(e);
  138. }
  139. } break;
  140. case NCDVALUE_VAR: {
  141. free(o->var_name);
  142. } break;
  143. default:
  144. ASSERT(0);
  145. }
  146. }
  147. int NCDValue_Type (NCDValue *o)
  148. {
  149. value_assert(o);
  150. return o->type;
  151. }
  152. int NCDValue_IsString (NCDValue *o)
  153. {
  154. value_assert(o);
  155. return o->type == NCDVALUE_STRING;
  156. }
  157. int NCDValue_IsStringNoNulls (NCDValue *o)
  158. {
  159. return NCDValue_IsString(o) && NCDValue_StringHasNoNulls(o);
  160. }
  161. int NCDValue_InitString (NCDValue *o, const char *str)
  162. {
  163. return NCDValue_InitStringBin(o, (const uint8_t *)str, strlen(str));
  164. }
  165. int NCDValue_InitStringBin (NCDValue *o, const uint8_t *str, size_t len)
  166. {
  167. if (len == SIZE_MAX) {
  168. return 0;
  169. }
  170. if (!(o->string = malloc(len + 1))) {
  171. return 0;
  172. }
  173. memcpy(o->string, str, len);
  174. o->string[len] = '\0';
  175. o->string_len = len;
  176. o->type = NCDVALUE_STRING;
  177. return 1;
  178. }
  179. char * NCDValue_StringValue (NCDValue *o)
  180. {
  181. ASSERT(o->type == NCDVALUE_STRING)
  182. return (char *)o->string;
  183. }
  184. size_t NCDValue_StringLength (NCDValue *o)
  185. {
  186. ASSERT(o->type == NCDVALUE_STRING)
  187. return o->string_len;
  188. }
  189. int NCDValue_StringHasNoNulls (NCDValue *o)
  190. {
  191. ASSERT(o->type == NCDVALUE_STRING)
  192. return strlen((char *)o->string) == o->string_len;
  193. }
  194. int NCDValue_StringHasNulls (NCDValue *o)
  195. {
  196. ASSERT(o->type == NCDVALUE_STRING)
  197. return !NCDValue_StringHasNoNulls(o);
  198. }
  199. int NCDValue_StringEquals (NCDValue *o, const char *str)
  200. {
  201. ASSERT(o->type == NCDVALUE_STRING)
  202. return NCDValue_StringHasNoNulls(o) && !strcmp((const char *)o->string, str);
  203. }
  204. int NCDValue_IsList (NCDValue *o)
  205. {
  206. value_assert(o);
  207. return o->type == NCDVALUE_LIST;
  208. }
  209. void NCDValue_InitList (NCDValue *o)
  210. {
  211. LinkedList2_Init(&o->list);
  212. o->list_count = 0;
  213. o->type = NCDVALUE_LIST;
  214. }
  215. int NCDValue_ListAppend (NCDValue *o, NCDValue v)
  216. {
  217. value_assert(o);
  218. value_assert(&v);
  219. ASSERT(o->type == NCDVALUE_LIST)
  220. if (o->list_count == SIZE_MAX) {
  221. return 0;
  222. }
  223. NCDListElement *e = malloc(sizeof(*e));
  224. if (!e) {
  225. return 0;
  226. }
  227. LinkedList2_Append(&o->list, &e->list_node);
  228. o->list_count++;
  229. e->v = v;
  230. return 1;
  231. }
  232. int NCDValue_ListPrepend (NCDValue *o, NCDValue v)
  233. {
  234. value_assert(o);
  235. value_assert(&v);
  236. ASSERT(o->type == NCDVALUE_LIST)
  237. if (o->list_count == SIZE_MAX) {
  238. return 0;
  239. }
  240. NCDListElement *e = malloc(sizeof(*e));
  241. if (!e) {
  242. return 0;
  243. }
  244. LinkedList2_Prepend(&o->list, &e->list_node);
  245. o->list_count++;
  246. e->v = v;
  247. return 1;
  248. }
  249. int NCDValue_ListAppendList (NCDValue *o, NCDValue l)
  250. {
  251. value_assert(o);
  252. value_assert(&l);
  253. ASSERT(o->type == NCDVALUE_LIST)
  254. ASSERT(l.type == NCDVALUE_LIST)
  255. if (l.list_count > SIZE_MAX - o->list_count) {
  256. return 0;
  257. }
  258. LinkedList2Node *n;
  259. while (n = LinkedList2_GetFirst(&l.list)) {
  260. NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
  261. LinkedList2_Remove(&l.list, &e->list_node);
  262. LinkedList2_Append(&o->list, &e->list_node);
  263. }
  264. o->list_count += l.list_count;
  265. return 1;
  266. }
  267. size_t NCDValue_ListCount (NCDValue *o)
  268. {
  269. value_assert(o);
  270. ASSERT(o->type == NCDVALUE_LIST)
  271. return o->list_count;
  272. }
  273. NCDValue * NCDValue_ListFirst (NCDValue *o)
  274. {
  275. value_assert(o);
  276. ASSERT(o->type == NCDVALUE_LIST)
  277. if (LinkedList2_IsEmpty(&o->list)) {
  278. return NULL;
  279. }
  280. NCDListElement *e = UPPER_OBJECT(LinkedList2_GetFirst(&o->list), NCDListElement, list_node);
  281. return &e->v;
  282. }
  283. NCDValue * NCDValue_ListNext (NCDValue *o, NCDValue *ev)
  284. {
  285. value_assert(o);
  286. ASSERT(o->type == NCDVALUE_LIST)
  287. NCDListElement *e = UPPER_OBJECT(ev, NCDListElement, v);
  288. LinkedList2Iterator it;
  289. LinkedList2Iterator_Init(&it, &o->list, 1, &e->list_node);
  290. LinkedList2Iterator_Next(&it);
  291. LinkedList2Node *nen = LinkedList2Iterator_Next(&it);
  292. LinkedList2Iterator_Free(&it);
  293. if (!nen) {
  294. return NULL;
  295. }
  296. NCDListElement *ne = UPPER_OBJECT(nen, NCDListElement, list_node);
  297. return &ne->v;
  298. }
  299. int NCDValue_ListRead (NCDValue *o, int num, ...)
  300. {
  301. value_assert(o);
  302. ASSERT(o->type == NCDVALUE_LIST)
  303. ASSERT(num >= 0)
  304. if (num != NCDValue_ListCount(o)) {
  305. return 0;
  306. }
  307. va_list ap;
  308. va_start(ap, num);
  309. LinkedList2Iterator it;
  310. LinkedList2Iterator_InitForward(&it, &o->list);
  311. LinkedList2Node *n;
  312. while (n = LinkedList2Iterator_Next(&it)) {
  313. NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
  314. NCDValue **dest = va_arg(ap, NCDValue **);
  315. *dest = &e->v;
  316. }
  317. va_end(ap);
  318. return 1;
  319. }
  320. int NCDValue_ListReadHead (NCDValue *o, int num, ...)
  321. {
  322. value_assert(o);
  323. ASSERT(o->type == NCDVALUE_LIST)
  324. ASSERT(num >= 0)
  325. if (num > NCDValue_ListCount(o)) {
  326. return 0;
  327. }
  328. va_list ap;
  329. va_start(ap, num);
  330. LinkedList2Node *n = LinkedList2_GetFirst(&o->list);
  331. while (num > 0) {
  332. ASSERT(n)
  333. NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
  334. NCDValue **dest = va_arg(ap, NCDValue **);
  335. *dest = &e->v;
  336. n = LinkedList2Node_Next(n);
  337. num--;
  338. }
  339. va_end(ap);
  340. return 1;
  341. }
  342. NCDValue * NCDValue_ListGet (NCDValue *o, size_t pos)
  343. {
  344. value_assert(o);
  345. ASSERT(o->type == NCDVALUE_LIST)
  346. ASSERT(pos < o->list_count)
  347. NCDValue *e = NCDValue_ListFirst(o);
  348. while (e) {
  349. if (pos == 0) {
  350. break;
  351. }
  352. pos--;
  353. e = NCDValue_ListNext(o, e);
  354. }
  355. ASSERT(e)
  356. return e;
  357. }
  358. NCDValue NCDValue_ListShift (NCDValue *o)
  359. {
  360. value_assert(o);
  361. ASSERT(o->type == NCDVALUE_LIST)
  362. ASSERT(o->list_count > 0)
  363. NCDListElement *e = UPPER_OBJECT(LinkedList2_GetFirst(&o->list), NCDListElement, list_node);
  364. NCDValue v = e->v;
  365. LinkedList2_Remove(&o->list, &e->list_node);
  366. o->list_count--;
  367. free(e);
  368. return v;
  369. }
  370. NCDValue NCDValue_ListRemove (NCDValue *o, NCDValue *ev)
  371. {
  372. value_assert(o);
  373. ASSERT(o->type == NCDVALUE_LIST)
  374. ASSERT(o->list_count > 0)
  375. NCDListElement *e = UPPER_OBJECT(ev, NCDListElement, v);
  376. NCDValue v = e->v;
  377. LinkedList2_Remove(&o->list, &e->list_node);
  378. o->list_count--;
  379. free(e);
  380. return v;
  381. }
  382. int NCDValue_IsMap (NCDValue *o)
  383. {
  384. value_assert(o);
  385. return o->type == NCDVALUE_MAP;
  386. }
  387. void NCDValue_InitMap (NCDValue *o)
  388. {
  389. o->type = NCDVALUE_MAP;
  390. BAVL_Init(&o->map_tree, OFFSET_DIFF(NCDMapElement, key, map_tree_node), ncdvalue_comparator, NULL);
  391. o->map_count = 0;
  392. }
  393. size_t NCDValue_MapCount (NCDValue *o)
  394. {
  395. value_assert(o);
  396. ASSERT(o->type == NCDVALUE_MAP)
  397. return o->map_count;
  398. }
  399. NCDValue * NCDValue_MapFirstKey (NCDValue *o)
  400. {
  401. value_assert(o);
  402. ASSERT(o->type == NCDVALUE_MAP)
  403. BAVLNode *tn = BAVL_GetFirst(&o->map_tree);
  404. if (!tn) {
  405. return NULL;
  406. }
  407. NCDMapElement *e = UPPER_OBJECT(tn, NCDMapElement, map_tree_node);
  408. value_assert(&e->key);
  409. value_assert(&e->val);
  410. return &e->key;
  411. }
  412. NCDValue * NCDValue_MapNextKey (NCDValue *o, NCDValue *ekey)
  413. {
  414. value_assert(o);
  415. ASSERT(o->type == NCDVALUE_MAP)
  416. NCDMapElement *e = UPPER_OBJECT(ekey, NCDMapElement, key);
  417. value_assert(&e->key);
  418. value_assert(&e->val);
  419. BAVLNode *tn = BAVL_GetNext(&o->map_tree, &e->map_tree_node);
  420. if (!tn) {
  421. return NULL;
  422. }
  423. NCDMapElement *ne = UPPER_OBJECT(tn, NCDMapElement, map_tree_node);
  424. value_assert(&ne->key);
  425. value_assert(&ne->val);
  426. return &ne->key;
  427. }
  428. NCDValue * NCDValue_MapKeyValue (NCDValue *o, NCDValue *ekey)
  429. {
  430. value_assert(o);
  431. ASSERT(o->type == NCDVALUE_MAP)
  432. NCDMapElement *e = UPPER_OBJECT(ekey, NCDMapElement, key);
  433. value_assert(&e->key);
  434. value_assert(&e->val);
  435. return &e->val;
  436. }
  437. NCDValue * NCDValue_MapFindKey (NCDValue *o, NCDValue *key)
  438. {
  439. value_assert(o);
  440. ASSERT(o->type == NCDVALUE_MAP)
  441. value_assert(key);
  442. BAVLNode *tn = BAVL_LookupExact(&o->map_tree, key);
  443. if (!tn) {
  444. return NULL;
  445. }
  446. NCDMapElement *e = UPPER_OBJECT(tn, NCDMapElement, map_tree_node);
  447. value_assert(&e->key);
  448. value_assert(&e->val);
  449. ASSERT(!NCDValue_Compare(&e->key, key))
  450. return &e->key;
  451. }
  452. NCDValue * NCDValue_MapInsert (NCDValue *o, NCDValue key, NCDValue val)
  453. {
  454. value_assert(o);
  455. ASSERT(o->type == NCDVALUE_MAP)
  456. value_assert(&key);
  457. value_assert(&val);
  458. ASSERT(!NCDValue_MapFindKey(o, &key))
  459. if (o->map_count == SIZE_MAX) {
  460. return NULL;
  461. }
  462. NCDMapElement *e = malloc(sizeof(*e));
  463. if (!e) {
  464. return NULL;
  465. }
  466. e->key = key;
  467. e->val = val;
  468. int res = BAVL_Insert(&o->map_tree, &e->map_tree_node, NULL);
  469. ASSERT(res)
  470. o->map_count++;
  471. return &e->key;
  472. }
  473. void NCDValue_MapRemove (NCDValue *o, NCDValue *ekey, NCDValue *out_key, NCDValue *out_val)
  474. {
  475. value_assert(o);
  476. ASSERT(o->type == NCDVALUE_MAP)
  477. ASSERT(out_key)
  478. ASSERT(out_val)
  479. ASSERT(o->map_count > 0)
  480. NCDMapElement *e = UPPER_OBJECT(ekey, NCDMapElement, key);
  481. value_assert(&e->key);
  482. value_assert(&e->val);
  483. BAVL_Remove(&o->map_tree, &e->map_tree_node);
  484. *out_key = e->key;
  485. *out_val = e->val;
  486. o->map_count--;
  487. free(e);
  488. }
  489. NCDValue * NCDValue_MapFindValueByString (NCDValue *o, const char *key_str)
  490. {
  491. value_assert(o);
  492. ASSERT(o->type == NCDVALUE_MAP)
  493. ASSERT(key_str)
  494. NCDValue key;
  495. key.type = NCDVALUE_STRING;
  496. key.string = (uint8_t *)key_str;
  497. key.string_len = strlen(key_str);
  498. NCDValue *ekey = NCDValue_MapFindKey(o, &key);
  499. if (!ekey) {
  500. return NULL;
  501. }
  502. return NCDValue_MapKeyValue(o, ekey);
  503. }
  504. int NCDValue_IsVar (NCDValue *o)
  505. {
  506. value_assert(o);
  507. return o->type == NCDVALUE_VAR;
  508. }
  509. int NCDValue_InitVar (NCDValue *o, const char *var_name)
  510. {
  511. ASSERT(var_name)
  512. if (!(o->var_name = strdup(var_name))) {
  513. return 0;
  514. }
  515. o->type = NCDVALUE_VAR;
  516. return 1;
  517. }
  518. const char * NCDValue_VarName (NCDValue *o)
  519. {
  520. value_assert(o);
  521. ASSERT(o->type == NCDVALUE_VAR)
  522. return o->var_name;
  523. }
  524. int NCDValue_Compare (NCDValue *o, NCDValue *v)
  525. {
  526. value_assert(o);
  527. value_assert(v);
  528. int cmp = (o->type > v->type) - (o->type < v->type);
  529. if (cmp) {
  530. return cmp;
  531. }
  532. ASSERT(o->type == v->type)
  533. if (o->type == NCDVALUE_STRING) {
  534. size_t min_len = o->string_len < v->string_len ? o->string_len : v->string_len;
  535. int cmp = memcmp(o->string, v->string, min_len);
  536. if (cmp) {
  537. return (cmp > 0) - (cmp < 0);
  538. }
  539. return (o->string_len > v->string_len) - (o->string_len < v->string_len);
  540. }
  541. if (o->type == NCDVALUE_LIST) {
  542. NCDValue *x = NCDValue_ListFirst(o);
  543. NCDValue *y = NCDValue_ListFirst(v);
  544. while (1) {
  545. if (!x && y) {
  546. return -1;
  547. }
  548. if (x && !y) {
  549. return 1;
  550. }
  551. if (!x && !y) {
  552. return 0;
  553. }
  554. int res = NCDValue_Compare(x, y);
  555. if (res) {
  556. return res;
  557. }
  558. x = NCDValue_ListNext(o, x);
  559. y = NCDValue_ListNext(v, y);
  560. }
  561. }
  562. if (o->type == NCDVALUE_MAP) {
  563. NCDValue *key1 = NCDValue_MapFirstKey(o);
  564. NCDValue *key2 = NCDValue_MapFirstKey(v);
  565. while (1) {
  566. if (!key1 && key2) {
  567. return -1;
  568. }
  569. if (key1 && !key2) {
  570. return 1;
  571. }
  572. if (!key1 && !key2) {
  573. return 0;
  574. }
  575. int res = NCDValue_Compare(key1, key2);
  576. if (res) {
  577. return res;
  578. }
  579. NCDValue *val1 = NCDValue_MapKeyValue(o, key1);
  580. NCDValue *val2 = NCDValue_MapKeyValue(v, key2);
  581. res = NCDValue_Compare(val1, val2);
  582. if (res) {
  583. return res;
  584. }
  585. key1 = NCDValue_MapNextKey(o, key1);
  586. key2 = NCDValue_MapNextKey(v, key2);
  587. }
  588. }
  589. if (o->type == NCDVALUE_VAR) {
  590. int res = strcmp(o->var_name, v->var_name);
  591. return (res > 0) - (res < 0);
  592. }
  593. ASSERT(0)
  594. return 0;
  595. }