NCDValue.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  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 void value_assert (NCDValue *o)
  37. {
  38. switch (o->type) {
  39. case NCDVALUE_STRING:
  40. case NCDVALUE_LIST:
  41. return;
  42. default:
  43. ASSERT(0);
  44. }
  45. }
  46. int NCDValue_InitCopy (NCDValue *o, NCDValue *v)
  47. {
  48. value_assert(v);
  49. switch (v->type) {
  50. case NCDVALUE_STRING: {
  51. return NCDValue_InitString(o, v->string);
  52. } break;
  53. case NCDVALUE_LIST: {
  54. NCDValue_InitList(o);
  55. LinkedList2Iterator it;
  56. LinkedList2Iterator_InitForward(&it, &v->list);
  57. LinkedList2Node *n;
  58. while (n = LinkedList2Iterator_Next(&it)) {
  59. NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
  60. NCDValue tmp;
  61. if (!NCDValue_InitCopy(&tmp, &e->v)) {
  62. goto fail;
  63. }
  64. if (!NCDValue_ListAppend(o, tmp)) {
  65. NCDValue_Free(&tmp);
  66. goto fail;
  67. }
  68. }
  69. return 1;
  70. fail:
  71. LinkedList2Iterator_Free(&it);
  72. NCDValue_Free(o);
  73. return 0;
  74. } break;
  75. default:
  76. ASSERT(0);
  77. }
  78. return 0;
  79. }
  80. void NCDValue_Free (NCDValue *o)
  81. {
  82. switch (o->type) {
  83. case NCDVALUE_STRING: {
  84. free(o->string);
  85. } break;
  86. case NCDVALUE_LIST: {
  87. LinkedList2Node *n;
  88. while (n = LinkedList2_GetFirst(&o->list)) {
  89. NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
  90. NCDValue_Free(&e->v);
  91. LinkedList2_Remove(&o->list, &e->list_node);
  92. free(e);
  93. }
  94. } break;
  95. default:
  96. ASSERT(0);
  97. }
  98. }
  99. int NCDValue_Type (NCDValue *o)
  100. {
  101. value_assert(o);
  102. return o->type;
  103. }
  104. int NCDValue_InitString (NCDValue *o, const char *str)
  105. {
  106. size_t len = strlen(str);
  107. if (!(o->string = malloc(len + 1))) {
  108. return 0;
  109. }
  110. memcpy(o->string, str, len);
  111. o->string[len] = '\0';
  112. o->type = NCDVALUE_STRING;
  113. return 1;
  114. }
  115. char * NCDValue_StringValue (NCDValue *o)
  116. {
  117. ASSERT(o->type == NCDVALUE_STRING)
  118. return o->string;
  119. }
  120. void NCDValue_InitList (NCDValue *o)
  121. {
  122. LinkedList2_Init(&o->list);
  123. o->list_count = 0;
  124. o->type = NCDVALUE_LIST;
  125. }
  126. int NCDValue_ListAppend (NCDValue *o, NCDValue v)
  127. {
  128. value_assert(o);
  129. value_assert(&v);
  130. ASSERT(o->type == NCDVALUE_LIST)
  131. if (o->list_count == SIZE_MAX) {
  132. return 0;
  133. }
  134. NCDListElement *e = malloc(sizeof(*e));
  135. if (!e) {
  136. return 0;
  137. }
  138. LinkedList2_Append(&o->list, &e->list_node);
  139. o->list_count++;
  140. e->v = v;
  141. return 1;
  142. }
  143. int NCDValue_ListAppendList (NCDValue *o, NCDValue l)
  144. {
  145. value_assert(o);
  146. value_assert(&l);
  147. ASSERT(o->type == NCDVALUE_LIST)
  148. ASSERT(l.type == NCDVALUE_LIST)
  149. if (l.list_count > SIZE_MAX - o->list_count) {
  150. return 0;
  151. }
  152. LinkedList2Node *n;
  153. while (n = LinkedList2_GetFirst(&l.list)) {
  154. NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
  155. LinkedList2_Remove(&l.list, &e->list_node);
  156. LinkedList2_Append(&o->list, &e->list_node);
  157. }
  158. o->list_count += l.list_count;
  159. return 1;
  160. }
  161. size_t NCDValue_ListCount (NCDValue *o)
  162. {
  163. value_assert(o);
  164. ASSERT(o->type == NCDVALUE_LIST)
  165. return o->list_count;
  166. }
  167. NCDValue * NCDValue_ListFirst (NCDValue *o)
  168. {
  169. value_assert(o);
  170. ASSERT(o->type == NCDVALUE_LIST)
  171. if (LinkedList2_IsEmpty(&o->list)) {
  172. return NULL;
  173. }
  174. NCDListElement *e = UPPER_OBJECT(LinkedList2_GetFirst(&o->list), NCDListElement, list_node);
  175. return &e->v;
  176. }
  177. NCDValue * NCDValue_ListNext (NCDValue *o, NCDValue *ev)
  178. {
  179. value_assert(o);
  180. ASSERT(o->type == NCDVALUE_LIST)
  181. NCDListElement *e = UPPER_OBJECT(ev, NCDListElement, v);
  182. LinkedList2Iterator it;
  183. LinkedList2Iterator_Init(&it, &o->list, 1, &e->list_node);
  184. LinkedList2Iterator_Next(&it);
  185. LinkedList2Node *nen = LinkedList2Iterator_Next(&it);
  186. LinkedList2Iterator_Free(&it);
  187. if (!nen) {
  188. return NULL;
  189. }
  190. NCDListElement *ne = UPPER_OBJECT(nen, NCDListElement, list_node);
  191. return &ne->v;
  192. }
  193. int NCDValue_ListRead (NCDValue *o, int num, ...)
  194. {
  195. value_assert(o);
  196. ASSERT(o->type == NCDVALUE_LIST)
  197. ASSERT(num >= 0)
  198. if (num != NCDValue_ListCount(o)) {
  199. return 0;
  200. }
  201. va_list ap;
  202. va_start(ap, num);
  203. LinkedList2Iterator it;
  204. LinkedList2Iterator_InitForward(&it, &o->list);
  205. LinkedList2Node *n;
  206. while (n = LinkedList2Iterator_Next(&it)) {
  207. NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
  208. NCDValue **dest = va_arg(ap, NCDValue **);
  209. *dest = &e->v;
  210. }
  211. va_end(ap);
  212. return 1;
  213. }
  214. int NCDValue_ListReadHead (NCDValue *o, int num, ...)
  215. {
  216. value_assert(o);
  217. ASSERT(o->type == NCDVALUE_LIST)
  218. ASSERT(num >= 0)
  219. if (num > NCDValue_ListCount(o)) {
  220. return 0;
  221. }
  222. va_list ap;
  223. va_start(ap, num);
  224. LinkedList2Node *n = LinkedList2_GetFirst(&o->list);
  225. while (num > 0) {
  226. ASSERT(n)
  227. NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
  228. NCDValue **dest = va_arg(ap, NCDValue **);
  229. *dest = &e->v;
  230. n = LinkedList2Node_Next(n);
  231. num--;
  232. }
  233. va_end(ap);
  234. return 1;
  235. }
  236. NCDValue * NCDValue_ListGet (NCDValue *o, size_t pos)
  237. {
  238. value_assert(o);
  239. ASSERT(o->type == NCDVALUE_LIST)
  240. ASSERT(pos < o->list_count)
  241. NCDValue *e = NCDValue_ListFirst(o);
  242. while (e) {
  243. if (pos == 0) {
  244. break;
  245. }
  246. pos--;
  247. e = NCDValue_ListNext(o, e);
  248. }
  249. ASSERT(e)
  250. return e;
  251. }
  252. NCDValue NCDValue_ListShift (NCDValue *o)
  253. {
  254. value_assert(o);
  255. ASSERT(o->type == NCDVALUE_LIST)
  256. ASSERT(o->list_count > 0)
  257. NCDListElement *e = UPPER_OBJECT(LinkedList2_GetFirst(&o->list), NCDListElement, list_node);
  258. NCDValue v = e->v;
  259. LinkedList2_Remove(&o->list, &e->list_node);
  260. o->list_count--;
  261. free(e);
  262. return v;
  263. }
  264. NCDValue NCDValue_ListRemove (NCDValue *o, NCDValue *ev)
  265. {
  266. value_assert(o);
  267. ASSERT(o->type == NCDVALUE_LIST)
  268. ASSERT(o->list_count > 0)
  269. NCDListElement *e = UPPER_OBJECT(ev, NCDListElement, v);
  270. NCDValue v = e->v;
  271. LinkedList2_Remove(&o->list, &e->list_node);
  272. o->list_count--;
  273. free(e);
  274. return v;
  275. }
  276. int NCDValue_Compare (NCDValue *o, NCDValue *v)
  277. {
  278. value_assert(o);
  279. value_assert(v);
  280. if (o->type == NCDVALUE_STRING && v->type == NCDVALUE_LIST) {
  281. return -1;
  282. }
  283. if (o->type == NCDVALUE_LIST && v->type == NCDVALUE_STRING) {
  284. return 1;
  285. }
  286. if (o->type == NCDVALUE_STRING && v->type == NCDVALUE_STRING) {
  287. int cmp = strcmp(o->string, v->string);
  288. if (cmp < 0) {
  289. return -1;
  290. }
  291. if (cmp > 0) {
  292. return 1;
  293. }
  294. return 0;
  295. }
  296. NCDValue *x = NCDValue_ListFirst(o);
  297. NCDValue *y = NCDValue_ListFirst(v);
  298. while (1) {
  299. if (!x && y) {
  300. return -1;
  301. }
  302. if (x && !y) {
  303. return 1;
  304. }
  305. if (!x && !y) {
  306. return 0;
  307. }
  308. int res = NCDValue_Compare(x, y);
  309. if (res) {
  310. return res;
  311. }
  312. x = NCDValue_ListNext(o, x);
  313. y = NCDValue_ListNext(v, y);
  314. }
  315. }