manage loops when freeing
[protos/libecoli.git] / lib / ecoli_node_weakref.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <assert.h>
9 #include <stdarg.h>
10 #include <errno.h>
11
12 #include <ecoli_malloc.h>
13 #include <ecoli_log.h>
14 #include <ecoli_test.h>
15 #include <ecoli_strvec.h>
16 #include <ecoli_node.h>
17 #include <ecoli_parse.h>
18 #include <ecoli_complete.h>
19 #include <ecoli_node_str.h>
20 #include <ecoli_node_option.h>
21 #include <ecoli_node_weakref.h>
22 #include <ecoli_node_int.h>
23 #include <ecoli_node_seq.h>
24 #include <ecoli_node_or.h>
25
26 EC_LOG_TYPE_REGISTER(node_weakref);
27
28 struct ec_node_weakref {
29         struct ec_node gen;
30         struct ec_node *child;
31 };
32
33 static int
34 ec_node_weakref_parse(const struct ec_node *gen_node,
35                 struct ec_parse *state,
36                 const struct ec_strvec *strvec)
37 {
38         struct ec_node_weakref *node = (struct ec_node_weakref *)gen_node;
39
40         return ec_node_parse_child(node->child, state, strvec);
41 }
42
43 static int
44 ec_node_weakref_complete(const struct ec_node *gen_node,
45                         struct ec_comp *comp,
46                         const struct ec_strvec *strvec)
47 {
48         struct ec_node_weakref *node = (struct ec_node_weakref *)gen_node;
49
50         return ec_node_complete_child(node->child, comp, strvec);
51 }
52
53 static struct ec_node_type ec_node_weakref_type = {
54         .name = "weakref",
55         .parse = ec_node_weakref_parse,
56         .complete = ec_node_weakref_complete,
57         .size = sizeof(struct ec_node_weakref),
58 };
59
60 EC_NODE_TYPE_REGISTER(ec_node_weakref_type);
61
62 int ec_node_weakref_set(struct ec_node *gen_node, struct ec_node *child)
63 {
64         struct ec_node_weakref *node = (struct ec_node_weakref *)gen_node;
65
66         assert(node != NULL);
67
68         if (child == NULL) {
69                 errno = EINVAL;
70                 goto fail;
71         }
72
73         if (ec_node_check_type(gen_node, &ec_node_weakref_type) < 0)
74                 goto fail;
75
76         node->child = child;
77
78         return 0;
79
80 fail:
81         /* do not free child */
82         return -1;
83 }
84
85 struct ec_node *ec_node_weakref(const char *id, struct ec_node *child)
86 {
87         struct ec_node *gen_node = NULL;
88
89         if (child == NULL)
90                 return NULL;
91
92         gen_node = __ec_node(&ec_node_weakref_type, id);
93         if (gen_node == NULL)
94                 return NULL;
95
96         ec_node_weakref_set(gen_node, child);
97
98         return gen_node;
99 }
100
101 /* LCOV_EXCL_START */
102 static int ec_node_weakref_testcase(void)
103 {
104         struct ec_node *weak = NULL, *expr = NULL, *val = NULL;
105         struct ec_node *seq = NULL, *op = NULL;
106         int testres = 0;
107
108         expr = ec_node("or", EC_NO_ID);
109         val = ec_node_int(EC_NO_ID, 0, 10, 10);
110         op = ec_node_str(EC_NO_ID, "!");
111         weak = ec_node_weakref(EC_NO_ID, expr);
112         if (weak == NULL || expr == NULL || val == NULL || op == NULL)
113                 goto fail;
114         seq = EC_NODE_SEQ(EC_NO_ID, op, weak);
115         op = NULL;
116         weak = NULL;
117
118         if (ec_node_or_add(expr, seq) < 0)
119                 goto fail;
120         seq = NULL;
121         if (ec_node_or_add(expr, val) < 0)
122                 goto fail;
123         val = NULL;
124
125         testres |= EC_TEST_CHECK_PARSE(expr, 1, "1");
126         testres |= EC_TEST_CHECK_PARSE(expr, 2, "!", "1");
127         testres |= EC_TEST_CHECK_PARSE(expr, 3, "!", "!", "1");
128
129         testres |= EC_TEST_CHECK_COMPLETE(expr,
130                 "", EC_NODE_ENDLIST,
131                 "!", EC_NODE_ENDLIST);
132         testres |= EC_TEST_CHECK_COMPLETE(expr,
133                 "!", "", EC_NODE_ENDLIST,
134                 "!", EC_NODE_ENDLIST);
135
136         ec_node_free(expr);
137
138         return testres;
139
140 fail:
141         ec_node_free(weak);
142         ec_node_free(expr);
143         ec_node_free(val);
144         ec_node_free(seq);
145         ec_node_free(op);
146         return -1;
147 }
148 /* LCOV_EXCL_STOP */
149
150 static struct ec_test ec_node_weakref_test = {
151         .name = "node_weakref",
152         .test = ec_node_weakref_testcase,
153 };
154
155 EC_TEST_REGISTER(ec_node_weakref_test);