1 /*
2 Copyright 2021 Northern.tech AS
3
4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 3.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
19 To the extent this program is licensed as part of the Enterprise
20 versions of CFEngine, the applicable Commercial Open Source License
21 (COSL) may apply to this file if you as a licensee so wish it. See
22 included file COSL.txt.
23 */
24
25 #include <platform.h>
26
27 #include <cf3.defs.h>
28 #include <stdbool.h>
29 #include <logic_expressions.h>
30 #include <misc_lib.h>
31
32 #include <stdlib.h>
33
34 /* <primary> */
35
ParsePrimary(const char * expr,int start,int end)36 static ParseResult ParsePrimary(const char *expr, int start, int end)
37 {
38 if (start < end && expr[start] == '(')
39 {
40 ParseResult res = ParseExpression(expr, start + 1, end);
41
42 if (res.result)
43 {
44 /* Check if there is a matching ')' at the end */
45 if (res.position < end && expr[res.position] == ')')
46 {
47 return (ParseResult) {res.result, res.position + 1};
48 }
49 else
50 {
51 /* Haven't found a matching bracket. Give up */
52 FreeExpression(res.result);
53 return (ParseResult) {NULL, res.position};
54 }
55 }
56 else
57 {
58 return res;
59 }
60 }
61 else
62 {
63 StringParseResult strres = ParseStringExpression(expr, start, end);
64
65 if (strres.result)
66 {
67 Expression *res = xcalloc(1, sizeof(Expression));
68
69 res->op = LOGICAL_OP_EVAL;
70 res->val.eval.name = strres.result;
71
72 return (ParseResult) {res, strres.position};
73 }
74 else
75 {
76 return (ParseResult) {NULL, strres.position};
77 }
78 }
79 }
80
81 /* <not-expr> */
82
ParseNotExpression(const char * expr,int start,int end)83 static ParseResult ParseNotExpression(const char *expr, int start, int end)
84 {
85 if (start < end && expr[start] == '!')
86 {
87 ParseResult primres = ParsePrimary(expr, start + 1, end);
88
89 if (primres.result)
90 {
91 Expression *res = xcalloc(1, sizeof(Expression));
92
93 res->op = LOGICAL_OP_NOT;
94 res->val.not.arg = primres.result;
95
96 return (ParseResult) {res, primres.position};
97 }
98 else
99 {
100 return primres;
101 }
102 }
103 else
104 {
105 return ParsePrimary(expr, start, end);
106 }
107 }
108
109 /* <and-expr> */
110
ParseAndExpression(const char * expr,int start,int end)111 static ParseResult ParseAndExpression(const char *expr, int start, int end)
112 {
113 ParseResult lhs, rhs;
114 Expression *res;
115
116 lhs = ParseNotExpression(expr, start, end);
117
118 if (!lhs.result)
119 {
120 return lhs;
121 }
122
123 if (lhs.position == end || (expr[lhs.position] != '.' && expr[lhs.position] != '&'))
124 {
125 return lhs;
126 }
127
128 rhs = ParseAndExpression(expr, lhs.position + 1, end);
129
130 if (!rhs.result)
131 {
132 FreeExpression(lhs.result);
133 return rhs;
134 }
135
136 res = xcalloc(1, sizeof(Expression));
137 res->op = LOGICAL_OP_AND;
138 res->val.andor.lhs = lhs.result;
139 res->val.andor.rhs = rhs.result;
140
141 return (ParseResult) {res, rhs.position};
142 }
143
144 /* <or-expr> */
145
ParseExpression(const char * expr,int start,int end)146 ParseResult ParseExpression(const char *expr, int start, int end)
147 {
148 ParseResult lhs, rhs;
149 Expression *res;
150 int position;
151
152 lhs = ParseAndExpression(expr, start, end);
153
154 if (!lhs.result)
155 {
156 return lhs;
157 }
158
159 /* End of left-hand side expression */
160 position = lhs.position;
161
162 if (position == end || expr[position] != '|')
163 {
164 return lhs;
165 }
166
167 /* Skip second '|' in 'lhs||rhs' */
168
169 if (position + 1 < end && expr[position + 1] == '|')
170 {
171 position++;
172 }
173
174 rhs = ParseExpression(expr, position + 1, end);
175
176 if (!rhs.result)
177 {
178 FreeExpression(lhs.result);
179 return rhs;
180 }
181
182 res = xcalloc(1, sizeof(Expression));
183 res->op = LOGICAL_OP_OR;
184 res->val.andor.lhs = lhs.result;
185 res->val.andor.rhs = rhs.result;
186
187 return (ParseResult) {res, rhs.position};
188 }
189
190 /* Evaluation */
191
EvalExpression(const Expression * expr,NameEvaluator nameevalfn,VarRefEvaluator varrefevalfn,void * param)192 ExpressionValue EvalExpression(const Expression *expr,
193 NameEvaluator nameevalfn, VarRefEvaluator varrefevalfn, void *param)
194 {
195 switch (expr->op)
196 {
197 case LOGICAL_OP_OR:
198 case LOGICAL_OP_AND:
199 {
200 ExpressionValue lhs = EXPRESSION_VALUE_ERROR, rhs = EXPRESSION_VALUE_ERROR;
201
202 lhs = EvalExpression(expr->val.andor.lhs, nameevalfn, varrefevalfn, param);
203 if (lhs == EXPRESSION_VALUE_ERROR)
204 {
205 return EXPRESSION_VALUE_ERROR;
206 }
207
208 rhs = EvalExpression(expr->val.andor.rhs, nameevalfn, varrefevalfn, param);
209
210 if (rhs == EXPRESSION_VALUE_ERROR)
211 {
212 return EXPRESSION_VALUE_ERROR;
213 }
214
215 if (expr->op == LOGICAL_OP_OR)
216 {
217 return ((ExpressionValue) (lhs || rhs));
218 }
219 else
220 {
221 return ((ExpressionValue) (lhs && rhs));
222 }
223 }
224
225 case LOGICAL_OP_NOT:
226 {
227 ExpressionValue arg = EvalExpression(expr->val.not.arg,
228 nameevalfn,
229 varrefevalfn,
230 param);
231
232 if (arg == EXPRESSION_VALUE_ERROR)
233 {
234 return EXPRESSION_VALUE_ERROR;
235 }
236 else
237 {
238 return !arg;
239 }
240 }
241
242 case LOGICAL_OP_EVAL:
243 {
244 ExpressionValue ret = EXPRESSION_VALUE_ERROR;
245 char *name = EvalStringExpression(expr->val.eval.name,
246 varrefevalfn,
247 param);
248
249 if (name == NULL)
250 {
251 return EXPRESSION_VALUE_ERROR;
252 }
253 else if (strcmp("true", name) == 0)
254 {
255 ret = EXPRESSION_VALUE_TRUE;
256 }
257 else if (strcmp("false", name) == 0)
258 {
259 ret = EXPRESSION_VALUE_FALSE;
260 }
261 else
262 {
263 ret = (*nameevalfn) (name, param);
264 }
265
266 free(name);
267 return ret;
268 }
269
270 default:
271 ProgrammingError("Unexpected class expression type is found: %d", expr->op);
272 }
273 }
274
275 /* Freeing results */
276
FreeExpression(Expression * e)277 void FreeExpression(Expression *e)
278 {
279 if (!e)
280 {
281 return;
282 }
283
284 switch (e->op)
285 {
286 case LOGICAL_OP_OR:
287 case LOGICAL_OP_AND:
288 FreeExpression(e->val.andor.lhs);
289 FreeExpression(e->val.andor.rhs);
290 break;
291 case LOGICAL_OP_NOT:
292 FreeExpression(e->val.not.arg);
293 break;
294 case LOGICAL_OP_EVAL:
295 FreeStringExpression(e->val.eval.name);
296 break;
297 default:
298 ProgrammingError("Unknown logic expression type encountered in" "FreeExpression: %d", e->op);
299 }
300 free(e);
301 }
302