Coverage Report

Created: 2023-12-12 06:10

/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
840k
{
39
840k
    StringParseResult lhs, rhs;
40
840k
    StringExpression *ret, *subret, *dot;
41
42
840k
    lhs = ParseStringExpression(expr, start, end);
43
44
840k
    if (!lhs.result)
45
15.3k
    {
46
15.3k
        return lhs;
47
15.3k
    }
48
49
825k
    if (lhs.position == end || expr[lhs.position] != '.')
50
702k
    {
51
702k
        return lhs;
52
702k
    }
53
54
123k
    rhs = ParseStringExpression(expr, lhs.position + 1, end);
55
56
123k
    if (!rhs.result)
57
1.70k
    {
58
1.70k
        FreeStringExpression(lhs.result);
59
1.70k
        return rhs;
60
1.70k
    }
61
62
121k
    dot = xcalloc(1, sizeof(StringExpression));
63
121k
    dot->op = LITERAL;
64
121k
    dot->val.literal.literal = xstrdup(".");
65
66
121k
    subret = xcalloc(1, sizeof(StringExpression));
67
121k
    subret->op = CONCAT;
68
121k
    subret->val.concat.lhs = dot;
69
121k
    subret->val.concat.rhs = rhs.result;
70
71
121k
    ret = xcalloc(1, sizeof(StringExpression));
72
121k
    ret->op = CONCAT;
73
121k
    ret->val.concat.lhs = lhs.result;
74
121k
    ret->val.concat.rhs = subret;
75
76
121k
    return (StringParseResult) {ret, rhs.position};
77
123k
}
78
79
/* <var-ref> */
80
81
static StringParseResult ParseVarRef(const char *expr, int start, int end)
82
984k
{
83
984k
    if (start + 1 < end && (expr[start] == '$' || expr[start] == '@'))
84
840k
    {
85
840k
        if (expr[start + 1] == '(' || expr[start + 1] == '{')
86
840k
        {
87
840k
            char closing_bracket = expr[start + 1] == '(' ? ')' : '}';
88
840k
            StringParseResult res = ParseQname(expr, start + 2, end);
89
90
840k
            if (res.result)
91
823k
            {
92
823k
                if (res.position < end && expr[res.position] == closing_bracket)
93
19.3k
                {
94
19.3k
                    StringExpression *ret = xcalloc(1, sizeof(StringExpression));
95
96
19.3k
                    ret->op = VARREF;
97
19.3k
                    ret->val.varref.name = res.result;
98
99
19.3k
                    if (expr[start] == '$')
100
15.7k
                    {
101
15.7k
                        ret->val.varref.type = VAR_REF_TYPE_SCALAR;
102
15.7k
                    }
103
3.56k
                    else if (expr[start] == '@')
104
3.56k
                    {
105
3.56k
                        ret->val.varref.type = VAR_REF_TYPE_LIST;
106
3.56k
                    }
107
0
                    else
108
0
                    {
109
0
                        ProgrammingError("Unrecognized var ref type");
110
0
                    }
111
112
19.3k
                    return (StringParseResult) {ret, res.position + 1};
113
19.3k
                }
114
804k
                else
115
804k
                {
116
804k
                    FreeStringExpression(res.result);
117
804k
                    return (StringParseResult) {NULL, res.position};
118
804k
                }
119
823k
            }
120
17.0k
            else
121
17.0k
            {
122
17.0k
                return res;
123
17.0k
            }
124
840k
        }
125
31
        else
126
31
        {
127
31
            return (StringParseResult) {NULL, start + 1};
128
31
        }
129
840k
    }
130
143k
    else
131
143k
    {
132
143k
        return (StringParseResult) {NULL, start};
133
143k
    }
134
984k
}
135
136
/* <token> */
137
138
static inline bool ValidTokenCharacter(char c, bool *inside_index)
139
11.9M
{
140
11.9M
    assert(inside_index != NULL);
141
142
11.9M
    if (c >= 'a' && c <= 'z')
143
1.13M
    {
144
1.13M
        return true;
145
1.13M
    }
146
147
10.8M
    if (c >= 'A' && c <= 'Z')
148
3.58M
    {
149
3.58M
        return true;
150
3.58M
    }
151
152
7.25M
    if (c >= '0' && c <= '9')
153
2.38M
    {
154
2.38M
        return true;
155
2.38M
    }
156
157
4.86M
    if (c == '_' || c == ':')
158
31.8k
    {
159
31.8k
        return true;
160
31.8k
    }
161
162
4.83M
    if (c == '[')
163
997k
    {
164
997k
        *inside_index = true;
165
997k
        return true;
166
997k
    }
167
168
3.83M
    if (c == ']')
169
1.84M
    {
170
1.84M
        if (*inside_index)
171
862k
        {
172
862k
            *inside_index = false;
173
862k
        }
174
1.84M
        return true;
175
1.84M
    }
176
177
1.99M
    if ((c == ' ') && *inside_index)
178
47.6k
    {
179
47.6k
        return true;
180
47.6k
    }
181
182
1.94M
    return false;
183
1.99M
}
184
185
static StringParseResult ParseToken(const char *expr, int start, int end)
186
1.94M
{
187
1.94M
    int endlit = start;
188
189
1.94M
    bool inside_index = false;
190
11.9M
    while (endlit < end && ValidTokenCharacter(expr[endlit], &inside_index))
191
10.0M
    {
192
10.0M
        endlit++;
193
10.0M
    }
194
195
1.94M
    if (endlit > start)
196
961k
    {
197
961k
        StringExpression *ret = xcalloc(1, sizeof(StringExpression));
198
199
961k
        ret->op = LITERAL;
200
961k
        ret->val.literal.literal = xstrndup(expr + start, endlit - start);
201
202
961k
        return (StringParseResult) {ret, endlit};
203
961k
    }
204
984k
    else
205
984k
    {
206
984k
        return (StringParseResult) {NULL, endlit};
207
984k
    }
208
1.94M
}
209
210
/* <term> */
211
212
static StringParseResult ParseTerm(const char *expr, int start, int end)
213
1.94M
{
214
1.94M
    StringParseResult res = ParseToken(expr, start, end);
215
216
1.94M
    if (res.result)
217
961k
    {
218
961k
        return res;
219
961k
    }
220
984k
    else
221
984k
    {
222
984k
        return ParseVarRef(expr, start, end);
223
984k
    }
224
1.94M
}
225
226
/* <name> */
227
228
StringParseResult ParseStringExpression(const char *expr, int start, int end)
229
1.94M
{
230
1.94M
    StringParseResult lhs = ParseTerm(expr, start, end);
231
232
1.94M
    if (lhs.result)
233
980k
    {
234
980k
        StringParseResult rhs = ParseStringExpression(expr, lhs.position, end);
235
236
980k
        if (rhs.result)
237
32.7k
        {
238
32.7k
            StringExpression *ret = xcalloc(1, sizeof(StringExpression));
239
240
32.7k
            ret->op = CONCAT;
241
32.7k
            ret->val.concat.lhs = lhs.result;
242
32.7k
            ret->val.concat.rhs = rhs.result;
243
244
32.7k
            return (StringParseResult) {ret, rhs.position};
245
32.7k
        }
246
947k
        else
247
947k
        {
248
947k
            return lhs;
249
947k
        }
250
980k
    }
251
964k
    else
252
964k
    {
253
964k
        return lhs;
254
964k
    }
255
1.94M
}
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.37M
{
316
1.37M
    if (!expr)
317
163
    {
318
163
        return;
319
163
    }
320
321
1.37M
    switch (expr->op)
322
1.37M
    {
323
276k
    case CONCAT:
324
276k
        FreeStringExpression(expr->val.concat.lhs);
325
276k
        FreeStringExpression(expr->val.concat.rhs);
326
276k
        break;
327
1.08M
    case LITERAL:
328
1.08M
        free(expr->val.literal.literal);
329
1.08M
        break;
330
19.3k
    case VARREF:
331
19.3k
        FreeStringExpression(expr->val.varref.name);
332
19.3k
        break;
333
0
    default:
334
0
        ProgrammingError("Unknown type of string expression encountered: %d", expr->op);
335
1.37M
    }
336
337
1.37M
    free(expr);
338
1.37M
}