Coverage Report

Created: 2023-06-07 07:02

/src/core/libpromises/string_expressions.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
  Copyright 2023 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 <cf3.defs.h>
26
27
#include <stdbool.h>
28
#include <string_expressions.h>
29
#include <misc_lib.h>
30
31
#include <stdlib.h>
32
#include <string.h>
33
#include <stdio.h>
34
35
/* <qname> */
36
37
static StringParseResult ParseQname(const char *expr, int start, int end)
38
861k
{
39
861k
    StringParseResult lhs, rhs;
40
861k
    StringExpression *ret, *subret, *dot;
41
42
861k
    lhs = ParseStringExpression(expr, start, end);
43
44
861k
    if (!lhs.result)
45
12.5k
    {
46
12.5k
        return lhs;
47
12.5k
    }
48
49
849k
    if (lhs.position == end || expr[lhs.position] != '.')
50
751k
    {
51
751k
        return lhs;
52
751k
    }
53
54
97.2k
    rhs = ParseStringExpression(expr, lhs.position + 1, end);
55
56
97.2k
    if (!rhs.result)
57
1.97k
    {
58
1.97k
        FreeStringExpression(lhs.result);
59
1.97k
        return rhs;
60
1.97k
    }
61
62
95.2k
    dot = xcalloc(1, sizeof(StringExpression));
63
95.2k
    dot->op = LITERAL;
64
95.2k
    dot->val.literal.literal = xstrdup(".");
65
66
95.2k
    subret = xcalloc(1, sizeof(StringExpression));
67
95.2k
    subret->op = CONCAT;
68
95.2k
    subret->val.concat.lhs = dot;
69
95.2k
    subret->val.concat.rhs = rhs.result;
70
71
95.2k
    ret = xcalloc(1, sizeof(StringExpression));
72
95.2k
    ret->op = CONCAT;
73
95.2k
    ret->val.concat.lhs = lhs.result;
74
95.2k
    ret->val.concat.rhs = subret;
75
76
95.2k
    return (StringParseResult) {ret, rhs.position};
77
97.2k
}
78
79
/* <var-ref> */
80
81
static StringParseResult ParseVarRef(const char *expr, int start, int end)
82
972k
{
83
972k
    if (start + 1 < end && (expr[start] == '$' || expr[start] == '@'))
84
861k
    {
85
861k
        if (expr[start + 1] == '(' || expr[start + 1] == '{')
86
861k
        {
87
861k
            char closing_bracket = expr[start + 1] == '(' ? ')' : '}';
88
861k
            StringParseResult res = ParseQname(expr, start + 2, end);
89
90
861k
            if (res.result)
91
847k
            {
92
847k
                if (res.position < end && expr[res.position] == closing_bracket)
93
12.7k
                {
94
12.7k
                    StringExpression *ret = xcalloc(1, sizeof(StringExpression));
95
96
12.7k
                    ret->op = VARREF;
97
12.7k
                    ret->val.varref.name = res.result;
98
99
12.7k
                    if (expr[start] == '$')
100
10.5k
                    {
101
10.5k
                        ret->val.varref.type = VAR_REF_TYPE_SCALAR;
102
10.5k
                    }
103
2.22k
                    else if (expr[start] == '@')
104
2.22k
                    {
105
2.22k
                        ret->val.varref.type = VAR_REF_TYPE_LIST;
106
2.22k
                    }
107
0
                    else
108
0
                    {
109
0
                        ProgrammingError("Unrecognized var ref type");
110
0
                    }
111
112
12.7k
                    return (StringParseResult) {ret, res.position + 1};
113
12.7k
                }
114
834k
                else
115
834k
                {
116
834k
                    FreeStringExpression(res.result);
117
834k
                    return (StringParseResult) {NULL, res.position};
118
834k
                }
119
847k
            }
120
14.5k
            else
121
14.5k
            {
122
14.5k
                return res;
123
14.5k
            }
124
861k
        }
125
25
        else
126
25
        {
127
25
            return (StringParseResult) {NULL, start + 1};
128
25
        }
129
861k
    }
130
110k
    else
131
110k
    {
132
110k
        return (StringParseResult) {NULL, start};
133
110k
    }
134
972k
}
135
136
/* <token> */
137
138
static inline bool ValidTokenCharacter(char c, bool *inside_index)
139
12.2M
{
140
12.2M
    assert(inside_index != NULL);
141
142
12.2M
    if (c >= 'a' && c <= 'z')
143
1.44M
    {
144
1.44M
        return true;
145
1.44M
    }
146
147
10.7M
    if (c >= 'A' && c <= 'Z')
148
3.78M
    {
149
3.78M
        return true;
150
3.78M
    }
151
152
7.01M
    if (c >= '0' && c <= '9')
153
3.75M
    {
154
3.75M
        return true;
155
3.75M
    }
156
157
3.25M
    if (c == '_' || c == ':')
158
87.1k
    {
159
87.1k
        return true;
160
87.1k
    }
161
162
3.16M
    if (c == '[')
163
687k
    {
164
687k
        *inside_index = true;
165
687k
        return true;
166
687k
    }
167
168
2.48M
    if (c == ']')
169
502k
    {
170
502k
        if (*inside_index)
171
442k
        {
172
442k
            *inside_index = false;
173
442k
        }
174
502k
        return true;
175
502k
    }
176
177
1.97M
    if ((c == ' ') && *inside_index)
178
50.9k
    {
179
50.9k
        return true;
180
50.9k
    }
181
182
1.92M
    return false;
183
1.97M
}
184
185
static StringParseResult ParseToken(const char *expr, int start, int end)
186
1.92M
{
187
1.92M
    int endlit = start;
188
189
1.92M
    bool inside_index = false;
190
12.2M
    while (endlit < end && ValidTokenCharacter(expr[endlit], &inside_index))
191
10.3M
    {
192
10.3M
        endlit++;
193
10.3M
    }
194
195
1.92M
    if (endlit > start)
196
955k
    {
197
955k
        StringExpression *ret = xcalloc(1, sizeof(StringExpression));
198
199
955k
        ret->op = LITERAL;
200
955k
        ret->val.literal.literal = xstrndup(expr + start, endlit - start);
201
202
955k
        return (StringParseResult) {ret, endlit};
203
955k
    }
204
972k
    else
205
972k
    {
206
972k
        return (StringParseResult) {NULL, endlit};
207
972k
    }
208
1.92M
}
209
210
/* <term> */
211
212
static StringParseResult ParseTerm(const char *expr, int start, int end)
213
1.92M
{
214
1.92M
    StringParseResult res = ParseToken(expr, start, end);
215
216
1.92M
    if (res.result)
217
955k
    {
218
955k
        return res;
219
955k
    }
220
972k
    else
221
972k
    {
222
972k
        return ParseVarRef(expr, start, end);
223
972k
    }
224
1.92M
}
225
226
/* <name> */
227
228
StringParseResult ParseStringExpression(const char *expr, int start, int end)
229
1.92M
{
230
1.92M
    StringParseResult lhs = ParseTerm(expr, start, end);
231
232
1.92M
    if (lhs.result)
233
968k
    {
234
968k
        StringParseResult rhs = ParseStringExpression(expr, lhs.position, end);
235
236
968k
        if (rhs.result)
237
23.5k
        {
238
23.5k
            StringExpression *ret = xcalloc(1, sizeof(StringExpression));
239
240
23.5k
            ret->op = CONCAT;
241
23.5k
            ret->val.concat.lhs = lhs.result;
242
23.5k
            ret->val.concat.rhs = rhs.result;
243
244
23.5k
            return (StringParseResult) {ret, rhs.position};
245
23.5k
        }
246
944k
        else
247
944k
        {
248
944k
            return lhs;
249
944k
        }
250
968k
    }
251
959k
    else
252
959k
    {
253
959k
        return lhs;
254
959k
    }
255
1.92M
}
256
257
/* Evaluation */
258
259
static char *EvalConcat(const StringExpression *expr, VarRefEvaluator evalfn, void *param)
260
0
{
261
0
    char *lhs, *rhs, *res;
262
263
0
    lhs = EvalStringExpression(expr->val.concat.lhs, evalfn, param);
264
0
    if (!lhs)
265
0
    {
266
0
        return NULL;
267
0
    }
268
269
0
    rhs = EvalStringExpression(expr->val.concat.rhs, evalfn, param);
270
0
    if (!rhs)
271
0
    {
272
0
        free(lhs);
273
0
        return NULL;
274
0
    }
275
276
0
    xasprintf(&res, "%s%s", lhs, rhs);
277
0
    free(lhs);
278
0
    free(rhs);
279
0
    return res;
280
0
}
281
282
static char *EvalVarRef(const StringExpression *expr, VarRefEvaluator evalfn, void *param)
283
0
{
284
0
    char *name, *eval;
285
286
0
    name = EvalStringExpression(expr->val.varref.name, evalfn, param);
287
0
    if (!name)
288
0
    {
289
0
        return NULL;
290
0
    }
291
292
0
    eval = (*evalfn) (name, expr->val.varref.type, param);
293
0
    free(name);
294
0
    return eval;
295
0
}
296
297
char *EvalStringExpression(const StringExpression *expr, VarRefEvaluator evalfn, void *param)
298
0
{
299
0
    switch (expr->op)
300
0
    {
301
0
    case CONCAT:
302
0
        return EvalConcat(expr, evalfn, param);
303
0
    case LITERAL:
304
0
        return xstrdup(expr->val.literal.literal);
305
0
    case VARREF:
306
0
        return EvalVarRef(expr, evalfn, param);
307
0
    default:
308
0
        ProgrammingError("Unknown type of string expression" "encountered during evaluation: %d", expr->op);
309
0
    }
310
0
}
311
312
/* Freeing results */
313
314
void FreeStringExpression(StringExpression *expr)
315
1.27M
{
316
1.27M
    if (!expr)
317
159
    {
318
159
        return;
319
159
    }
320
321
1.27M
    switch (expr->op)
322
1.27M
    {
323
214k
    case CONCAT:
324
214k
        FreeStringExpression(expr->val.concat.lhs);
325
214k
        FreeStringExpression(expr->val.concat.rhs);
326
214k
        break;
327
1.05M
    case LITERAL:
328
1.05M
        free(expr->val.literal.literal);
329
1.05M
        break;
330
12.7k
    case VARREF:
331
12.7k
        FreeStringExpression(expr->val.varref.name);
332
12.7k
        break;
333
0
    default:
334
0
        ProgrammingError("Unknown type of string expression encountered: %d", expr->op);
335
1.27M
    }
336
337
1.27M
    free(expr);
338
1.27M
}