Coverage Report

Created: 2026-03-12 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/shared/compare-operator.c
Line
Count
Source
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3
#include <fnmatch.h>
4
5
#include "compare-operator.h"
6
#include "string-util.h"
7
8
12.2k
CompareOperator parse_compare_operator(const char **s, CompareOperatorParseFlags flags) {
9
10
12.2k
        static const struct {
11
12.2k
                CompareOperator op;
12
12.2k
                const char *str;
13
12.2k
                CompareOperatorParseFlags valid_mask; /* If this operator appears when flags in mask not set, fail */
14
12.2k
                CompareOperatorParseFlags need_mask;  /* Skip over this operator when flags in mask not set */
15
12.2k
        } table[] = {
16
12.2k
                { COMPARE_FNMATCH_EQUAL,    "$=",  .valid_mask = COMPARE_ALLOW_FNMATCH   },
17
12.2k
                { COMPARE_FNMATCH_UNEQUAL,  "!$=", .valid_mask = COMPARE_ALLOW_FNMATCH   },
18
19
12.2k
                { COMPARE_UNEQUAL,          "<>"                                         },
20
12.2k
                { COMPARE_LOWER_OR_EQUAL,   "<="                                         },
21
12.2k
                { COMPARE_GREATER_OR_EQUAL, ">="                                         },
22
12.2k
                { COMPARE_LOWER,            "<"                                          },
23
12.2k
                { COMPARE_GREATER,          ">"                                          },
24
12.2k
                { COMPARE_EQUAL,            "=="                                         },
25
12.2k
                { COMPARE_STRING_EQUAL,     "=",   .need_mask = COMPARE_EQUAL_BY_STRING  },
26
12.2k
                { COMPARE_EQUAL,            "="                                          },
27
12.2k
                { COMPARE_STRING_UNEQUAL,   "!=",  .need_mask = COMPARE_EQUAL_BY_STRING  },
28
12.2k
                { COMPARE_UNEQUAL,          "!="                                         },
29
30
12.2k
                { COMPARE_LOWER,            "lt",  .valid_mask = COMPARE_ALLOW_TEXTUAL   },
31
12.2k
                { COMPARE_LOWER_OR_EQUAL,   "le",  .valid_mask = COMPARE_ALLOW_TEXTUAL   },
32
12.2k
                { COMPARE_EQUAL,            "eq",  .valid_mask = COMPARE_ALLOW_TEXTUAL   },
33
12.2k
                { COMPARE_UNEQUAL,          "ne",  .valid_mask = COMPARE_ALLOW_TEXTUAL   },
34
12.2k
                { COMPARE_GREATER_OR_EQUAL, "ge",  .valid_mask = COMPARE_ALLOW_TEXTUAL   },
35
12.2k
                { COMPARE_GREATER,          "gt",  .valid_mask = COMPARE_ALLOW_TEXTUAL   },
36
12.2k
        };
37
38
12.2k
        assert(s);
39
40
12.2k
        if (!*s) /* Hmm, we already reached the end, for example because extract_first_word() and
41
                  * parse_compare_operator() are use on the same string? */
42
0
                return _COMPARE_OPERATOR_INVALID;
43
44
94.1k
        FOREACH_ELEMENT(i, table) {
45
94.1k
                const char *e;
46
47
94.1k
                if (i->need_mask != 0 && !FLAGS_SET(flags, i->need_mask))
48
0
                        continue;
49
50
94.1k
                e = startswith(*s, i->str);
51
94.1k
                if (e) {
52
10.6k
                        if (i->valid_mask != 0 && !FLAGS_SET(flags, i->valid_mask))
53
3
                                return _COMPARE_OPERATOR_INVALID;
54
55
10.6k
                        *s = e;
56
10.6k
                        return i->op;
57
10.6k
                }
58
94.1k
        }
59
60
1.58k
        return _COMPARE_OPERATOR_INVALID;
61
12.2k
}
62
63
8.80k
int test_order(int k, CompareOperator op) {
64
65
8.80k
        switch (op) {
66
67
2.42k
        case COMPARE_LOWER:
68
2.42k
                return k < 0;
69
70
1.07k
        case COMPARE_LOWER_OR_EQUAL:
71
1.07k
                return k <= 0;
72
73
26
        case COMPARE_EQUAL:
74
26
                return k == 0;
75
76
559
        case COMPARE_UNEQUAL:
77
559
                return k != 0;
78
79
664
        case COMPARE_GREATER_OR_EQUAL:
80
664
                return k >= 0;
81
82
4.06k
        case COMPARE_GREATER:
83
4.06k
                return k > 0;
84
85
0
        default:
86
0
                return -EINVAL;
87
8.80k
        }
88
8.80k
}
89
90
int version_or_fnmatch_compare(
91
                CompareOperator op,
92
                const char *a,
93
12.0k
                const char *b) {
94
12.0k
        int r;
95
96
12.0k
        switch (op) {
97
98
159
        case COMPARE_STRING_EQUAL:
99
159
                return streq_ptr(a, b);
100
101
884
        case COMPARE_STRING_UNEQUAL:
102
884
                return !streq_ptr(a, b);
103
104
1.72k
        case COMPARE_FNMATCH_EQUAL:
105
1.72k
                r = fnmatch(b, a, 0);
106
1.72k
                return r == 0 ? true :
107
1.72k
                        r == FNM_NOMATCH ? false : -EINVAL;
108
109
462
        case COMPARE_FNMATCH_UNEQUAL:
110
462
                r = fnmatch(b, a, 0);
111
462
                return r == FNM_NOMATCH ? true:
112
462
                        r == 0 ? false : -EINVAL;
113
114
8.80k
        case _COMPARE_OPERATOR_ORDER_FIRST..._COMPARE_OPERATOR_ORDER_LAST:
115
8.80k
                return test_order(strverscmp_improved(a, b), op);
116
117
0
        default:
118
                return -EINVAL;
119
12.0k
        }
120
12.0k
}